From 530493fed4066b1efcf3ec22253b110495767eca Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 3 Dec 2025 02:46:02 +0000 Subject: [PATCH 001/141] 8364146: JList getScrollableUnitIncrement return 0 Reviewed-by: prr, tr --- .../share/classes/javax/swing/JList.java | 13 ++- test/jdk/javax/swing/JList/JListTest.java | 86 +++++++++++++++++++ 2 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 test/jdk/javax/swing/JList/JListTest.java diff --git a/src/java.desktop/share/classes/javax/swing/JList.java b/src/java.desktop/share/classes/javax/swing/JList.java index 301813533d7..8d4497d6f9a 100644 --- a/src/java.desktop/share/classes/javax/swing/JList.java +++ b/src/java.desktop/share/classes/javax/swing/JList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, 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 @@ -2497,6 +2497,9 @@ public class JList extends JComponent implements Scrollable, Accessible /** * Returns the distance to scroll to expose the next or previous * row (for vertical scrolling) or column (for horizontal scrolling). + * The scrolling distance returned will be positive, + * unless scrolling for the specified parameters is already + * at its furthest extent, in which case it will return zero. *

* For horizontal scrolling, if the layout orientation is {@code VERTICAL}, * then the list's font size is returned (or {@code 1} if the font is @@ -2507,8 +2510,9 @@ public class JList extends JComponent implements Scrollable, Accessible * {@code SwingConstants.VERTICAL} * @param direction less or equal to zero to scroll up/back, * greater than zero for down/forward - * @return the "unit" increment for scrolling in the specified direction; - * always positive + * @return the non-negative "unit" increment + * for scrolling in the specified direction + * * @see #getScrollableBlockIncrement * @see Scrollable#getScrollableUnitIncrement * @throws IllegalArgumentException if {@code visibleRect} is {@code null}, or @@ -2529,7 +2533,8 @@ public class JList extends JComponent implements Scrollable, Accessible /* Scroll Down */ if (direction > 0) { Rectangle r = getCellBounds(row, row); - return (r == null) ? 0 : r.height - (visibleRect.y - r.y); + return (r == null) ? 0 : + ((r.height - (visibleRect.y - r.y)) < 0) ? 0 : r.height - (visibleRect.y - r.y); } /* Scroll Up */ else { diff --git a/test/jdk/javax/swing/JList/JListTest.java b/test/jdk/javax/swing/JList/JListTest.java new file mode 100644 index 00000000000..fbc9bda69e3 --- /dev/null +++ b/test/jdk/javax/swing/JList/JListTest.java @@ -0,0 +1,86 @@ +/* + * 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 8364146 + * @key headful + * @summary Verifies JList getScrollableUnitIncrement return non-negative number + * @run main JListTest + */ + +import java.awt.Dimension; +import java.awt.Rectangle; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +public class JListTest { + + private static JFrame f; + + public static void main(String[] argv) throws Exception { + + SwingUtilities.invokeAndWait(() -> { + try { + f = new JFrame(); + String[] data = {"One", "Two", "Three", "Four", "Five", "Six ", + "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelv"}; + JList list = new JList<>(data); + list.setLayoutOrientation(JList.HORIZONTAL_WRAP); + + JScrollPane sp = new JScrollPane(list); + sp.setPreferredSize(new Dimension(200, 200)); + f.add(sp); + f.pack(); + f.setVisible(true); + + Rectangle cell = list.getCellBounds(1, data.length); + System.out.println(cell); + cell.y = list.getHeight() + 10; + int unit = list.getScrollableUnitIncrement( + cell, + SwingConstants.VERTICAL, + -1); + System.out.println("Scrollable unit increment: " + unit); + + if (unit < 0) { + throw new RuntimeException("JList scrollable unit increment should be greater than 0."); + } + unit = list.getScrollableUnitIncrement( + cell, + SwingConstants.VERTICAL, + 1); + System.out.println("Scrollable unit increment: " + unit); + if (unit < 0) { + throw new RuntimeException("JList scrollable unit increment should be greater than 0."); + } + } finally { + if (f != null) { + f.dispose(); + } + } + }); + } +} From 8f3d0ade11ddb45bb1719b6818e1b51df237a59b Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 3 Dec 2025 08:06:15 +0000 Subject: [PATCH 002/141] 8371893: [macOS] use dead_strip linker option to reduce binary size Reviewed-by: erikj, lucy, serb --- make/autoconf/flags-ldflags.m4 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 572790b567b..18ec04d92b7 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -108,6 +108,9 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # Setup OS-dependent LDFLAGS if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$TOOLCHAIN_TYPE" = xclang; then + if test x$DEBUG_LEVEL = xrelease; then + BASIC_LDFLAGS_JDK_ONLY="$BASIC_LDFLAGS_JDK_ONLY -Wl,-dead_strip" + fi # FIXME: We should really generalize SetSharedLibraryOrigin instead. OS_LDFLAGS_JVM_ONLY="-Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." OS_LDFLAGS="-mmacosx-version-min=$MACOSX_VERSION_MIN -Wl,-reproducible" From 2139c8c6e6e5c5f2c64ed3ad9ad8bd148a86efae Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 3 Dec 2025 08:08:14 +0000 Subject: [PATCH 003/141] 8372571: ResourceHashTable for some AOT data structures miss placement operator when allocating Reviewed-by: aboldtch, jsjolen, kvn --- src/hotspot/share/cds/aotMappedHeapWriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/cds/aotMappedHeapWriter.cpp b/src/hotspot/share/cds/aotMappedHeapWriter.cpp index 98f400c989c..edd0aede246 100644 --- a/src/hotspot/share/cds/aotMappedHeapWriter.cpp +++ b/src/hotspot/share/cds/aotMappedHeapWriter.cpp @@ -86,9 +86,9 @@ void AOTMappedHeapWriter::init() { if (CDSConfig::is_dumping_heap()) { Universe::heap()->collect(GCCause::_java_lang_system_gc); - _buffer_offset_to_source_obj_table = new BufferOffsetToSourceObjectTable(/*size (prime)*/36137, /*max size*/1 * M); + _buffer_offset_to_source_obj_table = new (mtClassShared) BufferOffsetToSourceObjectTable(/*size (prime)*/36137, /*max size*/1 * M); _dumped_interned_strings = new (mtClass)DumpedInternedStrings(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE); - _fillers = new FillersTable(); + _fillers = new (mtClassShared) FillersTable(); _requested_bottom = nullptr; _requested_top = nullptr; From a1e8694109ad87690e18fc03d17b6b9519092d81 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Wed, 3 Dec 2025 09:01:40 +0000 Subject: [PATCH 004/141] 8371306: JDK-8367002 behavior might not match existing HotSpot behavior. Reviewed-by: thartmann, dholmes --- src/hotspot/share/runtime/sharedRuntime.cpp | 8 ++++++-- .../jtreg/compiler/exceptions/IllegalAccessInCatch.jasm | 1 + .../jtreg/compiler/exceptions/TestAccessErrorInCatch.java | 7 ++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index e277e1fb569..3a7c60cf83e 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -809,6 +809,8 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, // determine handler bci, if any EXCEPTION_MARK; + Handle orig_exception(THREAD, exception()); + int handler_bci = -1; int scope_depth = 0; if (!force_unwind) { @@ -830,7 +832,7 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, // thrown (bugs 4307310 and 4546590). Set "exception" reference // argument to ensure that the correct exception is thrown (4870175). recursive_exception_occurred = true; - exception = Handle(THREAD, PENDING_EXCEPTION); + exception.replace(PENDING_EXCEPTION); CLEAR_PENDING_EXCEPTION; if (handler_bci >= 0) { bci = handler_bci; @@ -859,8 +861,10 @@ address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, // If the compiler did not anticipate a recursive exception, resulting in an exception // thrown from the catch bci, then the compiled exception handler might be missing. - // This is rare. Just deoptimize and let the interpreter handle it. + // This is rare. Just deoptimize and let the interpreter rethrow the original + // exception at the original bci. if (t == nullptr && recursive_exception_occurred) { + exception.replace(orig_exception()); // restore original exception bool make_not_entrant = false; return Deoptimization::deoptimize_for_missing_exception_handler(nm, make_not_entrant); } diff --git a/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm b/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm index beeffa69a97..78be0bbb177 100644 --- a/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm +++ b/test/hotspot/jtreg/compiler/exceptions/IllegalAccessInCatch.jasm @@ -46,6 +46,7 @@ super class IllegalAccessInCatch idiv; endtry t0; ireturn; + catch t0 java/lang/IllegalAccessError; catch t0 jdk/internal/agent/AgentConfigurationError; // loadable but not accessible from unnamed module stack_frame_type full; stack_map class java/lang/Throwable; diff --git a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java index 44cfd60cf38..fa81fa93f11 100644 --- a/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java +++ b/test/hotspot/jtreg/compiler/exceptions/TestAccessErrorInCatch.java @@ -64,6 +64,11 @@ public class TestAccessErrorInCatch { } private static int invoke(MethodHandle mh) throws Throwable { - return (int) mh.invokeExact(); + int expected = 1; + int ret = (int) mh.invokeExact(); + if (ret != expected) { + throw new RuntimeException("Returned " + ret + " but expected " + expected); + } + return ret; } } From b3e063c2c34ac12ae2a566617560ecc52253262d Mon Sep 17 00:00:00 2001 From: root Date: Wed, 3 Dec 2025 09:04:11 +0000 Subject: [PATCH 005/141] 8372710: Update ProcessBuilder/Basic regex Reviewed-by: shade, amitkumar --- test/jdk/java/lang/ProcessBuilder/Basic.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/Basic.java b/test/jdk/java/lang/ProcessBuilder/Basic.java index 4377752650d..7034174f85c 100644 --- a/test/jdk/java/lang/ProcessBuilder/Basic.java +++ b/test/jdk/java/lang/ProcessBuilder/Basic.java @@ -85,8 +85,8 @@ public class Basic { static final String libpath = System.getenv("LIBPATH"); /* Used for regex String matching for long error messages */ - static final String PERMISSION_DENIED_ERROR_MSG = "(Permission denied|error=13)"; - static final String NO_SUCH_FILE_ERROR_MSG = "(No such file|error=2)"; + static final String PERMISSION_DENIED_ERROR_MSG = "(Permission denied|error:13)"; + static final String NO_SUCH_FILE_ERROR_MSG = "(No such file|error:2)"; static final String SPAWNHELPER_FAILURE_MSG = "(Possible reasons:)"; /** From e65fd45dc7c9383a77fbd5171b541c2a003d30d2 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 3 Dec 2025 09:17:08 +0000 Subject: [PATCH 006/141] 8366101: Replace the use of ThreadTracker with ScopedValue in java.util.jar.JarFile Reviewed-by: vyazici, alanb --- .../share/classes/java/util/jar/JarFile.java | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index dc2d65bcc99..d1a8f1310a9 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -27,7 +27,6 @@ package java.util.jar; import jdk.internal.access.SharedSecrets; import jdk.internal.access.JavaUtilZipFileAccess; -import jdk.internal.misc.ThreadTracker; import sun.security.util.ManifestEntryVerifier; import sun.security.util.SignatureFileVerifier; @@ -213,6 +212,9 @@ public class JarFile extends ZipFile { */ static final String INDEX_NAME = "META-INF/INDEX.LIST"; + // this will be set when the thread is initializing a JAR verifier + private static final ScopedValue IN_VERIFIER_INIT = ScopedValue.newInstance(); + /** * Returns the version that represents the unversioned configuration of a * multi-release jar file. @@ -1025,36 +1027,30 @@ public class JarFile extends ZipFile { } } - private static class ThreadTrackHolder { - static final ThreadTracker TRACKER = new ThreadTracker(); - } - - private static Object beginInit() { - return ThreadTrackHolder.TRACKER.begin(); - } - - private static void endInit(Object key) { - ThreadTrackHolder.TRACKER.end(key); - } - synchronized void ensureInitialization() { try { maybeInstantiateVerifier(); } catch (IOException e) { throw new RuntimeException(e); } - if (jv != null && !jvInitialized) { - Object key = beginInit(); - try { + if (jv == null || jvInitialized) { + return; + } + // mark the current thread as initializing + // the JAR verifier + ScopedValue.where(IN_VERIFIER_INIT, true).run(new Runnable() { + @Override + public void run() { initializeVerifier(); jvInitialized = true; - } finally { - endInit(key); } - } + }); } + /** + * {@return true if the current thread is initializing a JAR verifier, false otherwise} + */ static boolean isInitializing() { - return ThreadTrackHolder.TRACKER.contains(Thread.currentThread()); + return IN_VERIFIER_INIT.isBound(); } } From a25e6f6462a5d77a2cb0dcec4f74e5e25d8565c4 Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Wed, 3 Dec 2025 09:22:13 +0000 Subject: [PATCH 007/141] 8319158: Parallel: Make TestObjectTenuringFlags use createTestJavaProcessBuilder Reviewed-by: stefank, aboldtch --- .../jtreg/gc/arguments/TestObjectTenuringFlags.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java b/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java index 1590d7ac967..ed087480815 100644 --- a/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestObjectTenuringFlags.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 @@ -26,7 +26,8 @@ package gc.arguments; /* * @test TestObjectTenuringFlags * @bug 6521376 - * @requires vm.gc.Parallel + * @requires vm.gc.Parallel & vm.opt.NeverTenure == null & vm.opt.AlwaysTenure == null + * & vm.opt.MaxTenuringThreshold == null & vm.opt.InitialTenuringThreshold == null * @summary Tests argument processing for NeverTenure, AlwaysTenure, * and MaxTenuringThreshold * @library /test/lib @@ -161,7 +162,7 @@ public class TestObjectTenuringFlags { } Collections.addAll(vmOpts, "-XX:+UseParallelGC", "-XX:+PrintFlagsFinal", "-version"); - OutputAnalyzer output = GCArguments.executeLimitedTestJava(vmOpts); + OutputAnalyzer output = GCArguments.executeTestJava(vmOpts); if (shouldFail) { output.shouldHaveExitValue(1); From 177f3404dfb146be724d952f8c88b4d070e36b52 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 3 Dec 2025 09:24:33 +0000 Subject: [PATCH 008/141] 8372733: GHA: Bump to Ubuntu 24.04 Reviewed-by: erikj, ayang --- .github/workflows/build-alpine-linux.yml | 2 +- .github/workflows/build-cross-compile.yml | 2 +- .github/workflows/build-linux.yml | 20 ++++++++++++++++---- .github/workflows/main.yml | 6 +++--- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-alpine-linux.yml b/.github/workflows/build-alpine-linux.yml index 0d366a4bdd0..a39b342a248 100644 --- a/.github/workflows/build-alpine-linux.yml +++ b/.github/workflows/build-alpine-linux.yml @@ -59,7 +59,7 @@ on: jobs: build-linux: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 container: image: alpine:3.20 diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index b3c63f488a0..e70937f57b6 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -48,7 +48,7 @@ on: jobs: build-cross-compile: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index f398625cb2c..0680dea6bbe 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -75,7 +75,7 @@ on: jobs: build-linux: name: build - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -115,9 +115,21 @@ jobs: if [[ '${{ inputs.apt-architecture }}' != '' ]]; then sudo dpkg --add-architecture ${{ inputs.apt-architecture }} fi - sudo apt-get update - sudo apt-get install --only-upgrade apt - sudo apt-get install gcc-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} g++-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} libxrandr-dev${{ steps.arch.outputs.suffix }} libxtst-dev${{ steps.arch.outputs.suffix }} libcups2-dev${{ steps.arch.outputs.suffix }} libasound2-dev${{ steps.arch.outputs.suffix }} ${{ inputs.apt-extra-packages }} + sudo apt update + sudo apt install --only-upgrade apt + sudo apt install \ + gcc-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} \ + g++-${{ inputs.gcc-major-version }}${{ inputs.gcc-package-suffix }} \ + libasound2-dev${{ steps.arch.outputs.suffix }} \ + libcups2-dev${{ steps.arch.outputs.suffix }} \ + libfontconfig1-dev${{ steps.arch.outputs.suffix }} \ + libx11-dev${{ steps.arch.outputs.suffix }} \ + libxext-dev${{ steps.arch.outputs.suffix }} \ + libxrandr-dev${{ steps.arch.outputs.suffix }} \ + libxrender-dev${{ steps.arch.outputs.suffix }} \ + libxt-dev${{ steps.arch.outputs.suffix }} \ + libxtst-dev${{ steps.arch.outputs.suffix }} \ + ${{ inputs.apt-extra-packages }} sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${{ inputs.gcc-major-version }} 100 --slave /usr/bin/g++ g++ /usr/bin/g++-${{ inputs.gcc-major-version }} - name: 'Configure' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4d1e8a8be3d..09e6ed65a47 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,7 +57,7 @@ jobs: prepare: name: 'Prepare the run' - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 env: # List of platforms to exclude by default EXCLUDED_PLATFORMS: 'alpine-linux-x64' @@ -405,7 +405,7 @@ jobs: with: platform: linux-x64 bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} debug-suffix: -debug @@ -419,7 +419,7 @@ jobs: with: platform: linux-x64 bootjdk-platform: linux-x64 - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 dry-run: ${{ needs.prepare.outputs.dry-run == 'true' }} static-suffix: "-static" From 3e04e11482605e7734ef75bc477fe31107988f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96sterlund?= Date: Wed, 3 Dec 2025 09:28:30 +0000 Subject: [PATCH 009/141] 8372738: ZGC: C2 allocation reloc promotion deopt race Reviewed-by: aboldtch, stefank --- src/hotspot/share/gc/z/zBarrierSet.cpp | 7 ++-- src/hotspot/share/gc/z/zGeneration.cpp | 3 +- src/hotspot/share/gc/z/zPage.cpp | 11 ++++- src/hotspot/share/gc/z/zPage.hpp | 4 ++ src/hotspot/share/gc/z/zRelocate.cpp | 39 +++++++++++------- src/hotspot/share/gc/z/zRelocate.hpp | 3 +- src/hotspot/share/gc/z/zRelocationSet.cpp | 49 +++++++++++++++++------ src/hotspot/share/gc/z/zRelocationSet.hpp | 4 ++ 8 files changed, 85 insertions(+), 35 deletions(-) diff --git a/src/hotspot/share/gc/z/zBarrierSet.cpp b/src/hotspot/share/gc/z/zBarrierSet.cpp index 643eba1947e..15b694b2ecc 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.cpp +++ b/src/hotspot/share/gc/z/zBarrierSet.cpp @@ -217,11 +217,10 @@ static void deoptimize_allocation(JavaThread* thread) { void ZBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { const ZPage* const page = ZHeap::heap()->page(to_zaddress(new_obj)); - const ZPageAge age = page->age(); - if (age == ZPageAge::old) { + if (!page->allows_raw_null()) { // We promised C2 that its allocations would end up in young gen. This object - // breaks that promise. Take a few steps in the interpreter instead, which has - // no such assumptions about where an object resides. + // is too old to guarantee that. Take a few steps in the interpreter instead, + // which does not elide barriers based on the age of an object. deoptimize_allocation(thread); } } diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 2b632ef29a9..a8c646bf895 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -190,7 +190,8 @@ void ZGeneration::flip_age_pages(const ZRelocationSetSelector* selector) { ZRendezvousHandshakeClosure cl; Handshake::execute(&cl); - _relocate.barrier_flip_promoted_pages(_relocation_set.flip_promoted_pages()); + _relocate.barrier_promoted_pages(_relocation_set.flip_promoted_pages(), + _relocation_set.relocate_promoted_pages()); } static double fragmentation_limit(ZGenerationId generation) { diff --git a/src/hotspot/share/gc/z/zPage.cpp b/src/hotspot/share/gc/z/zPage.cpp index 9f4654a655f..b6e0d162ef0 100644 --- a/src/hotspot/share/gc/z/zPage.cpp +++ b/src/hotspot/share/gc/z/zPage.cpp @@ -41,7 +41,8 @@ ZPage::ZPage(ZPageType type, ZPageAge age, const ZVirtualMemory& vmem, ZMultiPar _top(to_zoffset_end(start())), _livemap(object_max_count()), _remembered_set(), - _multi_partition_tracker(multi_partition_tracker) { + _multi_partition_tracker(multi_partition_tracker), + _relocate_promoted(false) { assert(!_virtual.is_null(), "Should not be null"); assert((_type == ZPageType::small && size() == ZPageSizeSmall) || (_type == ZPageType::medium && ZPageSizeMediumMin <= size() && size() <= ZPageSizeMediumMax) || @@ -70,6 +71,14 @@ ZPage* ZPage::clone_for_promotion() const { return page; } +bool ZPage::allows_raw_null() const { + return is_young() && !AtomicAccess::load(&_relocate_promoted); +} + +void ZPage::set_is_relocate_promoted() { + AtomicAccess::store(&_relocate_promoted, true); +} + ZGeneration* ZPage::generation() { return ZGeneration::generation(_generation_id); } diff --git a/src/hotspot/share/gc/z/zPage.hpp b/src/hotspot/share/gc/z/zPage.hpp index 96900a37680..0fc134e170a 100644 --- a/src/hotspot/share/gc/z/zPage.hpp +++ b/src/hotspot/share/gc/z/zPage.hpp @@ -52,6 +52,7 @@ private: ZLiveMap _livemap; ZRememberedSet _remembered_set; ZMultiPartitionTracker* const _multi_partition_tracker; + volatile bool _relocate_promoted; const char* type_to_string() const; @@ -103,6 +104,9 @@ public: ZPageAge age() const; + bool allows_raw_null() const; + void set_is_relocate_promoted(); + uint32_t seqnum() const; bool is_allocating() const; bool is_relocatable() const; diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 24c4bdeac16..da07f67d859 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -1366,27 +1366,35 @@ public: class ZPromoteBarrierTask : public ZTask { private: - ZArrayParallelIterator _iter; + ZArrayParallelIterator _flip_promoted_iter; + ZArrayParallelIterator _relocate_promoted_iter; public: - ZPromoteBarrierTask(const ZArray* pages) + ZPromoteBarrierTask(const ZArray* flip_promoted_pages, + const ZArray* relocate_promoted_pages) : ZTask("ZPromoteBarrierTask"), - _iter(pages) {} + _flip_promoted_iter(flip_promoted_pages), + _relocate_promoted_iter(relocate_promoted_pages) {} virtual void work() { SuspendibleThreadSetJoiner sts_joiner; - for (ZPage* page; _iter.next(&page);) { - // When promoting an object (and before relocate start), we must ensure that all - // contained zpointers are store good. The marking code ensures that for non-null - // pointers, but null pointers are ignored. This code ensures that even null pointers - // are made store good, for the promoted objects. - page->object_iterate([&](oop obj) { - ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field); - }); + auto promote_barriers = [&](ZArrayParallelIterator* iter) { + for (ZPage* page; iter->next(&page);) { + // When promoting an object (and before relocate start), we must ensure that all + // contained zpointers are store good. The marking code ensures that for non-null + // pointers, but null pointers are ignored. This code ensures that even null pointers + // are made store good, for the promoted objects. + page->object_iterate([&](oop obj) { + ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field); + }); - SuspendibleThreadSet::yield(); - } + SuspendibleThreadSet::yield(); + } + }; + + promote_barriers(&_flip_promoted_iter); + promote_barriers(&_relocate_promoted_iter); } }; @@ -1395,8 +1403,9 @@ void ZRelocate::flip_age_pages(const ZArray* pages) { workers()->run(&flip_age_task); } -void ZRelocate::barrier_flip_promoted_pages(const ZArray* pages) { - ZPromoteBarrierTask promote_barrier_task(pages); +void ZRelocate::barrier_promoted_pages(const ZArray* flip_promoted_pages, + const ZArray* relocate_promoted_pages) { + ZPromoteBarrierTask promote_barrier_task(flip_promoted_pages, relocate_promoted_pages); workers()->run(&promote_barrier_task); } diff --git a/src/hotspot/share/gc/z/zRelocate.hpp b/src/hotspot/share/gc/z/zRelocate.hpp index 50111f24ee5..038efba83eb 100644 --- a/src/hotspot/share/gc/z/zRelocate.hpp +++ b/src/hotspot/share/gc/z/zRelocate.hpp @@ -119,7 +119,8 @@ public: void relocate(ZRelocationSet* relocation_set); void flip_age_pages(const ZArray* pages); - void barrier_flip_promoted_pages(const ZArray* pages); + void barrier_promoted_pages(const ZArray* flip_promoted_pages, + const ZArray* relocate_promoted_pages); void synchronize(); void desynchronize(); diff --git a/src/hotspot/share/gc/z/zRelocationSet.cpp b/src/hotspot/share/gc/z/zRelocationSet.cpp index fb865934690..95ca6e56c45 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.cpp +++ b/src/hotspot/share/gc/z/zRelocationSet.cpp @@ -38,6 +38,7 @@ class ZRelocationSetInstallTask : public ZTask { private: + ZRelocationSet* _relocation_set; ZForwardingAllocator* const _allocator; ZForwarding** _forwardings; const size_t _nforwardings; @@ -54,16 +55,6 @@ private: page->log_msg(" (relocation selected)"); _forwardings[index] = forwarding; - - if (forwarding->is_promotion()) { - // Before promoting an object (and before relocate start), we must ensure that all - // contained zpointers are store good. The marking code ensures that for non-null - // pointers, but null pointers are ignored. This code ensures that even null pointers - // are made store good, for the promoted objects. - page->object_iterate([&](oop obj) { - ZIterator::basic_oop_iterate_safe(obj, ZBarrier::promote_barrier_on_young_oop_field); - }); - } } void install_small(ZForwarding* forwarding, size_t index) { @@ -78,10 +69,18 @@ private: return ZRelocate::compute_to_age(page->age()); } + void track_if_promoted(ZPage* page, ZForwarding* forwarding, ZArray& relocate_promoted) { + if (forwarding->is_promotion()) { + page->set_is_relocate_promoted(); + relocate_promoted.append(page); + } + } + public: - ZRelocationSetInstallTask(ZForwardingAllocator* allocator, const ZRelocationSetSelector* selector) + ZRelocationSetInstallTask(ZRelocationSet* relocation_set, const ZRelocationSetSelector* selector) : ZTask("ZRelocationSetInstallTask"), - _allocator(allocator), + _relocation_set(relocation_set), + _allocator(&relocation_set->_allocator), _forwardings(nullptr), _nforwardings((size_t)selector->selected_small()->length() + (size_t)selector->selected_medium()->length()), _small(selector->selected_small()), @@ -108,11 +107,14 @@ public: // Join the STS to block out VMThreads while running promote_barrier_on_young_oop_field SuspendibleThreadSetJoiner sts_joiner; + ZArray relocate_promoted; + // Allocate and install forwardings for small pages for (size_t page_index; _small_iter.next_index(&page_index);) { ZPage* page = _small->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_small(forwarding, (size_t)_medium->length() + page_index); + track_if_promoted(page, forwarding, relocate_promoted); SuspendibleThreadSet::yield(); } @@ -122,9 +124,12 @@ public: ZPage* page = _medium->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_medium(forwarding, page_index); + track_if_promoted(page, forwarding, relocate_promoted); SuspendibleThreadSet::yield(); } + + _relocation_set->register_relocate_promoted(relocate_promoted); } ZForwarding** forwardings() const { @@ -143,6 +148,7 @@ ZRelocationSet::ZRelocationSet(ZGeneration* generation) _nforwardings(0), _promotion_lock(), _flip_promoted_pages(), + _relocate_promoted_pages(), _in_place_relocate_promoted_pages() {} ZWorkers* ZRelocationSet::workers() const { @@ -157,9 +163,13 @@ ZArray* ZRelocationSet::flip_promoted_pages() { return &_flip_promoted_pages; } +ZArray* ZRelocationSet::relocate_promoted_pages() { + return &_relocate_promoted_pages; +} + void ZRelocationSet::install(const ZRelocationSetSelector* selector) { // Install relocation set - ZRelocationSetInstallTask task(&_allocator, selector); + ZRelocationSetInstallTask task(this, selector); workers()->run(&task); _forwardings = task.forwardings(); @@ -189,6 +199,7 @@ void ZRelocationSet::reset(ZPageAllocator* page_allocator) { destroy_and_clear(page_allocator, &_in_place_relocate_promoted_pages); destroy_and_clear(page_allocator, &_flip_promoted_pages); + _relocate_promoted_pages.clear(); } void ZRelocationSet::register_flip_promoted(const ZArray& pages) { @@ -199,6 +210,18 @@ void ZRelocationSet::register_flip_promoted(const ZArray& pages) { } } +void ZRelocationSet::register_relocate_promoted(const ZArray& pages) { + if (pages.is_empty()) { + return; + } + + ZLocker locker(&_promotion_lock); + for (ZPage* const page : pages) { + assert(!_relocate_promoted_pages.contains(page), "no duplicates allowed"); + _relocate_promoted_pages.append(page); + } +} + void ZRelocationSet::register_in_place_relocate_promoted(ZPage* page) { ZLocker locker(&_promotion_lock); assert(!_in_place_relocate_promoted_pages.contains(page), "no duplicates allowed"); diff --git a/src/hotspot/share/gc/z/zRelocationSet.hpp b/src/hotspot/share/gc/z/zRelocationSet.hpp index ee1a9447617..5f54df79805 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.hpp +++ b/src/hotspot/share/gc/z/zRelocationSet.hpp @@ -37,6 +37,7 @@ class ZWorkers; class ZRelocationSet { template friend class ZRelocationSetIteratorImpl; + friend class ZRelocationSetInstallTask; private: ZGeneration* _generation; @@ -45,6 +46,7 @@ private: size_t _nforwardings; ZLock _promotion_lock; ZArray _flip_promoted_pages; + ZArray _relocate_promoted_pages; ZArray _in_place_relocate_promoted_pages; ZWorkers* workers() const; @@ -58,8 +60,10 @@ public: void reset(ZPageAllocator* page_allocator); ZGeneration* generation() const; ZArray* flip_promoted_pages(); + ZArray* relocate_promoted_pages(); void register_flip_promoted(const ZArray& pages); + void register_relocate_promoted(const ZArray& pages); void register_in_place_relocate_promoted(ZPage* page); }; From 858d2e434dd4eb8aa94784bb1cd115554eec5dff Mon Sep 17 00:00:00 2001 From: Jonas Norlinder Date: Wed, 3 Dec 2025 09:35:59 +0000 Subject: [PATCH 010/141] 8372584: [Linux]: Replace reading proc to get thread user CPU time with clock_gettime Reviewed-by: dholmes, kevinw, redestad --- src/hotspot/os/linux/os_linux.cpp | 91 ++++++++----------- src/hotspot/os/linux/os_linux.hpp | 2 +- .../bench/vm/runtime/ThreadMXBeanBench.java | 55 +++++++++++ 3 files changed, 95 insertions(+), 53 deletions(-) create mode 100644 test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index cf64c22ddff..880dbeccf7d 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4305,7 +4305,7 @@ OSReturn os::get_native_priority(const Thread* const thread, // For reference, please, see IEEE Std 1003.1-2004: // http://www.unix.org/single_unix_specification -jlong os::Linux::total_thread_cpu_time(clockid_t clockid) { +jlong os::Linux::thread_cpu_time(clockid_t clockid) { struct timespec tp; int status = clock_gettime(clockid, &tp); assert(status == 0, "clock_gettime error: %s", os::strerror(errno)); @@ -4960,20 +4960,42 @@ int os::open(const char *path, int oflag, int mode) { return fd; } +// Since kernel v2.6.12 the Linux ABI has had support for encoding the clock +// types in the last three bits. Bit 2 indicates whether a cpu clock refers to a +// thread or a process. Bits 1 and 0 give the type: PROF=0, VIRT=1, SCHED=2, or +// FD=3. The clock CPUCLOCK_VIRT (0b001) reports the thread's consumed user +// time. POSIX compliant implementations of pthread_getcpuclockid return the +// clock CPUCLOCK_SCHED (0b010) which reports the thread's consumed system+user +// time (as mandated by the POSIX standard POSIX.1-2024/IEEE Std 1003.1-2024 +// §3.90). +static bool get_thread_clockid(Thread* thread, clockid_t* clockid, bool total) { + constexpr clockid_t CLOCK_TYPE_MASK = 3; + constexpr clockid_t CPUCLOCK_VIRT = 1; + + int rc = pthread_getcpuclockid(thread->osthread()->pthread_id(), clockid); + if (rc != 0) { + // It's possible to encounter a terminated native thread that failed + // to detach itself from the VM - which should result in ESRCH. + assert_status(rc == ESRCH, rc, "pthread_getcpuclockid failed"); + return false; + } + + if (!total) { + clockid_t clockid_tmp = *clockid; + clockid_tmp = (clockid_tmp & ~CLOCK_TYPE_MASK) | CPUCLOCK_VIRT; + *clockid = clockid_tmp; + } + + return true; +} + static jlong user_thread_cpu_time(Thread *thread); static jlong total_thread_cpu_time(Thread *thread) { - clockid_t clockid; - int rc = pthread_getcpuclockid(thread->osthread()->pthread_id(), - &clockid); - if (rc == 0) { - return os::Linux::total_thread_cpu_time(clockid); - } else { - // It's possible to encounter a terminated native thread that failed - // to detach itself from the VM - which should result in ESRCH. - assert_status(rc == ESRCH, rc, "pthread_getcpuclockid failed"); - return -1; - } + clockid_t clockid; + bool success = get_thread_clockid(thread, &clockid, true); + + return success ? os::Linux::thread_cpu_time(clockid) : -1; } // current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) @@ -4984,7 +5006,7 @@ static jlong total_thread_cpu_time(Thread *thread) { // the fast estimate available on the platform. jlong os::current_thread_cpu_time() { - return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); + return os::Linux::thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } jlong os::thread_cpu_time(Thread* thread) { @@ -4993,7 +5015,7 @@ jlong os::thread_cpu_time(Thread* thread) { jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { if (user_sys_cpu_time) { - return os::Linux::total_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); + return os::Linux::thread_cpu_time(CLOCK_THREAD_CPUTIME_ID); } else { return user_thread_cpu_time(Thread::current()); } @@ -5007,46 +5029,11 @@ jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { } } -// -1 on error. static jlong user_thread_cpu_time(Thread *thread) { - pid_t tid = thread->osthread()->thread_id(); - char *s; - char stat[2048]; - size_t statlen; - char proc_name[64]; - int count; - long sys_time, user_time; - char cdummy; - int idummy; - long ldummy; - FILE *fp; + clockid_t clockid; + bool success = get_thread_clockid(thread, &clockid, false); - os::snprintf_checked(proc_name, 64, "/proc/self/task/%d/stat", tid); - fp = os::fopen(proc_name, "r"); - if (fp == nullptr) return -1; - statlen = fread(stat, 1, 2047, fp); - stat[statlen] = '\0'; - fclose(fp); - - // Skip pid and the command string. Note that we could be dealing with - // weird command names, e.g. user could decide to rename java launcher - // to "java 1.4.2 :)", then the stat file would look like - // 1234 (java 1.4.2 :)) R ... ... - // We don't really need to know the command string, just find the last - // occurrence of ")" and then start parsing from there. See bug 4726580. - s = strrchr(stat, ')'); - if (s == nullptr) return -1; - - // Skip blank chars - do { s++; } while (s && isspace((unsigned char) *s)); - - count = sscanf(s,"%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu", - &cdummy, &idummy, &idummy, &idummy, &idummy, &idummy, - &ldummy, &ldummy, &ldummy, &ldummy, &ldummy, - &user_time, &sys_time); - if (count != 13) return -1; - - return (jlong)user_time * (1000000000 / os::Posix::clock_tics_per_second()); + return success ? os::Linux::thread_cpu_time(clockid) : -1; } void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index dd07cb600b9..43f70b4af56 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -142,7 +142,7 @@ class os::Linux { static bool manually_expand_stack(JavaThread * t, address addr); static void expand_stack_to(address bottom); - static jlong total_thread_cpu_time(clockid_t clockid); + static jlong thread_cpu_time(clockid_t clockid); static jlong sendfile(int out_fd, int in_fd, jlong* offset, jlong count); diff --git a/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java b/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java new file mode 100644 index 00000000000..f041eb89f5a --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/runtime/ThreadMXBeanBench.java @@ -0,0 +1,55 @@ +/* + * 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 org.openjdk.bench.vm.runtime; + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.util.concurrent.TimeUnit; + +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.Threads; +import org.openjdk.jmh.annotations.Warmup; + +@State(Scope.Benchmark) +@Warmup(iterations = 2, time = 5) +@Measurement(iterations = 5, time = 5) +@BenchmarkMode(Mode.SampleTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Threads(1) +@Fork(value = 10) +public class ThreadMXBeanBench { + static final ThreadMXBean mxThreadBean = ManagementFactory.getThreadMXBean(); + static long user; // To avoid dead-code elimination + + @Benchmark + public void getCurrentThreadUserTime() throws Throwable { + user = mxThreadBean.getCurrentThreadUserTime(); + } +} From 94977063baafc2e293193d284db408a069f12aca Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Wed, 3 Dec 2025 10:03:50 +0000 Subject: [PATCH 011/141] 8358706: Integer overflow with -XX:MinOopMapAllocation=-1 Reviewed-by: phubner, coleenp --- src/hotspot/share/runtime/globals.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index d002edd48cd..68b5d8254fd 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1671,8 +1671,9 @@ const int ObjectAlignmentInBytes = 8; "putback") \ \ /* new oopmap storage allocation */ \ - develop(intx, MinOopMapAllocation, 8, \ + develop(int, MinOopMapAllocation, 8, \ "Minimum number of OopMap entries in an OopMapSet") \ + range(0, max_jint) \ \ /* recompilation */ \ product_pd(intx, CompileThreshold, \ From f1a4d1bfde652cf758117b93bbd02ae8248e805e Mon Sep 17 00:00:00 2001 From: Casper Norrbin Date: Wed, 3 Dec 2025 10:06:01 +0000 Subject: [PATCH 012/141] 8372615: Many container tests fail when running rootless on cgroup v1 Reviewed-by: sgehwolf, dholmes --- .../containers/docker/DockerBasicTest.java | 8 +++--- .../jtreg/containers/docker/ShareTmpDir.java | 8 +++--- .../containers/docker/TestCPUAwareness.java | 7 +++--- .../jtreg/containers/docker/TestCPUSets.java | 10 +++----- .../containers/docker/TestContainerInfo.java | 8 +++--- .../containers/docker/TestJFREvents.java | 5 ++-- .../docker/TestJFRNetworkEvents.java | 8 +++--- .../containers/docker/TestJFRWithJMX.java | 7 +++--- .../jtreg/containers/docker/TestJcmd.java | 3 ++- .../docker/TestJcmdWithSideCar.java | 8 +++--- .../containers/docker/TestLimitsUpdating.java | 9 +++---- .../docker/TestMemoryAwareness.java | 5 +--- .../docker/TestMemoryInvisibleParent.java | 5 +--- .../docker/TestMemoryWithCgroupV1.java | 7 +++--- .../docker/TestMemoryWithSubgroups.java | 5 +--- .../jtreg/containers/docker/TestMisc.java | 16 +++--------- .../jtreg/containers/docker/TestPids.java | 7 +++--- .../platform/docker/TestDockerBasic.java | 9 +++---- .../platform/docker/TestDockerCpuMetrics.java | 7 +++--- .../docker/TestDockerMemoryMetrics.java | 5 ++-- .../TestDockerMemoryMetricsSubgroup.java | 5 +--- .../docker/TestGetFreeSwapSpaceSize.java | 8 +++--- .../platform/docker/TestLimitsUpdating.java | 6 ++--- .../platform/docker/TestPidsLimit.java | 7 +++--- .../platform/docker/TestSystemMetrics.java | 5 +--- .../docker/TestUseContainerSupport.java | 5 +--- .../containers/docker/DockerTestUtils.java | 25 +++++++++++++------ 27 files changed, 83 insertions(+), 125 deletions(-) diff --git a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java b/test/hotspot/jtreg/containers/docker/DockerBasicTest.java index 8e2c0b6a85a..e564cae9d8e 100644 --- a/test/hotspot/jtreg/containers/docker/DockerBasicTest.java +++ b/test/hotspot/jtreg/containers/docker/DockerBasicTest.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 @@ -29,6 +29,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build HelloDocker @@ -45,10 +46,7 @@ public class DockerBasicTest { private static final String imageNameAndTag = Common.imageName("basic"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageNameAndTag); try { diff --git a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java index 9a4748563bd..a84cdacefa1 100644 --- a/test/hotspot/jtreg/containers/docker/ShareTmpDir.java +++ b/test/hotspot/jtreg/containers/docker/ShareTmpDir.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build WaitForFlagFile * @run driver ShareTmpDir */ @@ -50,10 +51,7 @@ public class ShareTmpDir { private static final String imageName = Common.imageName("sharetmpdir"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java index 99220201f66..26f160ab27d 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUAwareness.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 @@ -48,9 +48,8 @@ public class TestCPUAwareness { private static final int availableCPUs = Runtime.getRuntime().availableProcessors(); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestCPUSets.java b/test/hotspot/jtreg/containers/docker/TestCPUSets.java index 7894172e401..001914a6686 100644 --- a/test/hotspot/jtreg/containers/docker/TestCPUSets.java +++ b/test/hotspot/jtreg/containers/docker/TestCPUSets.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 @@ -31,6 +31,7 @@ * @requires (os.arch != "s390x") * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build AttemptOOM jdk.test.whitebox.WhiteBox PrintContainerInfo @@ -52,11 +53,8 @@ public class TestCPUSets { private static final String imageName = Common.imageName("cpusets"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java b/test/hotspot/jtreg/containers/docker/TestContainerInfo.java index b9b6fb65b75..a5579aa9528 100644 --- a/test/hotspot/jtreg/containers/docker/TestContainerInfo.java +++ b/test/hotspot/jtreg/containers/docker/TestContainerInfo.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. * Copyright (c) 2024, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -31,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build CheckContainerized jdk.test.whitebox.WhiteBox PrintContainerInfo @@ -49,10 +50,7 @@ public class TestContainerInfo { private static final String imageName = Common.imageName("container-info"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestJFREvents.java b/test/hotspot/jtreg/containers/docker/TestJFREvents.java index 4c33ecfc79b..d46c422723b 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFREvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFREvents.java @@ -34,6 +34,7 @@ * @modules java.base/jdk.internal.platform * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build JfrReporter jdk.test.whitebox.WhiteBox @@ -61,9 +62,7 @@ public class TestJFREvents { public static void main(String[] args) throws Exception { System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); // If cgroups is not configured, report success. Metrics metrics = Metrics.systemMetrics(); diff --git a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java index c0dde368d1e..2c7120c577c 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.java +++ b/test/hotspot/jtreg/containers/docker/TestJFRNetworkEvents.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,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build JfrNetwork @@ -48,10 +49,7 @@ public class TestJFRNetworkEvents { public static void main(String[] args) throws Exception { System.out.println("Test Environment: detected availableCPUs = " + availableCPUs); - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java b/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java index efe1fa4ffbc..7c26af9b27a 100644 --- a/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java +++ b/test/hotspot/jtreg/containers/docker/TestJFRWithJMX.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, 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 @@ -29,6 +29,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @build EventProducer @@ -73,9 +74,7 @@ public class TestJFRWithJMX { static final AtomicReference ipAddr = new AtomicReference(); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - throw new SkippedException("Docker is not supported on this host"); - } + DockerTestUtils.checkCanTestDocker(); if (DockerTestUtils.isPodman() & !Platform.isRoot()) { throw new SkippedException("test cannot be run under rootless podman configuration"); diff --git a/test/hotspot/jtreg/containers/docker/TestJcmd.java b/test/hotspot/jtreg/containers/docker/TestJcmd.java index 8c210544bb6..3cfe2945e92 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmd.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmd.java @@ -29,6 +29,7 @@ * @requires container.support * @requires vm.flagless * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @library /test/lib @@ -62,7 +63,7 @@ public class TestJcmd { public static void main(String[] args) throws Exception { - DockerTestUtils.canTestDocker(); + DockerTestUtils.checkCanTestDocker(); // podman versions below 3.3.1 hava a bug where cross-container testing with correct // permissions fails. See JDK-8273216 diff --git a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java index 91a07012f00..28a7a20553f 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.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 @@ -33,6 +33,7 @@ * @requires vm.flagless * @requires !vm.asan * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * jdk.jartool/sun.tools.jar * @library /test/lib @@ -95,10 +96,7 @@ public class TestJcmdWithSideCar { private static final String NET_BIND_SERVICE = "--cap-add=NET_BIND_SERVICE"; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(IMAGE_NAME); try { diff --git a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java index 7b05669085c..df8ba5b6161 100644 --- a/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java +++ b/test/hotspot/jtreg/containers/docker/TestLimitsUpdating.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. - * 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. * @@ -32,6 +32,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build jdk.test.whitebox.WhiteBox LimitUpdateChecker * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox * @run driver TestLimitsUpdating @@ -54,10 +55,8 @@ public class TestLimitsUpdating { private static final String imageName = Common.imageName("limitsUpdating"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java index 10db6487fa2..4cf895156fe 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -59,10 +59,7 @@ public class TestMemoryAwareness { } public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java b/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java index 68331f26766..4854f663101 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryInvisibleParent.java @@ -55,10 +55,7 @@ public class TestMemoryInvisibleParent { System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java b/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java index 3340f9de03c..1edc98035e4 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryWithCgroupV1.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2022, Tencent. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,10 +52,8 @@ public class TestMemoryWithCgroupV1 { return; } if ("cgroupv1".equals(metrics.getProvider())) { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java b/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java index 3b901765ee9..35b7bf993f7 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java @@ -52,10 +52,7 @@ public class TestMemoryWithSubgroups { System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff --git a/test/hotspot/jtreg/containers/docker/TestMisc.java b/test/hotspot/jtreg/containers/docker/TestMisc.java index 400119dac9d..fca3cef5513 100644 --- a/test/hotspot/jtreg/containers/docker/TestMisc.java +++ b/test/hotspot/jtreg/containers/docker/TestMisc.java @@ -46,14 +46,10 @@ import jtreg.SkippedException; public class TestMisc { - private static final Metrics metrics = Metrics.systemMetrics(); private static final String imageName = Common.imageName("misc"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); @@ -102,14 +98,8 @@ public class TestMisc { // Test the mapping function on cgroups v2. Should also pass on cgroups v1 as it's // a direct mapping there. private static void testPrintContainerInfoCPUShares() throws Exception { - // Test won't work on cgv1 rootless podman since resource limits don't - // work there. - if ("cgroupv1".equals(metrics.getProvider()) && - DockerTestUtils.isPodman() && - DockerTestUtils.isRootless()) { - throw new SkippedException("Resource limits required for testPrintContainerInfoCPUShares(). " + - "This is cgv1 with podman in rootless mode. Test skipped."); - } + // Test won't work on cgv1 rootless since resource limits don't work there. + DockerTestUtils.checkCanUseResourceLimits(); // Anything less than 1024 should return the back-mapped cpu-shares value without // rounding to next multiple of 1024 (on cg v2). Only ensure that we get // 'cpu_shares: ' over 'cpu_shares: no shares'. diff --git a/test/hotspot/jtreg/containers/docker/TestPids.java b/test/hotspot/jtreg/containers/docker/TestPids.java index 7d5f1b0cdf9..0e39268184e 100644 --- a/test/hotspot/jtreg/containers/docker/TestPids.java +++ b/test/hotspot/jtreg/containers/docker/TestPids.java @@ -31,6 +31,7 @@ * @requires !vm.asan * @library /test/lib * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.platform * java.management * @build jdk.test.whitebox.WhiteBox PrintContainerInfo * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox @@ -54,10 +55,8 @@ public class TestPids { static final String warning_kernel_no_pids_support = "WARNING: Your kernel does not support pids limit capabilities"; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java b/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java index 9a531d692ed..bfc628a25fc 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerBasic.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022, Red Hat, Inc. - * 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 @@ -30,6 +30,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @run main/timeout=360 TestDockerBasic */ @@ -42,10 +43,8 @@ public class TestDockerBasic { private static final String imageName = Common.imageName("javaDockerBasic"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java index ff039913b8f..042996a353b 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerCpuMetrics.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 @@ -46,9 +46,8 @@ public class TestDockerCpuMetrics { private static final String imageName = Common.imageName("metrics-cpu"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); // These tests create a docker image and run this image with // varying docker cpu options. The arguments passed to the docker diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java index 2afb5ed93b1..818c2c04a1d 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetrics.java @@ -45,9 +45,8 @@ public class TestDockerMemoryMetrics { private static final String imageName = Common.imageName("metrics-memory"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); // These tests create a docker image and run this image with // varying docker memory options. The arguments passed to the docker diff --git a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java index f9dd405891c..7d5dbca6f7c 100644 --- a/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java +++ b/test/jdk/jdk/internal/platform/docker/TestDockerMemoryMetricsSubgroup.java @@ -58,10 +58,7 @@ public class TestDockerMemoryMetricsSubgroup { System.out.println("Cgroup not configured."); return; } - if (!DockerTestUtils.canTestDocker()) { - System.out.println("Unable to run docker tests."); - return; - } + DockerTestUtils.checkCanTestDocker(); ContainerRuntimeVersionTestUtils.checkContainerVersionSupported(); diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index dc70fe32b16..1e5160330de 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -29,9 +29,11 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build GetFreeSwapSpaceSize * @run driver/timeout=480 TestGetFreeSwapSpaceSize */ + import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; import jdk.test.lib.containers.docker.DockerTestUtils; @@ -41,10 +43,8 @@ public class TestGetFreeSwapSpaceSize { private static final String imageName = Common.imageName("osbeanSwapSpace"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java index e4decb7f903..a3df580fed1 100644 --- a/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java +++ b/test/jdk/jdk/internal/platform/docker/TestLimitsUpdating.java @@ -55,10 +55,8 @@ public class TestLimitsUpdating { private static final String imageName = Common.imageName("limitsUpdatingJDK"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java index 033562b3951..87ecae7ee62 100644 --- a/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java +++ b/test/jdk/jdk/internal/platform/docker/TestPidsLimit.java @@ -30,6 +30,7 @@ * @requires container.support * @requires !vm.asan * @library /test/lib + * @modules java.base/jdk.internal.platform * @build TestPidsLimit * @run driver/timeout=480 TestPidsLimit */ @@ -49,10 +50,8 @@ public class TestPidsLimit { private static final int UNLIMITED_PIDS_DOCKER = -1; public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); + DockerTestUtils.checkCanUseResourceLimits(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java index 49ec5663478..e6e78bd5cd8 100644 --- a/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java +++ b/test/jdk/jdk/internal/platform/docker/TestSystemMetrics.java @@ -42,10 +42,7 @@ public class TestSystemMetrics { private static final String imageName = Common.imageName("metrics"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java b/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java index d8d300401a0..e77783f395b 100644 --- a/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java +++ b/test/jdk/jdk/internal/platform/docker/TestUseContainerSupport.java @@ -42,10 +42,7 @@ public class TestUseContainerSupport { private static final String imageName = Common.imageName("useContainerSupport"); public static void main(String[] args) throws Exception { - if (!DockerTestUtils.canTestDocker()) { - return; - } - + DockerTestUtils.checkCanTestDocker(); DockerTestUtils.buildJdkContainerImage(imageName); try { diff --git a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java index 422671d65b7..ec3e6d773b1 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, 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 @@ -38,6 +38,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; +import jdk.internal.platform.Metrics; import jdk.test.lib.Container; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; @@ -47,6 +48,7 @@ import jtreg.SkippedException; public class DockerTestUtils { private static boolean isDockerEngineAvailable = false; private static boolean wasDockerEngineChecked = false; + private static final Metrics metrics = Metrics.systemMetrics(); // Specifies how many lines to copy from child STDOUT to main test output. // Having too many lines in the main test output will result @@ -93,16 +95,12 @@ public class DockerTestUtils { } /** - * Convenience method, will check if docker engine is available and usable; - * will print the appropriate message when not available. + * Checks if the docker engine is available and usable, throws an exception if not. * - * @return true if docker engine is available * @throws Exception */ - public static boolean canTestDocker() throws Exception { - if (isDockerEngineAvailable()) { - return true; - } else { + public static void checkCanTestDocker() throws Exception { + if (!isDockerEngineAvailable()) { throw new SkippedException("Docker engine is not available on this system"); } } @@ -133,6 +131,17 @@ public class DockerTestUtils { return execute(Container.ENGINE_COMMAND, "info", "-f", format).getStdout(); } + /** + * Checks if the engine can use resource limits, throws an exception if not. + * + * @throws Exception + */ + public static void checkCanUseResourceLimits() throws Exception { + if (isRootless() && "cgroupv1".equals(metrics.getProvider())) { + throw new SkippedException("Resource limits are not available on this system"); + } + } + /** * Determine if the engine is running in root-less mode. * From 804ce0a2394cb3f837441976e5ef6eb4b9cab257 Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Wed, 3 Dec 2025 10:29:09 +0000 Subject: [PATCH 013/141] 8370473: C2: Better Aligment of Vector Spill Slots Reviewed-by: goetz, mdoerr --- src/hotspot/cpu/aarch64/aarch64.ad | 3 + src/hotspot/cpu/ppc/ppc.ad | 70 ++++++----- src/hotspot/share/opto/chaitin.hpp | 2 +- src/hotspot/share/opto/matcher.cpp | 13 +-- src/hotspot/share/opto/regmask.hpp | 16 +-- .../compiler/lib/ir_framework/IRNode.java | 6 + .../vectorapi/TestVectorSpilling.java | 110 ++++++++++++++++++ 7 files changed, 174 insertions(+), 46 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 9c76ed24788..b9252cc56ff 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2003,6 +2003,9 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r if (bottom_type()->isa_vect() && !bottom_type()->isa_vectmask()) { uint ireg = ideal_reg(); + DEBUG_ONLY(int algm = MIN2(RegMask::num_registers(ireg), (int)Matcher::stack_alignment_in_slots()) * VMRegImpl::stack_slot_size); + assert((src_lo_rc != rc_stack) || is_aligned(src_offset, algm), "unaligned vector spill sp offset %d (src)", src_offset); + assert((dst_lo_rc != rc_stack) || is_aligned(dst_offset, algm), "unaligned vector spill sp offset %d (dst)", dst_offset); if (ireg == Op_VecA && masm) { int sve_vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 87fcf112756..aa00609094e 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -1795,10 +1795,13 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r return size; // Self copy, no move. if (bottom_type()->isa_vect() != nullptr && ideal_reg() == Op_VecX) { + int src_offset = ra_->reg2offset(src_lo); + int dst_offset = ra_->reg2offset(dst_lo); + DEBUG_ONLY(int algm = MIN2(RegMask::num_registers(ideal_reg()), (int)Matcher::stack_alignment_in_slots()) * VMRegImpl::stack_slot_size); + assert((src_lo_rc != rc_stack) || is_aligned(src_offset, algm), "unaligned vector spill sp offset %d (src)", src_offset); + assert((dst_lo_rc != rc_stack) || is_aligned(dst_offset, algm), "unaligned vector spill sp offset %d (dst)", dst_offset); // Memory->Memory Spill. if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { - int src_offset = ra_->reg2offset(src_lo); - int dst_offset = ra_->reg2offset(dst_lo); if (masm) { __ ld(R0, src_offset, R1_SP); __ std(R0, dst_offset, R1_SP); @@ -1806,26 +1809,20 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r __ std(R0, dst_offset+8, R1_SP); } size += 16; +#ifndef PRODUCT + if (st != nullptr) { + st->print("%-7s [R1_SP + #%d] -> [R1_SP + #%d] \t// vector spill copy", "SPILL", src_offset, dst_offset); + } +#endif // !PRODUCT } // VectorRegister->Memory Spill. else if (src_lo_rc == rc_vec && dst_lo_rc == rc_stack) { VectorSRegister Rsrc = as_VectorRegister(Matcher::_regEncode[src_lo]).to_vsr(); - int dst_offset = ra_->reg2offset(dst_lo); if (PowerArchitecturePPC64 >= 9) { - if (is_aligned(dst_offset, 16)) { - if (masm) { - __ stxv(Rsrc, dst_offset, R1_SP); // matches storeV16_Power9 - } - size += 4; - } else { - // Other alignment can be used by Vector API (VectorPayload in rearrangeOp, - // observed with VectorRearrangeTest.java on Power9). - if (masm) { - __ addi(R0, R1_SP, dst_offset); - __ stxvx(Rsrc, R0); // matches storeV16_Power9 (regarding element ordering) - } - size += 8; + if (masm) { + __ stxv(Rsrc, dst_offset, R1_SP); // matches storeV16_Power9 } + size += 4; } else { if (masm) { __ addi(R0, R1_SP, dst_offset); @@ -1833,24 +1830,25 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r } size += 8; } +#ifndef PRODUCT + if (st != nullptr) { + if (PowerArchitecturePPC64 >= 9) { + st->print("%-7s %s, [R1_SP + #%d] \t// vector spill copy", "STXV", Matcher::regName[src_lo], dst_offset); + } else { + st->print("%-7s R0, R1_SP, %d \t// vector spill copy\n\t" + "%-7s %s, [R0] \t// vector spill copy", "ADDI", dst_offset, "STXVD2X", Matcher::regName[src_lo]); + } + } +#endif // !PRODUCT } // Memory->VectorRegister Spill. else if (src_lo_rc == rc_stack && dst_lo_rc == rc_vec) { VectorSRegister Rdst = as_VectorRegister(Matcher::_regEncode[dst_lo]).to_vsr(); - int src_offset = ra_->reg2offset(src_lo); if (PowerArchitecturePPC64 >= 9) { - if (is_aligned(src_offset, 16)) { - if (masm) { - __ lxv(Rdst, src_offset, R1_SP); - } - size += 4; - } else { - if (masm) { - __ addi(R0, R1_SP, src_offset); - __ lxvx(Rdst, R0); - } - size += 8; + if (masm) { + __ lxv(Rdst, src_offset, R1_SP); } + size += 4; } else { if (masm) { __ addi(R0, R1_SP, src_offset); @@ -1858,6 +1856,16 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r } size += 8; } +#ifndef PRODUCT + if (st != nullptr) { + if (PowerArchitecturePPC64 >= 9) { + st->print("%-7s %s, [R1_SP + #%d] \t// vector spill copy", "LXV", Matcher::regName[dst_lo], src_offset); + } else { + st->print("%-7s R0, R1_SP, %d \t// vector spill copy\n\t" + "%-7s %s, [R0] \t// vector spill copy", "ADDI", src_offset, "LXVD2X", Matcher::regName[dst_lo]); + } + } +#endif // !PRODUCT } // VectorRegister->VectorRegister. else if (src_lo_rc == rc_vec && dst_lo_rc == rc_vec) { @@ -1867,6 +1875,12 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r __ xxlor(Rdst, Rsrc, Rsrc); } size += 4; +#ifndef PRODUCT + if (st != nullptr) { + st->print("%-7s %s, %s, %s\t// vector spill copy", + "XXLOR", Matcher::regName[dst_lo], Matcher::regName[src_lo], Matcher::regName[src_lo]); + } +#endif // !PRODUCT } else { ShouldNotReachHere(); // No VR spill. diff --git a/src/hotspot/share/opto/chaitin.hpp b/src/hotspot/share/opto/chaitin.hpp index ac072e94e2b..2d4f7eeb3f2 100644 --- a/src/hotspot/share/opto/chaitin.hpp +++ b/src/hotspot/share/opto/chaitin.hpp @@ -144,7 +144,7 @@ public: private: // Number of registers this live range uses when it colors - uint16_t _num_regs; // 2 for Longs and Doubles, 1 for all else + uint16_t _num_regs; // byte size of the value divided by slot size which is 4 // except _num_regs is kill count for fat_proj // For scalable register, num_regs may not be the actual physical register size. diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 159e13d8d23..69098befa38 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -285,13 +285,12 @@ void Matcher::match( ) { _parm_regs[i].set_pair(reg2, reg1); } - // Finally, make sure the incoming arguments take up an even number of - // words, in case the arguments or locals need to contain doubleword stack - // slots. The rest of the system assumes that stack slot pairs (in - // particular, in the spill area) which look aligned will in fact be - // aligned relative to the stack pointer in the target machine. Double - // stack slots will always be allocated aligned. - _new_SP = OptoReg::Name(align_up(_in_arg_limit, (int)RegMask::SlotsPerLong)); + // Allocated register sets are aligned to their size. Offsets to the stack + // pointer have to be aligned to the size of the access. For this _new_SP is + // aligned to the size of the largest register set with the stack alignment as + // limit and a minimum of SlotsPerLong (2). + int vector_aligment = MIN2(C->max_vector_size(), stack_alignment_in_bytes()) / VMRegImpl::stack_slot_size; + _new_SP = OptoReg::Name(align_up(_in_arg_limit, MAX2((int)RegMask::SlotsPerLong, vector_aligment))); // Compute highest outgoing stack argument as // _new_SP + out_preserve_stack_slots + max(outgoing argument size). diff --git a/src/hotspot/share/opto/regmask.hpp b/src/hotspot/share/opto/regmask.hpp index 453fbb45d33..421031fdf61 100644 --- a/src/hotspot/share/opto/regmask.hpp +++ b/src/hotspot/share/opto/regmask.hpp @@ -354,16 +354,12 @@ public: } // SlotsPerLong is 2, since slots are 32 bits and longs are 64 bits. - // Also, consider the maximum alignment size for a normally allocated - // value. Since we allocate register pairs but not register quads (at - // present), this alignment is SlotsPerLong (== 2). A normally - // aligned allocated register is either a single register, or a pair - // of adjacent registers, the lower-numbered being even. - // See also is_aligned_Pairs() below, and the padding added before - // Matcher::_new_SP to keep allocated pairs aligned properly. - // If we ever go to quad-word allocations, SlotsPerQuad will become - // the controlling alignment constraint. Note that this alignment - // requirement is internal to the allocator, and independent of any + // We allocate single registers for 32 bit values and register pairs for 64 + // bit values. The number of registers allocated for vectors match their size. E.g. for 128 bit + // vectors (VecX) we allocate a set of 4 registers. Allocated sets are adjacent and aligned. + // See RegMask::find_first_set(), is_aligned_pairs(), is_aligned_sets(), and the padding added before + // Matcher::_new_SP to keep allocated pairs and sets aligned properly. + // Note that this alignment requirement is internal to the allocator, and independent of any // particular platform. enum { SlotsPerLong = 2, SlotsPerVecA = 4, diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 787dedba9c6..85595b9b632 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1257,6 +1257,12 @@ public class IRNode { machOnly(MEM_TO_REG_SPILL_COPY, "MemToRegSpillCopy"); } + public static final String MEM_TO_REG_SPILL_COPY_TYPE = COMPOSITE_PREFIX + "MEM_TO_REG_SPILL_COPY_TYPE" + POSTFIX; + static { + String regex = START + "MemToRegSpillCopy" + MID + IS_REPLACED + ".*" + END; + machOnly(MEM_TO_REG_SPILL_COPY_TYPE, regex); + } + public static final String MIN = PREFIX + "MIN" + POSTFIX; static { beforeMatchingNameRegex(MIN, "Min(I|L)"); diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java new file mode 100644 index 00000000000..9d9a85e174c --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorSpilling.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 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 + * 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 compiler.lib.ir_framework.*; + +import jdk.incubator.vector.IntVector; +import jdk.incubator.vector.VectorSpecies; + +import jdk.test.lib.Asserts; + +/** + * @test + * @bug 8370473 + * @library /test/lib / + * @summary Test alignment of vector spill slots. It should match the vector size. + * @modules jdk.incubator.vector + * @requires vm.opt.final.MaxVectorSize == null | vm.opt.final.MaxVectorSize >= 16 + * + * @run driver compiler.vectorapi.TestVectorSpilling + */ + +public class TestVectorSpilling { + + private static final VectorSpecies I_SPECIES = IntVector.SPECIES_128; + private static int LENGTH = 1024; + + private static int[] ia1; + private static int[] ia2; + private static int[] ir ; + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector"); + } + + static class LData { + // Rading from a volatile field prevents cse optimization + static volatile long vF = 1042; + + long l1, l2, l3, l4, l5, l6, l7, l8; + public LData() { + l1 = vF; l2 = vF; l3 = vF; l4 = vF; l5 = vF; l6 = vF; l7 = vF; l8 = vF; + } + public long sum() { + return l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8; + } + } + + + @Run(test = "test16ByteSpilling") + static void test16ByteSpilling_runner() { + test16ByteSpilling(1, 2, 3, 4, 5, 6, 7, 8, 9); + } + + @Test + @IR(counts = {IRNode.MEM_TO_REG_SPILL_COPY_TYPE, "vectorx", "> 0"}, + phase = {CompilePhase.FINAL_CODE}, + applyIfCPUFeature= {"rvv", "false"}) + static long test16ByteSpilling(long l1, long l2, long l3, long l4, long l5, long l6, long l7, long l8, + long l9 /* odd stack arg */) { + // To be scalar replaced and spilled to stack + LData d1 = new LData(); + LData d2 = new LData(); + LData d3 = new LData(); + + for (int i = 0; i < LENGTH; i += I_SPECIES.length()) { + IntVector a1v = IntVector.fromArray(I_SPECIES, ia1, i); + IntVector a2v = IntVector.fromArray(I_SPECIES, ia2, i); + int scalar = spillPoint(); + a1v.add(a2v) + .add(scalar).intoArray(ir, i); + } + + return l1 + l2 + l3 + l4 + l5 + l6 + l7 + l8 + l9 + d1.sum() + d2.sum() + d3.sum(); + } + + @DontInline + static int spillPoint() { + return 42; + } + + static { + ia1 = new int[LENGTH]; + ia2 = new int[LENGTH]; + ir = new int[LENGTH]; + } + +} From 170ebdc5b7b5e54cc7bec60944898d35a24d760b Mon Sep 17 00:00:00 2001 From: Igor Rudenko Date: Wed, 3 Dec 2025 10:37:55 +0000 Subject: [PATCH 014/141] 8346657: Improve out of bounds exception messages for MemorySegments Reviewed-by: jvernee, liach, mcimadamore --- .../foreign/AbstractMemorySegmentImpl.java | 58 ++++++++++++------- .../foreign/SegmentBulkOperations.java | 2 +- .../jdk/internal/foreign/StringSupport.java | 6 +- test/jdk/java/foreign/TestSegments.java | 26 +++++++-- 4 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index d7636032c28..a0c8a0a5a4f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -33,6 +33,7 @@ import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.util.ArraysSupport; import jdk.internal.util.Preconditions; +import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.ForceInline; import sun.nio.ch.DirectBuffer; @@ -68,7 +69,7 @@ import java.util.stream.StreamSupport; * {@link MappedMemorySegmentImpl}. */ public abstract sealed class AbstractMemorySegmentImpl - implements MemorySegment, SegmentAllocator, BiFunction, RuntimeException> + implements MemorySegment, SegmentAllocator permits HeapMemorySegmentImpl, NativeMemorySegmentImpl { static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess(); @@ -100,19 +101,19 @@ public abstract sealed class AbstractMemorySegmentImpl @Override public AbstractMemorySegmentImpl asSlice(long offset, long newSize) { - checkBounds(offset, newSize); + checkSliceBounds(offset, newSize); return asSliceNoCheck(offset, newSize); } @Override public AbstractMemorySegmentImpl asSlice(long offset) { - checkBounds(offset, 0); + checkSliceBounds(offset, 0); return asSliceNoCheck(offset, length - offset); } @Override public MemorySegment asSlice(long offset, long newSize, long byteAlignment) { - checkBounds(offset, newSize); + checkSliceBounds(offset, newSize); Utils.checkAlign(byteAlignment); if (!isAlignedForElement(offset, byteAlignment)) { @@ -354,7 +355,7 @@ public abstract sealed class AbstractMemorySegmentImpl @ForceInline public void checkAccess(long offset, long length, boolean readOnly) { checkReadOnly(readOnly); - checkBounds(offset, length); + checkAccessBounds(offset, length); } @ForceInline @@ -398,20 +399,40 @@ public abstract sealed class AbstractMemorySegmentImpl } @ForceInline - void checkBounds(long offset, long length) { - if (length > 0) { - Preconditions.checkIndex(offset, this.length - length + 1, this); - } else if (length < 0 || offset < 0 || - offset > this.length - length) { - throw outOfBoundException(offset, length); + void checkSliceBounds(long offset, long length) { + try { + checkBounds(offset, length); + } catch (IndexOutOfBoundsException e) { + throwOutOfBounds(offset, length, /* isSlice = */ true); } } - @Override - public RuntimeException apply(String s, List numbers) { - long offset = numbers.get(0).longValue(); - long length = byteSize() - numbers.get(1).longValue() + 1; - return outOfBoundException(offset, length); + @ForceInline + void checkAccessBounds(long offset, long length) { + try { + checkBounds(offset, length); + } catch (IndexOutOfBoundsException e) { + throwOutOfBounds(offset, length, /* isSlice = */ false); + } + } + + @ForceInline + private void checkBounds(long offset, long length) { + if (length > 0) { + Preconditions.checkIndex(offset, this.length - length + 1, null); + } else if (length < 0 || offset < 0 || + offset > this.length - length) { + throw new IndexOutOfBoundsException(); + } + } + + @DontInline + private void throwOutOfBounds(long offset, long length, boolean isSlice) { + String action = isSlice ? "get slice" : "access an element"; + String msg = String.format("Out of bound access on segment %s; attempting to %s of length %d at offset %d " + + "which is outside the valid range 0 <= offset+length < byteSize (=%d)", + this, action, length, offset, this.length); + throw new IndexOutOfBoundsException(msg); } @Override @@ -429,11 +450,6 @@ public abstract sealed class AbstractMemorySegmentImpl return scope; } - private IndexOutOfBoundsException outOfBoundException(long offset, long length) { - return new IndexOutOfBoundsException(String.format("Out of bound access on segment %s; new offset = %d; new length = %d", - this, offset, length)); - } - static class SegmentSplitter implements Spliterator { AbstractMemorySegmentImpl segment; long elemCount; diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java index 5af4bc37692..ab6b78b73ee 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentBulkOperations.java @@ -194,7 +194,7 @@ public final class SegmentBulkOperations { @ForceInline public static int contentHash(AbstractMemorySegmentImpl segment, long fromOffset, long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length == 0) { // The state has to be checked explicitly for zero-length segments segment.scope.checkValidState(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java index bb6cb2d3915..208c6d54aab 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java +++ b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java @@ -145,7 +145,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Byte.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); @@ -179,7 +179,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Short.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); @@ -215,7 +215,7 @@ public final class StringSupport { final long fromOffset, final long toOffset) { final long length = toOffset - fromOffset; - segment.checkBounds(fromOffset, length); + segment.checkSliceBounds(fromOffset, length); if (length < Integer.BYTES) { // There can be no null terminator present segment.scope.checkValidState(); diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java index 2942b388d50..e9f3e8a87cc 100644 --- a/test/jdk/java/foreign/TestSegments.java +++ b/test/jdk/java/foreign/TestSegments.java @@ -212,14 +212,32 @@ public class TestSegments { } @Test - public void testSegmentOOBMessage() { + public void testSegmentAccessOOBMessage() { try { var segment = Arena.global().allocate(10, 1); segment.getAtIndex(ValueLayout.JAVA_INT, 2); + fail("Expected IndexOutOfBoundsException was not thrown"); } catch (IndexOutOfBoundsException ex) { - assertTrue(ex.getMessage().contains("Out of bound access")); - assertTrue(ex.getMessage().contains("offset = 8")); - assertTrue(ex.getMessage().contains("length = 4")); + assertTrue(ex.getMessage().startsWith("Out of bound access")); + assertTrue(ex.getMessage().endsWith("attempting to access an element of length 4 at offset 8 " + + "which is outside the valid range 0 <= offset+length < byteSize (=10)")); + } catch (Exception ex) { + fail("Unexpected exception type thrown: " + ex); + } + } + + @Test + public void testSegmentSliceOOBMessage() { + try { + var segment = Arena.global().allocate(10, 1); + var slice = segment.asSlice(8, 4); + fail("Expected IndexOutOfBoundsException was not thrown"); + } catch (IndexOutOfBoundsException ex) { + assertTrue(ex.getMessage().startsWith("Out of bound access")); + assertTrue(ex.getMessage().endsWith("attempting to get slice of length 4 at offset 8 " + + "which is outside the valid range 0 <= offset+length < byteSize (=10)")); + } catch (Exception ex) { + fail("Unexpected exception type thrown: " + ex); } } From 3f447edf0e22431628ebb74212f760209ea29d37 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 3 Dec 2025 10:55:12 +0000 Subject: [PATCH 015/141] 8372862: AArch64: Fix GetAndSet-acquire costs after JDK-8372188 Reviewed-by: dlong, mhaessig --- src/hotspot/cpu/aarch64/aarch64_atomic.ad | 8 ++++---- src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic.ad b/src/hotspot/cpu/aarch64/aarch64_atomic.ad index faac2a43110..3b05a637215 100644 --- a/src/hotspot/cpu/aarch64/aarch64_atomic.ad +++ b/src/hotspot/cpu/aarch64/aarch64_atomic.ad @@ -695,7 +695,7 @@ instruct getAndSetP(indirect mem, iRegP newval, iRegPNoSp oldval) %{ instruct getAndSetIAcq(indirect mem, iRegI newval, iRegINoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set oldval (GetAndSetI mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgw_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgalw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); @@ -706,7 +706,7 @@ instruct getAndSetIAcq(indirect mem, iRegI newval, iRegINoSp oldval) %{ instruct getAndSetLAcq(indirect mem, iRegL newval, iRegLNoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n)); match(Set oldval (GetAndSetL mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchg_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgal($oldval$$Register, $newval$$Register, as_Register($mem$$base)); @@ -717,7 +717,7 @@ instruct getAndSetLAcq(indirect mem, iRegL newval, iRegLNoSp oldval) %{ instruct getAndSetNAcq(indirect mem, iRegN newval, iRegNNoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set oldval (GetAndSetN mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgw_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgalw($oldval$$Register, $newval$$Register, as_Register($mem$$base)); @@ -728,7 +728,7 @@ instruct getAndSetNAcq(indirect mem, iRegN newval, iRegNNoSp oldval) %{ instruct getAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp oldval) %{ predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0)); match(Set oldval (GetAndSetP mem newval)); - ins_cost(2*VOLATILE_REF_COST); + ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchg_acq $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchgal($oldval$$Register, $newval$$Register, as_Register($mem$$base)); diff --git a/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 index 721b720873a..dc51754e7f9 100644 --- a/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_atomic_ad.m4 @@ -187,7 +187,7 @@ ifelse($1$3,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_Lo $3,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), `dnl') match(Set oldval (GetAndSet$1 mem newval)); - ins_cost(`'ifelse($4,Acq,,2*)VOLATILE_REF_COST); + ins_cost(`'ifelse($3,Acq,,2*)VOLATILE_REF_COST); format %{ "atomic_xchg$2`'ifelse($3,Acq,_acq) $oldval, $newval, [$mem]" %} ins_encode %{ __ atomic_xchg`'ifelse($3,Acq,al)$2($oldval$$Register, $newval$$Register, as_Register($mem$$base)); From 125d1820f1f64e465a6b83360c48715a79e3d165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?= Date: Wed, 3 Dec 2025 11:12:00 +0000 Subject: [PATCH 016/141] 8372393: Document requirement for separate metallib installation with Xcode 26.1.1 Reviewed-by: erikj --- doc/building.html | 5 +++++ doc/building.md | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/doc/building.html b/doc/building.html index 19313ebf43a..8e5a7625371 100644 --- a/doc/building.html +++ b/doc/building.html @@ -541,6 +541,11 @@ href="#apple-xcode">Apple Xcode on some strategies to deal with this.

It is recommended that you use at least macOS 14 and Xcode 15.4, but earlier versions may also work.

+

Starting with Xcode 26, introduced in macOS 26, the Metal toolchain +no longer comes bundled with Xcode, so it needs to be installed +separately. This can either be done via the Xcode's Settings/Components +UI, or in the command line calling +xcodebuild -downloadComponent metalToolchain.

The standard macOS environment contains the basic tooling needed to build, but for external libraries a package manager is recommended. The JDK uses homebrew in the examples, but diff --git a/doc/building.md b/doc/building.md index 1fbd395a9d1..b626027f101 100644 --- a/doc/building.md +++ b/doc/building.md @@ -352,6 +352,11 @@ on some strategies to deal with this. It is recommended that you use at least macOS 14 and Xcode 15.4, but earlier versions may also work. +Starting with Xcode 26, introduced in macOS 26, the Metal toolchain no longer +comes bundled with Xcode, so it needs to be installed separately. This can +either be done via the Xcode's Settings/Components UI, or in the command line +calling `xcodebuild -downloadComponent metalToolchain`. + The standard macOS environment contains the basic tooling needed to build, but for external libraries a package manager is recommended. The JDK uses [homebrew](https://brew.sh/) in the examples, but feel free to use whatever From a655ea48453a321fb7cadc6ffb6111276497a929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarre=C3=B1o?= Date: Wed, 3 Dec 2025 12:31:26 +0000 Subject: [PATCH 017/141] 8371792: Refactor barrier loop tests out of TestIfMinMax Reviewed-by: chagedorn, epeter, bmaillard --- .../compiler/c2/irTests/TestIfMinMax.java | 38 +------- .../gcbarriers/TestMinMaxLongLoopBarrier.java | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+), 37 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java index fdc0a83fb8b..bfcc775efeb 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestIfMinMax.java @@ -30,7 +30,7 @@ import jdk.test.lib.Utils; /* * @test - * @bug 8324655 8329797 8331090 + * @bug 8324655 8331090 * @key randomness * @summary Test that if expressions are properly folded into min/max nodes * @library /test/lib / @@ -139,42 +139,6 @@ public class TestIfMinMax { return a <= b ? b : a; } - public class Dummy { - long l; - public Dummy(long l) { this.l = l; } - } - - @Setup - Object[] setupDummyArray() { - Dummy[] arr = new Dummy[512]; - for (int i = 0; i < 512; i++) { - arr[i] = new Dummy(RANDOM.nextLong()); - } - return new Object[] { arr }; - } - - @Test - @Arguments(setup = "setupDummyArray") - @IR(failOn = { IRNode.MAX_L }) - public long testMaxLAndBarrierInLoop(Dummy[] arr) { - long result = 0; - for (int i = 0; i < arr.length; ++i) { - result += Math.max(arr[i].l, 1); - } - return result; - } - - @Test - @Arguments(setup = "setupDummyArray") - @IR(failOn = { IRNode.MIN_L }) - public long testMinLAndBarrierInLoop(Dummy[] arr) { - long result = 0; - for (int i = 0; i < arr.length; ++i) { - result += Math.min(arr[i].l, 1); - } - return result; - } - @Setup static Object[] setupIntArrays() { int[] a = new int[512]; diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java b/test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java new file mode 100644 index 00000000000..9f2ddc0d20e --- /dev/null +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestMinMaxLongLoopBarrier.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package compiler.gcbarriers; + +import compiler.lib.ir_framework.Arguments; +import compiler.lib.ir_framework.IR; +import compiler.lib.ir_framework.IRNode; +import compiler.lib.ir_framework.Setup; +import compiler.lib.ir_framework.Test; +import compiler.lib.ir_framework.TestFramework; +import jdk.test.lib.Utils; + +import java.util.Random; + +/* + * @test + * @bug 8329797 + * @key randomness + * @summary Test that MinL/MaxL nodes are removed when GC barriers in loop + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class TestMinMaxLongLoopBarrier { + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + TestFramework.run(); + } + + public class Dummy { + long l; + public Dummy(long l) { this.l = l; } + } + + @Setup + Object[] setupDummyArray() { + Dummy[] arr = new Dummy[512]; + for (int i = 0; i < 512; i++) { + arr[i] = new Dummy(RANDOM.nextLong()); + } + return new Object[] { arr }; + } + + @Test + @Arguments(setup = "setupDummyArray") + @IR(failOn = { IRNode.MAX_L }) + public long testMaxLAndBarrierInLoop(Dummy[] arr) { + long result = 0; + for (int i = 0; i < arr.length; ++i) { + result += Math.max(arr[i].l, 1); + } + return result; + } + + @Test + @Arguments(setup = "setupDummyArray") + @IR(failOn = { IRNode.MIN_L }) + public long testMinLAndBarrierInLoop(Dummy[] arr) { + long result = 0; + for (int i = 0; i < arr.length; ++i) { + result += Math.min(arr[i].l, 1); + } + return result; + } +} From abb75ba656ebe14e9e8e1d4a1765d64dfce9e661 Mon Sep 17 00:00:00 2001 From: Kerem Kat Date: Wed, 3 Dec 2025 13:01:32 +0000 Subject: [PATCH 018/141] 8372587: Put jdk/jfr/jvm/TestWaste.java into the ProblemList Reviewed-by: dholmes --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 9904bd88626..1d547faf662 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -750,6 +750,7 @@ jdk/jfr/event/compiler/TestCodeSweeper.java 8338127 generic- 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 ############################################################################ From afb6a0c2fecdb2114715290d5d463c9dccf93c28 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 3 Dec 2025 13:03:51 +0000 Subject: [PATCH 019/141] 8372958: SocketInputStream.read throws SocketException instead of returning -1 when input shutdown Reviewed-by: djelinski, michaelm --- .../classes/sun/nio/ch/NioSocketImpl.java | 23 +- test/jdk/java/net/Socket/AsyncShutdown.java | 50 ++-- .../java/net/vthread/BlockingSocketOps.java | 242 ++++++++---------- .../channels/vthread/BlockingChannelOps.java | 89 ++----- 4 files changed, 171 insertions(+), 233 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java index 5832e7f529a..57935ff5b00 100644 --- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java @@ -289,6 +289,7 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp */ private int implRead(byte[] b, int off, int len, long remainingNanos) throws IOException { int n = 0; + SocketException ex = null; FileDescriptor fd = beginRead(); try { if (connectionReset) @@ -307,18 +308,24 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp n = tryRead(fd, b, off, len); } } - return n; } catch (InterruptedIOException e) { throw e; } catch (ConnectionResetException e) { connectionReset = true; throw new SocketException("Connection reset"); } catch (IOException ioe) { - // throw SocketException to maintain compatibility - throw asSocketException(ioe); + // translate to SocketException to maintain compatibility + ex = asSocketException(ioe); } finally { endRead(n > 0); } + if (n <= 0 && isInputClosed) { + return -1; + } + if (ex != null) { + throw ex; + } + return n; } /** @@ -411,6 +418,7 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp */ private int implWrite(byte[] b, int off, int len) throws IOException { int n = 0; + SocketException ex = null; FileDescriptor fd = beginWrite(); try { configureNonBlockingIfNeeded(fd, false); @@ -419,15 +427,18 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp park(fd, Net.POLLOUT); n = tryWrite(fd, b, off, len); } - return n; } catch (InterruptedIOException e) { throw e; } catch (IOException ioe) { - // throw SocketException to maintain compatibility - throw asSocketException(ioe); + // translate to SocketException to maintain compatibility + ex = asSocketException(ioe); } finally { endWrite(n > 0); } + if (ex != null) { + throw ex; + } + return n; } /** diff --git a/test/jdk/java/net/Socket/AsyncShutdown.java b/test/jdk/java/net/Socket/AsyncShutdown.java index cdc930b360c..159c08075ad 100644 --- a/test/jdk/java/net/Socket/AsyncShutdown.java +++ b/test/jdk/java/net/Socket/AsyncShutdown.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 @@ -24,11 +24,13 @@ /* * @test * @requires (os.family == "linux" | os.family == "mac") - * @run testng AsyncShutdown * @summary Test shutdownInput/shutdownOutput with threads blocked in read/write + * @run junit AsyncShutdown */ import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; @@ -38,54 +40,56 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import static org.junit.jupiter.api.Assertions.*; -@Test -public class AsyncShutdown { +class AsyncShutdown { - public void testShutdownInput1() throws IOException { + @ParameterizedTest + @ValueSource(booleans = { false, true }) + void testShutdownInput(boolean timed) throws IOException { withConnection((s1, s2) -> { + InputStream in = s1.getInputStream(); scheduleShutdownInput(s1, 2000); - int n = s1.getInputStream().read(); - assertTrue(n == -1); + if (timed) { + s1.setSoTimeout(30*1000); + } + assertEquals(-1, in.read()); + assertEquals(0, in.available()); }); } - public void testShutdownInput2() throws IOException { - withConnection((s1, s2) -> { - scheduleShutdownInput(s1, 2000); - s1.setSoTimeout(30*1000); - int n = s1.getInputStream().read(); - assertTrue(n == -1); - }); - } - - public void testShutdownOutput1() throws IOException { + @Test + void testShutdownOutput1() throws IOException { withConnection((s1, s2) -> { + OutputStream out = s1.getOutputStream(); scheduleShutdownOutput(s1, 2000); byte[] data = new byte[128*1024]; try { while (true) { - s1.getOutputStream().write(data); + out.write(data); } } catch (IOException expected) { } }); } - public void testShutdownOutput2() throws IOException { + @Test + void testShutdownOutput2() throws IOException { withConnection((s1, s2) -> { s1.setSoTimeout(100); try { s1.getInputStream().read(); - assertTrue(false); + fail(); } catch (SocketTimeoutException e) { } + OutputStream out = s1.getOutputStream(); scheduleShutdownOutput(s1, 2000); byte[] data = new byte[128*1024]; try { while (true) { - s1.getOutputStream().write(data); + out.write(data); } } catch (IOException expected) { } }); diff --git a/test/jdk/java/net/vthread/BlockingSocketOps.java b/test/jdk/java/net/vthread/BlockingSocketOps.java index 3c6b9cd5276..ef58e06b915 100644 --- a/test/jdk/java/net/vthread/BlockingSocketOps.java +++ b/test/jdk/java/net/vthread/BlockingSocketOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,15 +21,15 @@ * questions. */ -/** +/* * @test id=default - * @bug 8284161 + * @bug 8284161 8372958 * @summary Test virtual threads doing blocking I/O on java.net Sockets * @library /test/lib * @run junit BlockingSocketOps */ -/** +/* * @test id=poller-modes * @requires (os.family == "linux") | (os.family == "mac") * @library /test/lib @@ -37,7 +37,7 @@ * @run junit/othervm -Djdk.pollerMode=2 BlockingSocketOps */ -/** +/* * @test id=no-vmcontinuations * @requires vm.continuations * @library /test/lib @@ -60,6 +60,8 @@ import java.net.SocketTimeoutException; import jdk.test.lib.thread.VThreadRunner; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.*; class BlockingSocketOps { @@ -90,19 +92,8 @@ class BlockingSocketOps { /** * Virtual thread blocks in read. */ - @Test - void testSocketRead1() throws Exception { - testSocketRead(0); - } - - /** - * Virtual thread blocks in timed read. - */ - @Test - void testSocketRead2() throws Exception { - testSocketRead(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testSocketRead(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { @@ -202,19 +193,8 @@ class BlockingSocketOps { /** * Socket close while virtual thread blocked in read. */ - @Test - void testSocketReadAsyncClose1() throws Exception { - testSocketReadAsyncClose(0); - } - - /** - * Socket close while virtual thread blocked in timed read. - */ - @Test - void testSocketReadAsyncClose2() throws Exception { - testSocketReadAsyncClose(0); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testSocketReadAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { @@ -230,7 +210,34 @@ class BlockingSocketOps { try { int n = s.getInputStream().read(); fail("read " + n); - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } + } + }); + } + + /** + * Socket shutdownInput while virtual thread blocked in read. + */ + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testSocketReadAsyncShutdownInput(int timeout) throws Exception { + VThreadRunner.run(() -> { + try (var connection = new Connection()) { + Socket s = connection.socket1(); + + // delayed shutdown of input stream + InputStream in = s.getInputStream(); + runAfterParkedAsync(s::shutdownInput); + + // read should return -1 + if (timeout > 0) { + s.setSoTimeout(timeout); + } + assertEquals(-1, in.read()); + assertEquals(0, in.available()); + assertFalse(s.isClosed()); } }); } @@ -238,19 +245,8 @@ class BlockingSocketOps { /** * Virtual thread interrupted while blocked in Socket read. */ - @Test - void testSocketReadInterrupt1() throws Exception { - testSocketReadInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in Socket read with timeout - */ - @Test - void testSocketReadInterrupt2() throws Exception { - testSocketReadInterrupt(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testSocketReadInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { @@ -269,6 +265,7 @@ class BlockingSocketOps { int n = s.getInputStream().read(); fail("read " + n); } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(s.isClosed()); } @@ -285,7 +282,7 @@ class BlockingSocketOps { try (var connection = new Connection()) { Socket s = connection.socket1(); - // delayedclose of s + // delayed close of s runAfterParkedAsync(s::close); // write to s should block, then throw @@ -295,7 +292,36 @@ class BlockingSocketOps { for (;;) { out.write(ba); } - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } + } + }); + } + + /** + * Socket shutdownOutput while virtual thread blocked in write. + */ + @Test + void testSocketWriteAsyncShutdownOutput() throws Exception { + VThreadRunner.run(() -> { + try (var connection = new Connection()) { + Socket s = connection.socket1(); + + // delayed shutdown of output stream + OutputStream out = s.getOutputStream(); + runAfterParkedAsync(s::shutdownOutput); + + // write to s should block, then throw + try { + byte[] ba = new byte[100*1024]; + for (;;) { + out.write(ba); + } + } catch (SocketException expected) { + log(expected); + } + assertFalse(s.isClosed()); } }); } @@ -321,6 +347,7 @@ class BlockingSocketOps { out.write(ba); } } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(s.isClosed()); } @@ -355,7 +382,9 @@ class BlockingSocketOps { try { s1.getInputStream().read(ba); fail(); - } catch (SocketTimeoutException expected) { } + } catch (SocketTimeoutException expected) { + log(expected); + } } }); } @@ -384,19 +413,8 @@ class BlockingSocketOps { /** * Virtual thread blocks in accept. */ - @Test - void testServerSocketAccept2() throws Exception { - testServerSocketAccept(0); - } - - /** - * Virtual thread blocks in timed accept. - */ - @Test - void testServerSocketAccept3() throws Exception { - testServerSocketAccept(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testServerSocketAccept(int timeout) throws Exception { VThreadRunner.run(() -> { try (var listener = new ServerSocket()) { @@ -422,19 +440,8 @@ class BlockingSocketOps { /** * ServerSocket close while virtual thread blocked in accept. */ - @Test - void testServerSocketAcceptAsyncClose1() throws Exception { - testServerSocketAcceptAsyncClose(0); - } - - /** - * ServerSocket close while virtual thread blocked in timed accept. - */ - @Test - void testServerSocketAcceptAsyncClose2() throws Exception { - testServerSocketAcceptAsyncClose(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testServerSocketAcceptAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (var listener = new ServerSocket()) { @@ -451,7 +458,9 @@ class BlockingSocketOps { try { listener.accept().close(); fail("connection accepted???"); - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } } }); } @@ -459,19 +468,8 @@ class BlockingSocketOps { /** * Virtual thread interrupted while blocked in ServerSocket accept. */ - @Test - void testServerSocketAcceptInterrupt1() throws Exception { - testServerSocketAcceptInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in ServerSocket accept with timeout. - */ - @Test - void testServerSocketAcceptInterrupt2() throws Exception { - testServerSocketAcceptInterrupt(60_000); - } - + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) void testServerSocketAcceptInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (var listener = new ServerSocket()) { @@ -490,6 +488,7 @@ class BlockingSocketOps { listener.accept().close(); fail("connection accepted???"); } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(listener.isClosed()); } @@ -529,20 +528,9 @@ class BlockingSocketOps { /** * Virtual thread blocks in DatagramSocket receive. */ - @Test - void testDatagramSocketSendReceive2() throws Exception { - testDatagramSocketSendReceive(0); - } - - /** - * Virtual thread blocks in DatagramSocket receive with timeout. - */ - @Test - void testDatagramSocketSendReceive3() throws Exception { - testDatagramSocketSendReceive(60_000); - } - - private void testDatagramSocketSendReceive(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketSendReceive(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramSocket s1 = new DatagramSocket(null); DatagramSocket s2 = new DatagramSocket(null)) { @@ -585,7 +573,9 @@ class BlockingSocketOps { try { s.receive(p); fail(); - } catch (SocketTimeoutException expected) { } + } catch (SocketTimeoutException expected) { + log(expected); + } } }); } @@ -593,20 +583,9 @@ class BlockingSocketOps { /** * DatagramSocket close while virtual thread blocked in receive. */ - @Test - void testDatagramSocketReceiveAsyncClose1() throws Exception { - testDatagramSocketReceiveAsyncClose(0); - } - - /** - * DatagramSocket close while virtual thread blocked with timeout. - */ - @Test - void testDatagramSocketReceiveAsyncClose2() throws Exception { - testDatagramSocketReceiveAsyncClose(60_000); - } - - private void testDatagramSocketReceiveAsyncClose(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketReceiveAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramSocket s = new DatagramSocket(null)) { InetAddress lh = InetAddress.getLoopbackAddress(); @@ -624,7 +603,9 @@ class BlockingSocketOps { DatagramPacket p = new DatagramPacket(ba, ba.length); s.receive(p); fail(); - } catch (SocketException expected) { } + } catch (SocketException expected) { + log(expected); + } } }); } @@ -632,20 +613,9 @@ class BlockingSocketOps { /** * Virtual thread interrupted while blocked in DatagramSocket receive. */ - @Test - void testDatagramSocketReceiveInterrupt1() throws Exception { - testDatagramSocketReceiveInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in DatagramSocket receive with timeout. - */ - @Test - void testDatagramSocketReceiveInterrupt2() throws Exception { - testDatagramSocketReceiveInterrupt(60_000); - } - - private void testDatagramSocketReceiveInterrupt(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketReceiveInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramSocket s = new DatagramSocket(null)) { InetAddress lh = InetAddress.getLoopbackAddress(); @@ -665,6 +635,7 @@ class BlockingSocketOps { s.receive(p); fail(); } catch (SocketException expected) { + log(expected); assertTrue(Thread.interrupted()); assertTrue(s.isClosed()); } @@ -737,4 +708,11 @@ class BlockingSocketOps { } }); } + + /** + * Log to System.err to inline with the JUnit messages. + */ + static void log(Throwable e) { + System.err.println(e); + } } diff --git a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java index f04bece07b6..eb2229d927a 100644 --- a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java +++ b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java @@ -66,6 +66,8 @@ import java.util.concurrent.locks.LockSupport; import jdk.test.lib.thread.VThreadRunner; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.*; class BlockingChannelOps { @@ -301,20 +303,9 @@ class BlockingChannelOps { /** * Virtual thread blocks in SocketChannel adaptor read. */ - @Test - void testSocketAdaptorRead1() throws Exception { - testSocketAdaptorRead(0); - } - - /** - * Virtual thread blocks in SocketChannel adaptor read with timeout. - */ - @Test - void testSocketAdaptorRead2() throws Exception { - testSocketAdaptorRead(60_000); - } - - private void testSocketAdaptorRead(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testSocketAdaptorRead(int timeout) throws Exception { VThreadRunner.run(() -> { try (var connection = new Connection()) { SocketChannel sc1 = connection.channel1(); @@ -420,20 +411,9 @@ class BlockingChannelOps { /** * Virtual thread blocks in ServerSocketChannel adaptor accept. */ - @Test - void testSocketChannelAdaptorAccept1() throws Exception { - testSocketChannelAdaptorAccept(0); - } - - /** - * Virtual thread blocks in ServerSocketChannel adaptor accept with timeout. - */ - @Test - void testSocketChannelAdaptorAccept2() throws Exception { - testSocketChannelAdaptorAccept(60_000); - } - - private void testSocketChannelAdaptorAccept(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testSocketChannelAdaptorAccept(int timeout) throws Exception { VThreadRunner.run(() -> { try (var ssc = ServerSocketChannel.open()) { ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); @@ -546,20 +526,9 @@ class BlockingChannelOps { /** * Virtual thread blocks in DatagramSocket adaptor receive. */ - @Test - void testDatagramSocketAdaptorReceive1() throws Exception { - testDatagramSocketAdaptorReceive(0); - } - - /** - * Virtual thread blocks in DatagramSocket adaptor receive with timeout. - */ - @Test - void testDatagramSocketAdaptorReceive2() throws Exception { - testDatagramSocketAdaptorReceive(60_000); - } - - private void testDatagramSocketAdaptorReceive(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketAdaptorReceive(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramChannel dc1 = DatagramChannel.open(); DatagramChannel dc2 = DatagramChannel.open()) { @@ -585,21 +554,9 @@ class BlockingChannelOps { /** * DatagramChannel close while virtual thread blocked in adaptor receive. */ - @Test - void testDatagramSocketAdaptorReceiveAsyncClose1() throws Exception { - testDatagramSocketAdaptorReceiveAsyncClose(0); - } - - /** - * DatagramChannel close while virtual thread blocked in adaptor receive - * with timeout. - */ - @Test - void testDatagramSocketAdaptorReceiveAsyncClose2() throws Exception { - testDatagramSocketAdaptorReceiveAsyncClose(60_1000); - } - - private void testDatagramSocketAdaptorReceiveAsyncClose(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketAdaptorReceiveAsyncClose(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramChannel dc = DatagramChannel.open()) { InetAddress lh = InetAddress.getLoopbackAddress(); @@ -621,21 +578,9 @@ class BlockingChannelOps { /** * Virtual thread interrupted while blocked in DatagramSocket adaptor receive. */ - @Test - void testDatagramSocketAdaptorReceiveInterrupt1() throws Exception { - testDatagramSocketAdaptorReceiveInterrupt(0); - } - - /** - * Virtual thread interrupted while blocked in DatagramSocket adaptor receive - * with timeout. - */ - @Test - void testDatagramSocketAdaptorReceiveInterrupt2() throws Exception { - testDatagramSocketAdaptorReceiveInterrupt(60_1000); - } - - private void testDatagramSocketAdaptorReceiveInterrupt(int timeout) throws Exception { + @ParameterizedTest + @ValueSource(ints = { 0, 60_000 }) + void testDatagramSocketAdaptorReceiveInterrupt(int timeout) throws Exception { VThreadRunner.run(() -> { try (DatagramChannel dc = DatagramChannel.open()) { InetAddress lh = InetAddress.getLoopbackAddress(); From 135661b4389663b8c2e348d9e61e72cc628636bb Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 3 Dec 2025 13:36:55 +0000 Subject: [PATCH 020/141] 8372179: Remove Unused ConcurrentHashTable::MultiGetHandle Reviewed-by: dholmes, iwalulya --- .../share/utilities/concurrentHashTable.hpp | 15 +-------------- .../utilities/concurrentHashTable.inline.hpp | 8 -------- .../utilities/test_concurrentHashtable.cpp | 17 ++--------------- 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/hotspot/share/utilities/concurrentHashTable.hpp b/src/hotspot/share/utilities/concurrentHashTable.hpp index 48166b22126..a837a56a19a 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.hpp @@ -451,8 +451,7 @@ class ConcurrentHashTable : public CHeapObj { // All callbacks for get are under critical sections. Other callbacks may be // under critical section or may have locked parts of table. Calling any - // methods on the table during a callback is not supported.Only MultiGetHandle - // supports multiple gets. + // methods on the table during a callback is not supported. // Get methods return true on found item with LOOKUP_FUNC and FOUND_FUNC is // called. @@ -538,18 +537,6 @@ class ConcurrentHashTable : public CHeapObj { // Must be done at a safepoint. void rehash_nodes_to(Thread* thread, ConcurrentHashTable* to_cht); - // Scoped multi getter. - class MultiGetHandle : private ScopedCS { - public: - MultiGetHandle(Thread* thread, ConcurrentHashTable* cht) - : ScopedCS(thread, cht) {} - // In the MultiGetHandle scope you can lookup items matching LOOKUP_FUNC. - // The VALUEs are safe as long as you never save the VALUEs outside the - // scope, e.g. after ~MultiGetHandle(). - template - VALUE* get(LOOKUP_FUNC& lookup_f, bool* grow_hint = nullptr); - }; - private: class BucketsOperation; diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 908405d3617..eeaff0167b2 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -233,14 +233,6 @@ inline ConcurrentHashTable:: GlobalCounter::critical_section_end(_thread, _cs_context); } -template -template -inline typename CONFIG::Value* ConcurrentHashTable:: - MultiGetHandle::get(LOOKUP_FUNC& lookup_f, bool* grow_hint) -{ - return ScopedCS::_cht->internal_get(ScopedCS::_thread, lookup_f, grow_hint); -} - // HaveDeletables template template diff --git a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp index 927b5ff3d42..775f0e17409 100644 --- a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp +++ b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp @@ -97,7 +97,6 @@ struct Config : public AllStatic { }; typedef ConcurrentHashTable SimpleTestTable; -typedef ConcurrentHashTable::MultiGetHandle SimpleTestGetHandle; typedef ConcurrentHashTable CustomTestTable; struct SimpleTestLookup { @@ -345,10 +344,6 @@ static void cht_scope(Thread* thr) { SimpleTestLookup stl(val); SimpleTestTable* cht = new SimpleTestTable(); EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed."; - { - SimpleTestGetHandle get_handle(thr, cht); - EXPECT_EQ(*get_handle.get(stl), val) << "Getting a pre-existing value failed."; - } // We do remove here to make sure the value-handle 'unlocked' the table when leaving the scope. EXPECT_TRUE(cht->remove(thr, stl)) << "Removing a pre-existing value failed."; EXPECT_FALSE(cht_get_copy(cht, thr, stl) == val) << "Got a removed value."; @@ -556,7 +551,6 @@ public: }; typedef ConcurrentHashTable TestTable; -typedef ConcurrentHashTable::MultiGetHandle TestGetHandle; struct TestLookup { uintptr_t _val; @@ -788,15 +782,8 @@ public: bool test_loop() { for (uintptr_t v = 0x1; v < 0xFFF; v++ ) { uintptr_t tv; - if (v & 0x1) { - TestLookup tl(v); - tv = cht_get_copy(_cht, this, tl); - } else { - TestLookup tl(v); - TestGetHandle value_handle(this, _cht); - uintptr_t* tmp = value_handle.get(tl); - tv = tmp != nullptr ? *tmp : 0; - } + TestLookup tl(v); + tv = cht_get_copy(_cht, this, tl); EXPECT_TRUE(tv == 0 || tv == v) << "Got unknown value."; } return true; From c0636734bdf19de6ba41c127aef1f090010c6d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Wed, 3 Dec 2025 14:34:05 +0000 Subject: [PATCH 021/141] 8372993: Serial: max_eden_size is too small after JDK-8368740 Reviewed-by: ayang, aboldtch, stefank --- src/hotspot/share/gc/serial/defNewGeneration.cpp | 5 ++++- .../jtreg/gc/arguments/TestNewSizeFlags.java | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 0b2ba44c780..9ccc7b95529 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -236,7 +236,10 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs, // These values are exported as performance counters. uintx size = _virtual_space.reserved_size(); _max_survivor_size = compute_survivor_size(size, SpaceAlignment); - _max_eden_size = size - (2*_max_survivor_size); + + // Eden might grow to be almost as large as the entire young generation. + // We approximate this as the entire virtual space. + _max_eden_size = size; // allocate the performance counters diff --git a/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java b/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java index 2f454940863..f65f211b812 100644 --- a/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java +++ b/test/hotspot/jtreg/gc/arguments/TestNewSizeFlags.java @@ -286,6 +286,20 @@ public class TestNewSizeFlags { if (YOUNG_GC_TYPE == GCTypes.YoungGCType.G1) { return new MemoryUsage(edenUsageInit + survivorUsageInit, 0, edenUsageCommited + survivorUsageCommited, Long.MAX_VALUE); + } else if (YOUNG_GC_TYPE == GCTypes.YoungGCType.DefNew) { + // Eden might grow to be almost the entire young generation, + // so it is approximated as the size for the entire young + // generation. + long youngGenUsageMax = edenUsage.getMax(); + + long combinedSurvivorUsageMax = 2 * survivorUsage.getMax(); + if (combinedSurvivorUsageMax > youngGenUsageMax) { + throw new RuntimeException("Unexpectedly large survivorUsage combined maximum value: " + combinedSurvivorUsageMax); + } + + return new MemoryUsage(edenUsageInit + survivorUsageInit * 2, 0, + edenUsageCommited + survivorUsageCommited * 2, + youngGenUsageMax); } else { return new MemoryUsage(edenUsageInit + survivorUsageInit * 2, 0, edenUsageCommited + survivorUsageCommited * 2, From 44e2d499f84458003aa73a149d1ae44735b71d91 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Wed, 3 Dec 2025 14:38:32 +0000 Subject: [PATCH 022/141] 8372705: The riscv-64 cross-compilation build is failing in the CI Reviewed-by: dholmes, shade --- make/autoconf/flags-ldflags.m4 | 16 +++++++++------- make/autoconf/toolchain.m4 | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 18ec04d92b7..b0dc565b39f 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -34,7 +34,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS], FLAGS_SETUP_LDFLAGS_CPU_DEP([TARGET]) # Setup the build toolchain - FLAGS_SETUP_LDFLAGS_CPU_DEP([BUILD], [OPENJDK_BUILD_]) + FLAGS_SETUP_LDFLAGS_CPU_DEP([BUILD], [OPENJDK_BUILD_], [BUILD_]) AC_SUBST(ADLC_LDFLAGS) ]) @@ -52,11 +52,6 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], # add --no-as-needed to disable default --as-needed link flag on some GCC toolchains # add --icf=all (Identical Code Folding — merges identical functions) BASIC_LDFLAGS="-Wl,-z,defs -Wl,-z,relro -Wl,-z,now -Wl,--no-as-needed -Wl,--exclude-libs,ALL" - if test "x$LINKER_TYPE" = "xgold"; then - if test x$DEBUG_LEVEL = xrelease; then - BASIC_LDFLAGS="$BASIC_LDFLAGS -Wl,--icf=all" - fi - fi # Linux : remove unused code+data in link step if test "x$ENABLE_LINKTIME_GC" = xtrue; then @@ -169,7 +164,8 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], ################################################################################ # $1 - Either BUILD or TARGET to pick the correct OS/CPU variables to check # conditionals against. -# $2 - Optional prefix for each variable defined. +# $2 - Optional prefix for each variable defined (OPENJDK_BUILD_ or nothing). +# $3 - Optional prefix for toolchain variables (BUILD_ or nothing). AC_DEFUN([FLAGS_SETUP_LDFLAGS_CPU_DEP], [ # Setup CPU-dependent basic LDFLAGS. These can differ between the target and @@ -203,6 +199,12 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_CPU_DEP], fi fi + if test "x${$3LD_TYPE}" = "xgold"; then + if test x$DEBUG_LEVEL = xrelease; then + $1_CPU_LDFLAGS="${$1_CPU_LDFLAGS} -Wl,--icf=all" + fi + fi + # Export variables according to old definitions, prefix with $2 if present. LDFLAGS_JDK_COMMON="$BASIC_LDFLAGS $BASIC_LDFLAGS_JDK_ONLY \ $OS_LDFLAGS $DEBUGLEVEL_LDFLAGS_JDK_ONLY ${$2EXTRA_LDFLAGS}" diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 15210efe4a7..c882deb10a7 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -516,7 +516,7 @@ AC_DEFUN([TOOLCHAIN_EXTRACT_LD_VERSION], if [ [[ "$LINKER_VERSION_STRING" == *gold* ]] ]; then [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*) .*/\1/'` ] - LINKER_TYPE=gold + $1_TYPE=gold else [ LINKER_VERSION_NUMBER=`$ECHO $LINKER_VERSION_STRING | \ $SED -e 's/.* \([0-9][0-9]*\(\.[0-9][0-9]*\)*\).*/\1/'` ] From 87c4b01ea3d94c25d260f0687addf7ecd154279a Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Wed, 3 Dec 2025 14:38:53 +0000 Subject: [PATCH 023/141] 8372943: Restore --with-tools-dir Reviewed-by: mikael, tbell, shade --- make/autoconf/basic.m4 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/make/autoconf/basic.m4 b/make/autoconf/basic.m4 index 316bfc5037d..bb6908d9194 100644 --- a/make/autoconf/basic.m4 +++ b/make/autoconf/basic.m4 @@ -353,7 +353,12 @@ AC_DEFUN_ONCE([BASIC_SETUP_DEVKIT], [set up toolchain on Mac OS using a path to an Xcode installation])]) UTIL_DEPRECATED_ARG_WITH(sys-root) - UTIL_DEPRECATED_ARG_WITH(tools-dir) + + AC_ARG_WITH([tools-dir], [AS_HELP_STRING([--with-tools-dir], + [Point to a nonstandard Visual Studio installation location on Windows by + specifying any existing directory 2 or 3 levels below the installation + root.])] + ) if test "x$with_xcode_path" != x; then if test "x$OPENJDK_BUILD_OS" = "xmacosx"; then From 829b85813a3810eeecf6ce4b30b5c3d1fc34ad23 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Wed, 3 Dec 2025 14:53:35 +0000 Subject: [PATCH 024/141] 8372703: Test compiler/arguments/TestCodeEntryAlignment.java failed: assert(allocates2(pc)) failed: not in CodeBuffer memory Reviewed-by: mhaessig, dfenacci, thartmann --- src/hotspot/cpu/x86/stubDeclarations_x86.hpp | 2 +- test/hotspot/jtreg/ProblemList.txt | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp index 3e0e1d5bf07..971c8fd3c44 100644 --- a/src/hotspot/cpu/x86/stubDeclarations_x86.hpp +++ b/src/hotspot/cpu/x86/stubDeclarations_x86.hpp @@ -73,7 +73,7 @@ do_arch_blob, \ do_arch_entry, \ do_arch_entry_init) \ - do_arch_blob(compiler, 109000 WINDOWS_ONLY(+2000)) \ + do_arch_blob(compiler, 120000 WINDOWS_ONLY(+2000)) \ do_stub(compiler, vector_float_sign_mask) \ do_arch_entry(x86, compiler, vector_float_sign_mask, \ vector_float_sign_mask, vector_float_sign_mask) \ diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index f379f57a8e5..177c14da785 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -78,8 +78,6 @@ compiler/c2/aarch64/TestStaticCallStub.java 8359963 linux-aarch64,macosx-aarch64 serviceability/jvmti/NMethodRelocation/NMethodRelocationTest.java 8369150 generic-all -compiler/arguments/TestCodeEntryAlignment.java 8372703 generic-x64 - ############################################################################# # :hotspot_gc From 1d753f116135cffa3ec9e8b4af3922aa647317dc Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Wed, 3 Dec 2025 15:14:57 +0000 Subject: [PATCH 025/141] 8373010: Update starting-next-release.html after JDK-8372940 Reviewed-by: jpai, erikj --- doc/starting-next-release.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/starting-next-release.html b/doc/starting-next-release.html index 6cffdf38b0f..bbb48e243ad 100644 --- a/doc/starting-next-release.html +++ b/doc/starting-next-release.html @@ -119,6 +119,9 @@ cover the new source version and test/langtools/tools/javac/preview/classReaderTest/Client.preview.out: update expected messages for preview errors and warnings +

  • test/langtools/tools/javac/versions/Versions.java: add +new source version to the set of valid sources and add new enum constant +for the new class file version.
  • From 3d54a802e38f425c7035c947758c887fec48e43a Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Wed, 3 Dec 2025 15:21:11 +0000 Subject: [PATCH 026/141] 8372995: SerialGC: Allow SerialHeap::allocate_loaded_archive_space expand old_gen Reviewed-by: ayang, jsikstro --- src/hotspot/share/gc/serial/serialHeap.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index faef3b89125..932c06b8109 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -147,7 +147,8 @@ GrowableArray SerialHeap::memory_pools() { HeapWord* SerialHeap::allocate_loaded_archive_space(size_t word_size) { MutexLocker ml(Heap_lock); - return old_gen()->allocate(word_size); + HeapWord* const addr = old_gen()->allocate(word_size); + return addr != nullptr ? addr : old_gen()->expand_and_allocate(word_size); } void SerialHeap::complete_loaded_archive_space(MemRegion archive_space) { From 6d5bf9c801bbec3cd3580f889cc92415021f7322 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 3 Dec 2025 15:30:14 +0000 Subject: [PATCH 027/141] 8372999: Parallel: Old generation min size constraint broken Reviewed-by: stefank, jsikstro --- .../share/gc/parallel/parallelScavengeHeap.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 4d291120e4a..9df3deedf89 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -891,9 +891,23 @@ void ParallelScavengeHeap::resize_after_young_gc(bool is_survivor_overflowing) { // Consider if should shrink old-gen if (!is_survivor_overflowing) { - // Upper bound for a single step shrink - size_t max_shrink_bytes = SpaceAlignment; + assert(old_gen()->capacity_in_bytes() >= old_gen()->min_gen_size(), "inv"); + + // Old gen min_gen_size constraint. + const size_t max_shrink_bytes_gen_size_constraint = old_gen()->capacity_in_bytes() - old_gen()->min_gen_size(); + + // Per-step delta to avoid too aggressive shrinking. + const size_t max_shrink_bytes_per_step_constraint = SpaceAlignment; + + // Combining the above two constraints. + const size_t max_shrink_bytes = MIN2(max_shrink_bytes_gen_size_constraint, + max_shrink_bytes_per_step_constraint); + size_t shrink_bytes = _size_policy->compute_old_gen_shrink_bytes(old_gen()->free_in_bytes(), max_shrink_bytes); + + assert(old_gen()->capacity_in_bytes() >= shrink_bytes, "inv"); + assert(old_gen()->capacity_in_bytes() - shrink_bytes >= old_gen()->min_gen_size(), "inv"); + if (shrink_bytes != 0) { if (MinHeapFreeRatio != 0) { size_t new_capacity = old_gen()->capacity_in_bytes() - shrink_bytes; From af8977e40661db2edec069d524f7c9352c7de850 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 3 Dec 2025 15:32:46 +0000 Subject: [PATCH 028/141] 8372951: The property jdk.httpclient.quic.maxBidiStreams should be renamed to jdk.internal 8365794: StreamLimitTest vs H3StreamLimitReachedTest: consider renaming or merging Reviewed-by: jpai --- .../net/http/quic/QuicConnectionImpl.java | 14 ++++++- .../H3MultipleConnectionsToSameHost.java | 10 ++--- .../http3/H3StreamLimitReachedTest.java | 42 +++++++++++++++++-- .../net/httpclient/http3/StreamLimitTest.java | 5 ++- 4 files changed, 61 insertions(+), 10 deletions(-) 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 240f90852bc..c07df1c6eb2 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 @@ -174,17 +174,29 @@ public class QuicConnectionImpl extends QuicConnection implements QuicPacketRece public static final int SMALLEST_MAXIMUM_DATAGRAM_SIZE = QuicClient.SMALLEST_MAXIMUM_DATAGRAM_SIZE; + // The default value for the Quic maxInitialTimeout, in seconds. Will be clamped to [1, Integer.MAX_vALUE] public static final int DEFAULT_MAX_INITIAL_TIMEOUT = Math.clamp( Utils.getIntegerProperty("jdk.httpclient.quic.maxInitialTimeout", 30), 1, Integer.MAX_VALUE); + // The default value for the initial_max_data transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final long DEFAULT_INITIAL_MAX_DATA = Math.clamp( Utils.getLongProperty("jdk.httpclient.quic.maxInitialData", 15 << 20), 0, 1L << 60); + // The default value for the initial_max_stream_data_bidi_local, initial_max_stream_data_bidi_remote, + // and initial_max_stream_data_uni transport parameters that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final long DEFAULT_INITIAL_STREAM_MAX_DATA = Math.clamp( Utils.getIntegerProperty("jdk.httpclient.quic.maxStreamInitialData", 6 << 20), 0, 1L << 60); + // The default value for the initial_max_streams_bidi transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. + // The Http3ClientImpl typically provides a value of 0, so this property has no effect + // on QuicConnectionImpl instances created on behalf of the HTTP/3 client public static final int DEFAULT_MAX_BIDI_STREAMS = - Utils.getIntegerProperty("jdk.httpclient.quic.maxBidiStreams", 100); + Utils.getIntegerProperty("jdk.internal.httpclient.quic.maxBidiStreams", 100); + // The default value for the initial_max_streams_uni transport parameter that a QuicConnectionImpl + // will send to its peer, if no value is provided by the higher level protocol. public static final int DEFAULT_MAX_UNI_STREAMS = Utils.getIntegerProperty("jdk.httpclient.quic.maxUniStreams", 100); public static final boolean USE_DIRECT_BUFFER_POOL = Utils.getBooleanProperty( diff --git a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java index 862ccf22ddc..2e4047cf5ea 100644 --- a/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java +++ b/test/jdk/java/net/httpclient/http3/H3MultipleConnectionsToSameHost.java @@ -37,7 +37,7 @@ * -Djdk.internal.httpclient.quic.poller.usePlatformThreads=false * -Djdk.httpclient.quic.maxEndpoints=-1 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:retransmit * -Dsimpleget.requests=100 @@ -61,7 +61,7 @@ * -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations * -Djdk.httpclient.quic.maxEndpoints=-1 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:retransmit * -Dsimpleget.requests=100 @@ -85,7 +85,7 @@ * -Djdk.internal.httpclient.quic.useNioSelector=true * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 * -Djdk.httpclient.quic.maxEndpoints=1 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:hs:retransmit * -Dsimpleget.requests=100 @@ -109,7 +109,7 @@ * -Djdk.httpclient.quic.maxPtoBackoff=9 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 * -Djdk.httpclient.quic.maxEndpoints=1 - * -Djdk.httpclient.quic.maxBidiStreams=2 + * -Djdk.internal.httpclient.quic.maxBidiStreams=2 * -Djdk.httpclient.retryOnStreamlimit=50 * -Djdk.httpclient.HttpClient.log=errors,http3,quic:hs:retransmit * -Dsimpleget.requests=100 @@ -239,7 +239,7 @@ public class H3MultipleConnectionsToSameHost implements HttpServerAdapters { long done = System.nanoTime(); System.out.println("Initialization and warmup took "+ TimeUnit.NANOSECONDS.toMillis(done-prestart)+" millis"); // Thread.sleep(30000); - int maxBidiStreams = Utils.getIntegerNetProperty("jdk.httpclient.quic.maxBidiStreams", 100); + int maxBidiStreams = Utils.getIntegerNetProperty("jdk.internal.httpclient.quic.maxBidiStreams", 100); long timeout = MAX_STREAM_LIMIT_WAIT_TIMEOUT; Set connections = new ConcurrentSkipListSet<>(); diff --git a/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java b/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java index 916a6a5221d..0de80c6d587 100644 --- a/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java +++ b/test/jdk/java/net/httpclient/http3/H3StreamLimitReachedTest.java @@ -23,6 +23,24 @@ /* * @test id=with-default-wait + * @summary this test verifies that the correct connection is + * used when a request is retried on a new connection + * due to stream limit reached. + * The maxBidiStreams limit is artificially set to 1. + * This configuration uses the default wait for a stream + * to become available before retrying. + * Different configurations are tested if possible, + * with both HTTP/3 only and HTTP/2 HTTP/3 with altsvc. + * In one case the HTTP/3 only server will be listening + * on the same port as the HTTP/2 server, with the + * HTTP/2 server advertising an AltService on a different + * port. In another case the AltService will be on the + * same port as the HTTP/2 server and the HTTP/3 server + * will be on a different port. In all case, the test + * verifies that the right connection is picked up + * for the retry. + * @bug 8372951 + * @comment this test also tests bug 8372951 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.Asserts @@ -30,12 +48,30 @@ * jdk.test.lib.net.SimpleSSLContext * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors,http3,quic:control * -Djdk.internal.httpclient.debug=false - * -Djdk.httpclient.quic.maxBidiStreams=1 + * -Djdk.internal.httpclient.quic.maxBidiStreams=1 * H3StreamLimitReachedTest */ /* * @test id=with-no-wait + * @summary this test verifies that the correct connection is + * used when a request is retried on a new connection + * due to stream limit reached. + * The maxBidiStreams limit is artificially set to 1. + * This configuration retries immediately on a new + * connection when no stream is available. + * Different configurations are tested if possible, + * with both HTTP/3 only and HTTP/2 HTTP/3 with altsvc. + * In one case the HTTP/3 only server will be listening + * on the same port as the HTTP/2 server, with the + * HTTP/2 server advertising an AltService on a different + * port. In another case the AltService will be on the + * same port as the HTTP/2 server and the HTTP/3 server + * will be on a different port. In all case, the test + * verifies that the right connection is picked up + * for the retry. + * @bug 8372951 + * @comment this test also tests bug 8372951 * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.httpclient.test.lib.http2.Http2TestServer * jdk.test.lib.Asserts @@ -43,7 +79,7 @@ * jdk.test.lib.net.SimpleSSLContext * @run testng/othervm -Djdk.httpclient.HttpClient.log=ssl,requests,responses,errors,http3,quic:control * -Djdk.internal.httpclient.debug=false - * -Djdk.httpclient.quic.maxBidiStreams=1 + * -Djdk.internal.httpclient.quic.maxBidiStreams=1 * -Djdk.httpclient.http3.maxStreamLimitTimeout=0 * -Djdk.httpclient.retryOnStreamlimit=9 * H3StreamLimitReachedTest @@ -93,7 +129,7 @@ import static org.testng.Assert.assertFalse; public class H3StreamLimitReachedTest implements HttpServerAdapters { - private static final String CLASS_NAME = H3ConnectionPoolTest.class.getSimpleName(); + private static final String CLASS_NAME = H3StreamLimitReachedTest.class.getSimpleName(); static int altsvcPort, https2Port, http3Port; static Http3TestServer http3OnlyServer; diff --git a/test/jdk/java/net/httpclient/http3/StreamLimitTest.java b/test/jdk/java/net/httpclient/http3/StreamLimitTest.java index d8a920c8544..105417950a1 100644 --- a/test/jdk/java/net/httpclient/http3/StreamLimitTest.java +++ b/test/jdk/java/net/httpclient/http3/StreamLimitTest.java @@ -56,7 +56,10 @@ import static java.net.http.HttpOption.H3_DISCOVERY; /* * @test * @summary verifies that when the Quic stream limit is reached - * then HTTP3 requests are retried on newer connection + * then HTTP3 requests are retried on newer connection. + * This test uses an HTTP/3 only test server, which is + * configured to allow the test to control when a new + * MAX_STREAMS frames is sent to the client. * @library /test/lib /test/jdk/java/net/httpclient/lib * @build jdk.test.lib.net.SimpleSSLContext * jdk.httpclient.test.lib.common.HttpServerAdapters From c4321503976840f6630567c4fa430cd1ffca41fb Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 3 Dec 2025 16:37:10 +0000 Subject: [PATCH 029/141] 8372809: Test vmTestbase/nsk/jdi/ThreadReference/isSuspended/issuspended001/TestDescription.java failed: JVMTI_ERROR_THREAD_NOT_ALIVE Reviewed-by: amenkov, sspitsyn --- .../share/native/libjdwp/threadControl.c | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 491182a583f..39407133889 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -157,11 +157,20 @@ setThreadLocalStorage(jthread thread, ThreadNode *node) error = JVMTI_FUNC_PTR(gdata->jvmti,SetThreadLocalStorage) (gdata->jvmti, thread, (void*)node); - if ( error == JVMTI_ERROR_THREAD_NOT_ALIVE && node == NULL) { - /* Just return. This can happen when clearing the TLS. */ - return; - } else if ( error != JVMTI_ERROR_NONE ) { - /* The jthread object must be valid, so this must be a fatal error */ + if (error == JVMTI_ERROR_THREAD_NOT_ALIVE) { + if (node == NULL) { + // Just return. This can happen when clearing the TLS. + return; + } + if (isVThread(thread)) { + // Just return. This can happen with a vthread that is running and we + // had to create a ThreadNode for it. By the time we get here, it may + // have already terminated. + return; + } + } + if (error != JVMTI_ERROR_NONE) { + // The jthread object must be valid, so this must be a fatal error. EXIT_ERROR(error, "cannot set thread local storage"); } } @@ -251,9 +260,10 @@ findThread(ThreadList *list, jthread thread) * Otherwise the thread should not be on the runningThreads. */ if ( !gdata->jvmtiCallBacksCleared ) { - /* The thread better not be on either list if the TLS lookup failed. */ + // The thread better not be on the runningThreads list if the TLS lookup failed. + // It might be on the runningVThreads list because of how ThreadNodes for vthreads + // can be recreated just before terminating, so we don't check runningVThreads. JDI_ASSERT(!nonTlsSearch(getEnv(), &runningThreads, thread)); - JDI_ASSERT(!nonTlsSearch(getEnv(), &runningVThreads, thread)); } else { /* * Search the runningThreads and runningVThreads lists. The TLS lookup may have From 0bcef61a6de027c1b7e481e2115016ee961707a5 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 3 Dec 2025 17:15:37 +0000 Subject: [PATCH 030/141] 8372957: After JDK-8282441 JDWP might allow some invalid FrameIDs to be used Reviewed-by: amenkov, sspitsyn --- src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 39407133889..734dd5eb7dc 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -70,6 +70,7 @@ typedef struct ThreadNode { unsigned int popFrameEvent : 1; unsigned int popFrameProceed : 1; unsigned int popFrameThread : 1; + unsigned int frameGeneration_accessed:1; /* true if frameGeneration accessed to produce a FrameID */ EventIndex current_ei; /* Used to determine if we are currently handling an event on this thread. */ jobject pendingStop; /* Object we are throwing to stop the thread (ThreadReferenceImpl.stop). */ jint suspendCount; /* Number of outstanding suspends from the debugger. */ @@ -616,6 +617,7 @@ freeUnusedVThreadNode(JNIEnv *env, ThreadNode* node) !node->popFrameEvent && !node->popFrameProceed && !node->popFrameThread && + !node->frameGeneration_accessed && node->pendingStop == NULL) { removeNode(node); @@ -2683,6 +2685,7 @@ threadControl_getFrameGeneration(jthread thread) if (node != NULL) { frameGeneration = node->frameGeneration; + node->frameGeneration_accessed = JNI_TRUE; } } debugMonitorExit(threadLock); From fa6ca0bbd14436cd3778a7a3383183cd73688123 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 3 Dec 2025 17:25:05 +0000 Subject: [PATCH 031/141] 8362428: Update IANA Language Subtag Registry to Version 2025-08-25 Reviewed-by: lancea, naoto, iris --- .../data/lsrdata/language-subtag-registry.txt | 61 +++++++++++++++++-- .../Locale/LanguageSubtagRegistryTest.java | 4 +- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/data/lsrdata/language-subtag-registry.txt b/src/java.base/share/data/lsrdata/language-subtag-registry.txt index 64c40f28162..82618f9b40e 100644 --- a/src/java.base/share/data/lsrdata/language-subtag-registry.txt +++ b/src/java.base/share/data/lsrdata/language-subtag-registry.txt @@ -1,4 +1,4 @@ -File-Date: 2025-05-15 +File-Date: 2025-08-25 %% Type: language Subtag: aa @@ -3102,6 +3102,7 @@ Added: 2009-07-29 Type: language Subtag: asb Description: Assiniboine +Description: Nakoda Assiniboine Added: 2009-07-29 %% Type: language @@ -3269,6 +3270,7 @@ Added: 2009-07-29 Type: language Subtag: atj Description: Atikamekw +Description: Nehirowimowin Added: 2009-07-29 %% Type: language @@ -7981,6 +7983,7 @@ Added: 2009-07-29 Type: language Subtag: clc Description: Chilcotin +Description: Tsilhqot’in Added: 2009-07-29 %% Type: language @@ -8021,6 +8024,7 @@ Added: 2009-07-29 %% Type: language Subtag: clm +Description: Klallam Description: Clallam Added: 2009-07-29 %% @@ -13509,7 +13513,7 @@ Added: 2009-07-29 %% Type: language Subtag: haa -Description: Han +Description: Hän Added: 2009-07-29 %% Type: language @@ -19022,6 +19026,7 @@ Added: 2009-07-29 %% Type: language Subtag: kwk +Description: Kwak'wala Description: Kwakiutl Added: 2009-07-29 %% @@ -22262,7 +22267,7 @@ Added: 2009-07-29 %% Type: language Subtag: mhn -Description: Mócheno +Description: Mòcheno Added: 2009-07-29 %% Type: language @@ -31655,6 +31660,7 @@ Added: 2009-07-29 Type: language Subtag: sec Description: Sechelt +Description: She shashishalhem Added: 2009-07-29 %% Type: language @@ -32003,6 +32009,7 @@ Added: 2009-07-29 Type: language Subtag: shs Description: Shuswap +Description: Secwepemctsín Added: 2009-07-29 %% Type: language @@ -33014,6 +33021,7 @@ Added: 2009-07-29 Type: language Subtag: squ Description: Squamish +Description: Sḵwx̱wú7mesh sníchim Added: 2009-07-29 %% Type: language @@ -34664,6 +34672,8 @@ Added: 2009-07-29 Type: language Subtag: thp Description: Thompson +Description: Nłeʔkepmxcín +Description: Thompson River Salish Added: 2009-07-29 %% Type: language @@ -34684,6 +34694,7 @@ Added: 2009-07-29 Type: language Subtag: tht Description: Tahltan +Description: Tāłtān Added: 2009-07-29 %% Type: language @@ -42419,7 +42430,7 @@ Added: 2009-07-29 %% Type: language Subtag: zmp -Description: Mpuono +Description: Mbuun Added: 2009-07-29 %% Type: language @@ -47639,6 +47650,12 @@ Comments: Denotes conventions established by the Academia Brasileira de Letras in 1943 and generally used in Brazil until 2009 %% Type: variant +Subtag: akhmimic +Description: Akhmimic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: akuapem Description: Akuapem Twi Added: 2017-06-05 @@ -47814,6 +47831,12 @@ Comments: Black American Sign Language (BASL) or Black Sign Variation (BSV) is a dialect of American Sign Language (ASL) %% Type: variant +Subtag: bohairic +Description: Bohairic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: bohoric Description: Slovene in Bohorič alphabet Added: 2012-06-27 @@ -47898,6 +47921,12 @@ Comments: Represents the standard written form of Ladin in Fascia which unified the three subvarieties Cazet, Brach and Moenat %% Type: variant +Subtag: fayyumic +Description: Fayyumic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: fodom Description: Fodom standard of Ladin Added: 2024-03-04 @@ -48167,6 +48196,12 @@ Comments: Russian orthography as established by the 1917/1918 orthographic reforms %% Type: variant +Subtag: lycopol +Description: Lycopolitan alias Subakhmimic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: mdcegyp Description: Ancient Egyptian hieroglyphs encoded in Manuel de Codage Added: 2025-02-06 @@ -48180,6 +48215,12 @@ Added: 2025-02-06 Prefix: egy %% Type: variant +Subtag: mesokem +Description: Mesokemic alias Oxyrhynchite dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: metelko Description: Slovene in Metelko alphabet Added: 2012-06-27 @@ -48367,6 +48408,12 @@ Prefix: rm Comments: Supraregional Romansh written standard %% Type: variant +Subtag: sahidic +Description: Sahidic dialect of Coptic +Added: 2025-07-14 +Prefix: cop +%% +Type: variant Subtag: saigon Description: The Sài Gòn variant of Vietnamese Added: 2025-03-10 @@ -48555,6 +48602,12 @@ Comments: The subtag represents the old orthography of the Latvian language used during c. 1600s–1920s. %% Type: variant +Subtag: viennese +Description: The Viennese dialect of German +Added: 2025-06-22 +Prefix: de +%% +Type: variant Subtag: vivaraup Description: Vivaro-Alpine Added: 2018-04-22 diff --git a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java index 12f5a96d3fb..07cc7a412b6 100644 --- a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java +++ b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java @@ -25,9 +25,9 @@ * @test * @bug 8025703 8040211 8191404 8203872 8222980 8225435 8241082 8242010 8247432 * 8258795 8267038 8287180 8302512 8304761 8306031 8308021 8313702 8318322 - * 8327631 8332424 8334418 8344589 8348328 + * 8327631 8332424 8334418 8344589 8348328 8362428 * @summary Checks the IANA language subtag registry data update - * (LSR Revision: 2025-05-15) with Locale and Locale.LanguageRange + * (LSR Revision: 2025-08-25) with Locale and Locale.LanguageRange * class methods. * @run main LanguageSubtagRegistryTest */ From 8d80778e05aee878f9a3e8beabe6a0cfd0a02c16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Wed, 3 Dec 2025 18:02:06 +0000 Subject: [PATCH 032/141] 8373023: [REDO] Remove the default value of InitialRAMPercentage Reviewed-by: stefank, sjohanss, aboldtch --- src/hotspot/share/gc/shared/gc_globals.hpp | 2 +- src/hotspot/share/runtime/flags/jvmFlag.cpp | 2 +- src/java.base/share/man/java.md | 3 +-- test/hotspot/jtreg/ProblemList.txt | 10 ++++++++++ test/jdk/ProblemList.txt | 1 + 5 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index e86a8744847..d08e95378f7 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -291,7 +291,7 @@ "size on systems with small physical memory size") \ range(0.0, 100.0) \ \ - product(double, InitialRAMPercentage, 0.2, \ + product(double, InitialRAMPercentage, 0.0, \ "Percentage of real memory used for initial heap size") \ range(0.0, 100.0) \ \ diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 487528c49bd..51517fa49db 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -162,7 +162,7 @@ void JVMFlag::print_on(outputStream* st, bool withComments, bool printRanges) co // uintx ThresholdTolerance = 10 {product} {default} // size_t TLABSize = 0 {product} {default} // uintx SurvivorRatio = 8 {product} {default} - // double InitialRAMPercentage = 1.562500 {product} {default} + // double InitialRAMPercentage = 0.000000 {product} {default} // ccstr CompileCommandFile = MyFile.cmd {product} {command line} // ccstrlist CompileOnly = Method1 // CompileOnly += Method2 {product} {command line} diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 462baa5a4a0..8517e161e3f 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2455,8 +2455,7 @@ Java HotSpot VM. `-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. The default value is - 0.2 percent. + determined as described in the `-XX:MaxRAM` option. The following example shows how to set the percentage of the initial amount of memory used for the Java heap: diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 177c14da785..6c3d907961d 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -94,6 +94,7 @@ gc/shenandoah/TestEvilSyncBug.java#generational 8345501 generic-all gc/shenandoah/TestRetainObjects.java#no-tlab 8361099 generic-all gc/shenandoah/TestSieveObjects.java#no-tlab 8361099 generic-all gc/shenandoah/TestSieveObjects.java#no-tlab-genshen 8361099 generic-all +gc/cslocker/TestCSLocker.java 8373025 generic-all ############################################################################# @@ -139,6 +140,9 @@ serviceability/sa/ClhsdbPstack.java#core 8318754 macosx-aarch64 serviceability/sa/TestJmapCore.java 8318754 macosx-aarch64 serviceability/sa/TestJmapCoreMetaspace.java 8318754 macosx-aarch64 +serviceability/sa/ClhsdbScanOops.java#parallel 8373022 generic-all +serviceability/sa/ClhsdbScanOops.java#serial 8373022 generic-all + serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64 serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 @@ -183,3 +187,9 @@ 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 + +vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001/TestDescription.java 8373022 generic-all +vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded002/TestDescription.java 8373022 generic-all +vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded003/TestDescription.java 8373022 generic-all +vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded004/TestDescription.java 8373022 generic-all +vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded005/TestDescription.java 8373022 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1d547faf662..72a248408ac 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -715,6 +715,7 @@ javax/swing/plaf/synth/7158712/bug7158712.java 8324782 macosx-all # jdk_jdi com/sun/jdi/InvokeHangTest.java 8218463 linux-all +com/sun/jdi/MethodInvokeWithTraceOnTest.java 8373022 generic-all ############################################################################ From e93b10d08456f720e303771a882e79660911e1eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Wed, 3 Dec 2025 18:12:58 +0000 Subject: [PATCH 033/141] 8365400: Enhance JFR to emit file and module metadata for class loading Reviewed-by: coleenp, egahlin --- .../share/cds/lambdaProxyClassDictionary.cpp | 6 +- .../share/classfile/classFileParser.cpp | 5 - .../share/classfile/classFileParser.hpp | 2 + src/hotspot/share/classfile/klassFactory.cpp | 7 +- .../share/classfile/systemDictionary.cpp | 51 ++- .../share/classfile/systemDictionary.hpp | 6 +- src/hotspot/share/classfile/vmClasses.cpp | 7 + .../jfrEventClassTransformer.cpp | 2 +- src/hotspot/share/jfr/jfr.cpp | 18 +- src/hotspot/share/jfr/jfr.hpp | 2 + src/hotspot/share/jfr/metadata/metadata.xml | 1 + .../recorder/checkpoint/types/jfrTypeSet.cpp | 5 +- .../checkpoint/types/jfrTypeSetUtils.cpp | 49 +-- .../checkpoint/types/jfrTypeSetUtils.hpp | 18 +- .../types/jfrTypeSetUtils.inline.hpp | 42 ++ .../checkpoint/types/traceid/jfrTraceId.cpp | 1 + .../share/jfr/recorder/jfrRecorder.cpp | 9 + .../share/jfr/recorder/jfrRecorder.hpp | 1 + .../recorder/service/jfrRecorderService.cpp | 3 + .../share/jfr/support/jfrClassDefineEvent.cpp | 188 ++++++++ .../share/jfr/support/jfrClassDefineEvent.hpp | 40 ++ .../share/jfr/support/jfrKlassExtension.hpp | 1 - .../share/jfr/support/jfrSymbolTable.cpp | 406 +++++++++++------- .../share/jfr/support/jfrSymbolTable.hpp | 179 ++++---- .../jfr/support/jfrSymbolTable.inline.hpp | 72 ++++ .../share/jfr/support/jfrTraceIdExtension.hpp | 1 - .../jfr/utilities/jfrConcurrentHashtable.hpp | 139 ++++++ .../jfrConcurrentHashtable.inline.hpp | 254 +++++++++++ .../share/jfr/utilities/jfrLinkedList.hpp | 5 +- .../jfr/utilities/jfrLinkedList.inline.hpp | 36 +- src/hotspot/share/oops/klass.cpp | 8 +- .../classes/jdk/jfr/internal/query/view.ini | 9 + .../event/runtime/TestClassDefineEvent.java | 2 + 33 files changed, 1224 insertions(+), 351 deletions(-) create mode 100644 src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp create mode 100644 src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp create mode 100644 src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp create mode 100644 src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp create mode 100644 src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp create mode 100644 src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp diff --git a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp index f6da1a34af3..d091067c116 100644 --- a/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp +++ b/src/hotspot/share/cds/lambdaProxyClassDictionary.cpp @@ -357,7 +357,7 @@ InstanceKlass* LambdaProxyClassDictionary::load_and_init_lambda_proxy_class(Inst InstanceKlass* nest_host = caller_ik->nest_host(THREAD); assert(nest_host == shared_nest_host, "mismatched nest host"); - EventClassLoad class_load_start_event; + EventClassLoad class_load_event; // Add to class hierarchy, and do possible deoptimizations. lambda_ik->add_to_hierarchy(THREAD); @@ -368,8 +368,8 @@ InstanceKlass* LambdaProxyClassDictionary::load_and_init_lambda_proxy_class(Inst if (JvmtiExport::should_post_class_load()) { JvmtiExport::post_class_load(THREAD, lambda_ik); } - if (class_load_start_event.should_commit()) { - SystemDictionary::post_class_load_event(&class_load_start_event, lambda_ik, ClassLoaderData::class_loader_data(class_loader())); + if (class_load_event.should_commit()) { + JFR_ONLY(SystemDictionary::post_class_load_event(&class_load_event, lambda_ik, ClassLoaderData::class_loader_data(class_loader()));) } lambda_ik->initialize(CHECK_NULL); diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 68890775051..312accb1df9 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -89,9 +89,6 @@ #if INCLUDE_CDS #include "classfile/systemDictionaryShared.hpp" #endif -#if INCLUDE_JFR -#include "jfr/support/jfrTraceIdExtension.hpp" -#endif // We generally try to create the oops directly when parsing, rather than // allocating temporary data structures and copying the bytes twice. A @@ -5272,8 +5269,6 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, } } - JFR_ONLY(INIT_ID(ik);) - // If we reach here, all is well. // Now remove the InstanceKlass* from the _klass_to_deallocate field // in order for it to not be destroyed in the ClassFileParser destructor. diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index 5d4236132f1..48cdacedc1e 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -500,6 +500,8 @@ class ClassFileParser { InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, const ClassInstanceInfo& cl_inst_info, TRAPS); + const ClassFileStream& stream() const { return *_stream; } + const ClassFileStream* clone_stream() const; void set_klass_to_deallocate(InstanceKlass* klass); diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp index 50d327d7e8c..4e599feb3ff 100644 --- a/src/hotspot/share/classfile/klassFactory.cpp +++ b/src/hotspot/share/classfile/klassFactory.cpp @@ -37,7 +37,7 @@ #include "runtime/handles.inline.hpp" #include "utilities/macros.hpp" #if INCLUDE_JFR -#include "jfr/support/jfrKlassExtension.hpp" +#include "jfr/jfr.hpp" #endif @@ -99,6 +99,9 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook( new_ik->set_classpath_index(path_index); } + + JFR_ONLY(Jfr::on_klass_creation(new_ik, parser, THREAD);) + return new_ik; } } @@ -213,7 +216,7 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream, result->set_cached_class_file(cached_class_file); } - JFR_ONLY(ON_KLASS_CREATION(result, parser, THREAD);) + JFR_ONLY(Jfr::on_klass_creation(result, parser, THREAD);) #if INCLUDE_CDS if (CDSConfig::is_dumping_archive()) { diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index a17e7e129ce..ac57293687c 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -560,15 +560,6 @@ static InstanceKlass* handle_parallel_loading(JavaThread* current, return nullptr; } -void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { - assert(event != nullptr, "invariant"); - assert(k != nullptr, "invariant"); - event->set_loadedClass(k); - event->set_definingClassLoader(k->class_loader_data()); - event->set_initiatingClassLoader(init_cld); - event->commit(); -} - // SystemDictionary::resolve_instance_class_or_null is the main function for class name resolution. // After checking if the InstanceKlass already exists, it checks for ClassCircularityError and // whether the thread must wait for loading in parallel. It eventually calls load_instance_class, @@ -582,7 +573,7 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, assert(name != nullptr && !Signature::is_array(name) && !Signature::has_envelope(name), "invalid class name: %s", name == nullptr ? "nullptr" : name->as_C_string()); - EventClassLoad class_load_start_event; + EventClassLoad class_load_event; HandleMark hm(THREAD); @@ -713,8 +704,8 @@ InstanceKlass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, return nullptr; } - if (class_load_start_event.should_commit()) { - post_class_load_event(&class_load_start_event, loaded_class, loader_data); + if (class_load_event.should_commit()) { + JFR_ONLY(post_class_load_event(&class_load_event, loaded_class, loader_data);) } // Make sure we have the right class in the dictionary @@ -789,7 +780,7 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream( const ClassLoadInfo& cl_info, TRAPS) { - EventClassLoad class_load_start_event; + EventClassLoad class_load_event; ClassLoaderData* loader_data; // - for hidden classes that are not strong: create a new CLD that has a class holder and @@ -819,15 +810,16 @@ InstanceKlass* SystemDictionary::resolve_hidden_class_from_stream( k->add_to_hierarchy(THREAD); // But, do not add to dictionary. + if (class_load_event.should_commit()) { + JFR_ONLY(post_class_load_event(&class_load_event, k, loader_data);) + } + k->link_class(CHECK_NULL); // notify jvmti if (JvmtiExport::should_post_class_load()) { JvmtiExport::post_class_load(THREAD, k); } - if (class_load_start_event.should_commit()) { - post_class_load_event(&class_load_start_event, k, loader_data); - } return k; } @@ -1154,6 +1146,17 @@ void SystemDictionary::load_shared_class_misc(InstanceKlass* ik, ClassLoaderData } } +#if INCLUDE_JFR +void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { + assert(event != nullptr, "invariant"); + assert(k != nullptr, "invariant"); + event->set_loadedClass(k); + event->set_definingClassLoader(k->class_loader_data()); + event->set_initiatingClassLoader(init_cld); + event->commit(); +} +#endif // INCLUDE_JFR + // This is much more lightweight than SystemDictionary::resolve_or_null // - There's only a single Java thread at this point. No need for placeholder. // - All supertypes of ik have been loaded @@ -1182,6 +1185,8 @@ void SystemDictionary::preload_class(Handle class_loader, InstanceKlass* ik, TRA } #endif + EventClassLoad class_load_event; + ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader()); oop java_mirror = ik->archived_java_mirror(); precond(java_mirror != nullptr); @@ -1203,6 +1208,10 @@ void SystemDictionary::preload_class(Handle class_loader, InstanceKlass* ik, TRA update_dictionary(THREAD, ik, loader_data); } + if (class_load_event.should_commit()) { + JFR_ONLY(post_class_load_event(&class_load_event, ik, loader_data);) + } + assert(ik->is_loaded(), "Must be in at least loaded state"); } @@ -1380,15 +1389,6 @@ InstanceKlass* SystemDictionary::load_instance_class(Symbol* name, return loaded_class; } -static void post_class_define_event(InstanceKlass* k, const ClassLoaderData* def_cld) { - EventClassDefine event; - if (event.should_commit()) { - event.set_definedClass(k); - event.set_definingClassLoader(def_cld); - event.commit(); - } -} - void SystemDictionary::define_instance_class(InstanceKlass* k, Handle class_loader, TRAPS) { ClassLoaderData* loader_data = k->class_loader_data(); @@ -1440,7 +1440,6 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, Handle class_load if (JvmtiExport::should_post_class_load()) { JvmtiExport::post_class_load(THREAD, k); } - post_class_define_event(k, loader_data); } // Support parallel classloading diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index 99cb1d0b5d2..99e13fea61e 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -326,11 +326,10 @@ private: static void restore_archived_method_handle_intrinsics_impl(TRAPS) NOT_CDS_RETURN; protected: - // Used by AOTLinkedClassBulkLoader, LambdaProxyClassDictionary, and SystemDictionaryShared + // Used by AOTLinkedClassBulkLoader, LambdaProxyClassDictionary, VMClasses and SystemDictionaryShared static bool add_loader_constraint(Symbol* name, Klass* klass_being_linked, Handle loader1, Handle loader2); - static void post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld); static InstanceKlass* load_shared_class(InstanceKlass* ik, Handle class_loader, Handle protection_domain, @@ -342,6 +341,9 @@ protected: static InstanceKlass* find_or_define_instance_class(Symbol* class_name, Handle class_loader, InstanceKlass* k, TRAPS); + JFR_ONLY(static void post_class_load_event(EventClassLoad* event, + const InstanceKlass* k, + const ClassLoaderData* init_cld);) public: static bool is_system_class_loader(oop class_loader); diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index 0a3d33f4c5b..00d209a05ca 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -35,6 +35,7 @@ #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" #include "gc/shared/collectedHeap.hpp" +#include "jfr/jfrEvents.hpp" #include "memory/metaspaceClosure.hpp" #include "memory/universe.hpp" #include "oops/instanceKlass.hpp" @@ -240,6 +241,8 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load return; } + EventClassLoad class_load_event; + // add super and interfaces first InstanceKlass* super = klass->super(); if (super != nullptr && super->class_loader_data() == nullptr) { @@ -261,6 +264,10 @@ void vmClasses::resolve_shared_class(InstanceKlass* klass, ClassLoaderData* load dictionary->add_klass(THREAD, klass->name(), klass); klass->add_to_hierarchy(THREAD); assert(klass->is_loaded(), "Must be in at least loaded state"); + + if (class_load_event.should_commit()) { + JFR_ONLY(SystemDictionary::post_class_load_event(&class_load_event, klass, loader_data);) + } } #endif // INCLUDE_CDS diff --git a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp index d5ef3502fa2..27accac2c00 100644 --- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp +++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp @@ -1427,10 +1427,10 @@ static void transform(InstanceKlass*& ik, ClassFileParser& parser, JavaThread* t } else { JfrClassTransformer::cache_class_file_data(new_ik, stream, thread); } + JfrClassTransformer::copy_traceid(ik, new_ik); if (is_instrumented && JdkJfrEvent::is_subklass(new_ik)) { bless_commit_method(new_ik); } - JfrClassTransformer::copy_traceid(ik, new_ik); JfrClassTransformer::rewrite_klass_pointer(ik, new_ik, parser, thread); } diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 7abf5c89945..3a2465e211d 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -22,6 +22,7 @@ * */ +#include "classfile/classFileParser.hpp" #include "jfr/instrumentation/jfrEventClassTransformer.hpp" #include "jfr/jfr.hpp" #include "jfr/jni/jfrJavaSupport.hpp" @@ -31,6 +32,7 @@ #include "jfr/recorder/repository/jfrEmergencyDump.hpp" #include "jfr/recorder/repository/jfrRepository.hpp" #include "jfr/recorder/service/jfrOptionSet.hpp" +#include "jfr/support/jfrClassDefineEvent.hpp" #include "jfr/support/jfrKlassExtension.hpp" #include "jfr/support/jfrResolution.hpp" #include "jfr/support/jfrThreadLocal.hpp" @@ -78,13 +80,15 @@ void Jfr::on_unloading_classes() { } void Jfr::on_klass_creation(InstanceKlass*& ik, ClassFileParser& parser, TRAPS) { + JfrTraceId::assign(ik); if (IS_EVENT_OR_HOST_KLASS(ik)) { JfrEventClassTransformer::on_klass_creation(ik, parser, THREAD); - return; - } - if (JfrMethodTracer::in_use()) { + } else if (JfrMethodTracer::in_use()) { JfrMethodTracer::on_klass_creation(ik, parser, THREAD); } + if (!parser.is_internal()) { + JfrClassDefineEvent::on_creation(ik, parser, THREAD); + } } void Jfr::on_klass_redefinition(const InstanceKlass* ik, const InstanceKlass* scratch_klass) { @@ -168,3 +172,11 @@ bool Jfr::on_flight_recorder_option(const JavaVMOption** option, char* delimiter bool Jfr::on_start_flight_recording_option(const JavaVMOption** option, char* delimiter) { return JfrOptionSet::parse_start_flight_recording_option(option, delimiter); } + +void Jfr::on_restoration(const Klass* k, JavaThread* jt) { + assert(k != nullptr, "invariant"); + JfrTraceId::restore(k); + if (k->is_instance_klass()) { + JfrClassDefineEvent::on_restoration(InstanceKlass::cast(k), jt); + } +} diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index 2e1fc738a61..7b86e6c917e 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_JFR_JFR_HPP #define SHARE_JFR_JFR_HPP +#include "jfr/utilities/jfrTypes.hpp" #include "memory/allStatic.hpp" #include "oops/oopsHierarchy.hpp" #include "utilities/exceptions.hpp" @@ -78,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_restoration(const Klass* k, JavaThread* jt); }; #endif // SHARE_JFR_JFR_HPP diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index eaafef37306..18a74454eb6 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -215,6 +215,7 @@ + diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 375ab4d04e9..b1c502e17f8 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -30,11 +30,12 @@ #include "classfile/vmClasses.hpp" #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp" #include "jfr/recorder/checkpoint/types/jfrTypeSet.hpp" -#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" +#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp" #include "jfr/recorder/jfrRecorder.hpp" #include "jfr/support/jfrKlassUnloading.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "jfr/support/methodtracer/jfrInstrumentedClass.hpp" #include "jfr/support/methodtracer/jfrMethodTracer.hpp" #include "jfr/utilities/jfrHashtable.hpp" @@ -1262,7 +1263,7 @@ static size_t teardown() { clear_klasses_and_methods(); clear_method_tracer_klasses(); JfrKlassUnloading::clear(); - _artifacts->increment_checkpoint_id(); + _artifacts->clear(); _initial_type_set = true; } else { _initial_type_set = false; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp index c60556927ad..765bba69105 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp @@ -23,18 +23,19 @@ */ #include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "jfr/utilities/jfrPredicate.hpp" #include "jfr/utilities/jfrRelation.hpp" #include "oops/instanceKlass.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" -JfrArtifactSet::JfrArtifactSet(bool class_unload, bool previous_epoch) : _symbol_table(nullptr), - _klass_set(nullptr), +JfrArtifactSet::JfrArtifactSet(bool class_unload, bool previous_epoch) : _klass_set(nullptr), _klass_loader_set(nullptr), _klass_loader_leakp_set(nullptr), _total_count(0), - _class_unload(class_unload) { + _class_unload(class_unload), + _previous_epoch(previous_epoch) { initialize(class_unload, previous_epoch); assert(!previous_epoch || _klass_loader_leakp_set != nullptr, "invariant"); assert(_klass_loader_set != nullptr, "invariant"); @@ -47,12 +48,7 @@ static unsigned initial_klass_loader_leakp_set_size = 64; void JfrArtifactSet::initialize(bool class_unload, bool previous_epoch) { _class_unload = class_unload; - if (_symbol_table == nullptr) { - _symbol_table = JfrSymbolTable::create(); - assert(_symbol_table != nullptr, "invariant"); - } - assert(_symbol_table != nullptr, "invariant"); - _symbol_table->set_class_unload(class_unload); + _previous_epoch = previous_epoch; _total_count = 0; // Resource allocations. Keep in this allocation order. if (previous_epoch) { @@ -63,45 +59,33 @@ void JfrArtifactSet::initialize(bool class_unload, bool previous_epoch) { } void JfrArtifactSet::clear() { - if (_symbol_table != nullptr) { - _symbol_table->clear(); - } + assert(_previous_epoch, "invariant"); + JfrSymbolTable::clear_previous_epoch(); + assert(_klass_loader_leakp_set != nullptr, "invariant"); + initial_klass_loader_leakp_set_size = MAX2(initial_klass_loader_leakp_set_size, _klass_loader_leakp_set->table_size()); } JfrArtifactSet::~JfrArtifactSet() { - delete _symbol_table; // _klass_loader_set, _klass_loader_leakp_set and // _klass_list will be cleared by a ResourceMark } traceid JfrArtifactSet::bootstrap_name(bool leakp) { - return _symbol_table->bootstrap_name(leakp); -} - -traceid JfrArtifactSet::mark_hidden_klass_name(const Klass* klass, bool leakp) { - assert(klass->is_instance_klass(), "invariant"); - return _symbol_table->mark_hidden_klass_name((const InstanceKlass*)klass, leakp); -} - -traceid JfrArtifactSet::mark(uintptr_t hash, const Symbol* sym, bool leakp) { - return _symbol_table->mark(hash, sym, leakp); + return JfrSymbolTable::bootstrap_name(leakp); } traceid JfrArtifactSet::mark(const Klass* klass, bool leakp) { - return _symbol_table->mark(klass, leakp); + return JfrSymbolTable::mark(klass, leakp, _class_unload, _previous_epoch); } traceid JfrArtifactSet::mark(const Symbol* symbol, bool leakp) { - return _symbol_table->mark(symbol, leakp); -} - -traceid JfrArtifactSet::mark(uintptr_t hash, const char* const str, bool leakp) { - return _symbol_table->mark(hash, str, leakp); + return JfrSymbolTable::mark(symbol, leakp, _class_unload, _previous_epoch); } bool JfrArtifactSet::has_klass_entries() const { return _klass_set->is_nonempty(); } + static inline bool not_in_set(JfrArtifactSet::JfrKlassSet* set, const Klass* k) { assert(set != nullptr, "invariant"); assert(k != nullptr, "invariant"); @@ -129,10 +113,3 @@ size_t JfrArtifactSet::total_count() const { initial_klass_loader_set_size = MAX2(initial_klass_loader_set_size, _klass_loader_set->table_size()); return _total_count; } - -void JfrArtifactSet::increment_checkpoint_id() { - assert(_symbol_table != nullptr, "invariant"); - _symbol_table->increment_checkpoint_id(); - assert(_klass_loader_leakp_set != nullptr, "invariant"); - initial_klass_loader_leakp_set_size = MAX2(initial_klass_loader_leakp_set_size, _klass_loader_leakp_set->table_size()); -} diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp index 74200aef1f1..cc5ebb2be39 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -207,12 +207,12 @@ class JfrArtifactSet : public JfrCHeapObj { typedef JfrSet JfrKlassSet; private: - JfrSymbolTable* _symbol_table; JfrKlassSet* _klass_set; JfrKlassSet* _klass_loader_set; JfrKlassSet* _klass_loader_leakp_set; size_t _total_count; bool _class_unload; + bool _previous_epoch; public: JfrArtifactSet(bool class_unload, bool previous_epoch); @@ -222,32 +222,20 @@ class JfrArtifactSet : public JfrCHeapObj { void initialize(bool class_unload, bool previous_epoch); void clear(); - traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); traceid mark(const Klass* klass, bool leakp); traceid mark(const Symbol* symbol, bool leakp); - traceid mark(uintptr_t hash, const char* const str, bool leakp); - traceid mark_hidden_klass_name(const Klass* klass, bool leakp); traceid bootstrap_name(bool leakp); - const JfrSymbolTable::SymbolEntry* map_symbol(const Symbol* symbol) const; - const JfrSymbolTable::SymbolEntry* map_symbol(uintptr_t hash) const; - const JfrSymbolTable::StringEntry* map_string(uintptr_t hash) const; - bool has_klass_entries() const; size_t total_count() const; void register_klass(const Klass* k); bool should_do_cld_klass(const Klass* k, bool leakp); - void increment_checkpoint_id(); template - void iterate_symbols(T& functor) { - _symbol_table->iterate_symbols(functor); - } + void iterate_symbols(T& functor); template - void iterate_strings(T& functor) { - _symbol_table->iterate_strings(functor); - } + void iterate_strings(T& functor); template void tally(Writer& writer) { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp new file mode 100644 index 00000000000..a1a25c4e907 --- /dev/null +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.inline.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_INLINE_HPP +#define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_INLINE_HPP + +#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" + +#include "jfr/support/jfrSymbolTable.inline.hpp" + +template +inline void JfrArtifactSet::iterate_symbols(T& functor) { + JfrSymbolTable::iterate_symbols(functor, _previous_epoch); +} + +template +inline void JfrArtifactSet::iterate_strings(T& functor) { + JfrSymbolTable::iterate_strings(functor, _previous_epoch); +} + +#endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETUTILS_INLINE_HPP diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp index 2fcb1a64baf..405fa25baff 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp @@ -109,6 +109,7 @@ static void check_klass(const Klass* klass) { void JfrTraceId::assign(const Klass* klass) { assert(klass != nullptr, "invariant"); + assert(klass->trace_id() == 0, "invariant"); klass->set_trace_id(next_class_id()); check_klass(klass); const Klass* const super = klass->super(); diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index f5214ff7942..6a6da0f9b04 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -43,6 +43,7 @@ #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp" #include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" +#include "jfr/support/jfrSymbolTable.hpp" #include "jfr/support/jfrThreadLocal.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/writers/jfrJavaEventWriter.hpp" @@ -315,6 +316,9 @@ bool JfrRecorder::create_components() { if (!create_thread_group_manager()) { return false; } + if (!create_symbol_table()) { + return false; + } return true; } @@ -413,6 +417,10 @@ bool JfrRecorder::create_thread_group_manager() { return JfrThreadGroupManager::create(); } +bool JfrRecorder::create_symbol_table() { + return JfrSymbolTable::create(); +} + void JfrRecorder::destroy_components() { JfrJvmtiAgent::destroy(); if (_post_box != nullptr) { @@ -453,6 +461,7 @@ void JfrRecorder::destroy_components() { } JfrEventThrottler::destroy(); JfrThreadGroupManager::destroy(); + JfrSymbolTable::destroy(); } bool JfrRecorder::create_recorder_thread() { diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp index 34cc8fda949..8cc4521669d 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp @@ -57,6 +57,7 @@ class JfrRecorder : public JfrCHeapObj { static bool create_thread_sampler(); static bool create_cpu_time_thread_sampling(); static bool create_event_throttler(); + static bool create_symbol_table(); static bool create_components(); static void destroy_components(); static void on_recorder_thread_exit(); diff --git a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp index 3f0b132f1a4..08250a1ae59 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp @@ -39,6 +39,7 @@ #include "jfr/recorder/storage/jfrStorageControl.hpp" #include "jfr/recorder/stringpool/jfrStringPool.hpp" #include "jfr/support/jfrDeprecationManager.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrThreadIterator.hpp" #include "jfr/utilities/jfrTime.hpp" @@ -450,6 +451,7 @@ void JfrRecorderService::clear() { void JfrRecorderService::pre_safepoint_clear() { _storage.clear(); JfrStackTraceRepository::clear(); + JfrSymbolTable::allocate_next_epoch(); } void JfrRecorderService::invoke_safepoint_clear() { @@ -558,6 +560,7 @@ void JfrRecorderService::pre_safepoint_write() { } write_storage(_storage, _chunkwriter); write_stacktrace(_stack_trace_repository, _chunkwriter, true); + JfrSymbolTable::allocate_next_epoch(); } void JfrRecorderService::invoke_safepoint_write() { diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp new file mode 100644 index 00000000000..06f361ced8c --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "cds/aotClassLocation.hpp" +#include "classfile/classFileParser.hpp" +#include "classfile/classFileStream.hpp" +#include "classfile/classLoaderData.inline.hpp" +#include "jfr/instrumentation/jfrClassTransformer.hpp" +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" +#include "jfr/support/jfrClassDefineEvent.hpp" +#include "jfr/support/jfrSymbolTable.hpp" +#include "jfrfiles/jfrEventClasses.hpp" +#include "oops/instanceKlass.hpp" +#include "runtime/javaThread.hpp" + + /* + * Two cases for JDK modules as outlined by JEP 200: The Modular JDK. + * + * The modular structure of the JDK implements the following principles: + * 1. Standard modules, whose specifications are governed by the JCP, have names starting with the string "java.". + * 2. All other modules are merely part of the JDK, and have names starting with the string "jdk.". + * */ +static inline bool is_jdk_module(const char* module_name) { + assert(module_name != nullptr, "invariant"); + return strstr(module_name, "java.") == module_name || strstr(module_name, "jdk.") == module_name; +} + +static inline bool is_unnamed_module(const ModuleEntry* module) { + return module == nullptr || !module->is_named(); +} + +static inline bool is_jdk_module(const ModuleEntry* module, JavaThread* jt) { + assert(jt != nullptr, "invariant"); + if (is_unnamed_module(module)) { + return false; + } + const Symbol* const module_symbol = module->name(); + assert(module_symbol != nullptr, "invariant"); + return is_jdk_module(module_symbol->as_C_string()); +} + +static inline bool is_jdk_module(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + return is_jdk_module(ik->module(), jt); +} + +static traceid module_path(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + const ModuleEntry* const module_entry = ik->module(); + if (is_unnamed_module(module_entry)) { + return 0; + } + const char* const module_name = module_entry->name()->as_C_string(); + assert(module_name != nullptr, "invariant"); + if (is_jdk_module(module_name)) { + const size_t module_name_len = strlen(module_name); + char* const path = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, module_name_len + 6); // "jrt:/" + jio_snprintf(path, module_name_len + 6, "%s%s", "jrt:/", module_name); + return JfrSymbolTable::add(path); + } + return 0; +} + +static traceid caller_path(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + assert(ik->class_loader_data()->is_the_null_class_loader_data(), "invariant"); + const Klass* const caller = jt->security_get_caller_class(1); + // caller can be null, for example, during a JVMTI VM_Init hook + if (caller != nullptr) { + const char* caller_name = caller->external_name(); + assert(caller_name != nullptr, "invariant"); + const size_t caller_name_len = strlen(caller_name); + char* const path = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, caller_name_len + 13); // "instance of " + jio_snprintf(path, caller_name_len + 13, "%s%s", "instance of ", caller_name); + return JfrSymbolTable::add(path); + } + return 0; +} + +static traceid class_loader_path(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(jt != nullptr, "invariant"); + assert(!ik->class_loader_data()->is_the_null_class_loader_data(), "invariant"); + oop class_loader = ik->class_loader_data()->class_loader(); + const char* class_loader_name = class_loader->klass()->external_name(); + return class_loader_name != nullptr ? JfrSymbolTable::add(class_loader_name) : 0; +} + +static inline bool is_not_retransforming(const InstanceKlass* ik, JavaThread* jt) { + return JfrClassTransformer::find_existing_klass(ik, jt) == nullptr; +} + +static traceid get_source(const InstanceKlass* ik, JavaThread* jt) { + traceid source_id = 0; + if (is_jdk_module(ik, jt)) { + source_id = module_path(ik, jt); + } else if (ik->class_loader_data()->is_the_null_class_loader_data()) { + source_id = caller_path(ik, jt); + } else { + source_id = class_loader_path(ik, jt); + } + return source_id; +} + +static traceid get_source(const AOTClassLocation* cl, JavaThread* jt) { + assert(cl != nullptr, "invariant"); + assert(!cl->is_modules_image(), "invariant"); + const char* const path = cl->path(); + assert(path != nullptr, "invariant"); + size_t len = strlen(path); + const char* file_type = cl->file_type_string(); + assert(file_type != nullptr, "invariant"); + len += strlen(file_type) + 3; // ":/" + null + char* const url = NEW_RESOURCE_ARRAY_IN_THREAD(jt, char, len); + jio_snprintf(url, len, "%s%s%s", file_type, ":/", path); + return JfrSymbolTable::add(url); +} + +static inline void send_event(const InstanceKlass* ik, traceid source_id) { + EventClassDefine event; + event.set_definedClass(ik); + event.set_definingClassLoader(ik->class_loader_data()); + event.set_source(source_id); + event.commit(); +} + +void JfrClassDefineEvent::on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(ik->trace_id() != 0, "invariant"); + assert(!parser.is_internal(), "invariant"); + assert(jt != nullptr, "invariant"); + + if (EventClassDefine::is_enabled() && is_not_retransforming(ik, jt)) { + ResourceMark rm(jt); + traceid source_id = 0; + const ClassFileStream& stream = parser.stream(); + if (stream.source() != nullptr) { + if (stream.from_boot_loader_modules_image()) { + assert(is_jdk_module(ik, jt), "invariant"); + source_id = module_path(ik, jt); + } else { + source_id = JfrSymbolTable::add(stream.source()); + } + } else { + source_id = get_source(ik, jt); + } + send_event(ik, source_id); + } +} + +void JfrClassDefineEvent::on_restoration(const InstanceKlass* ik, JavaThread* jt) { + assert(ik != nullptr, "invariant"); + assert(ik->trace_id() != 0, "invariant"); + assert(jt != nullptr, "invariant"); + + if (EventClassDefine::is_enabled()) { + ResourceMark rm(jt); + assert(is_not_retransforming(ik, jt), "invariant"); + const int index = ik->shared_classpath_index(); + assert(index >= 0, "invariant"); + const AOTClassLocation* const cl = AOTClassLocationConfig::runtime()->class_location_at(index); + assert(cl != nullptr, "invariant"); + send_event(ik, cl->is_modules_image() ? module_path(ik, jt) : get_source(cl, jt)); + } +} diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp new file mode 100644 index 00000000000..4a0926023ca --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP +#define SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP + +#include "memory/allStatic.hpp" + +class ClassFileParser; +class InstanceKlass; +class JavaThread; + +class JfrClassDefineEvent : AllStatic { + public: + static void on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt); + static void on_restoration(const InstanceKlass* ik, JavaThread* jt); +}; + +#endif // SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP diff --git a/src/hotspot/share/jfr/support/jfrKlassExtension.hpp b/src/hotspot/share/jfr/support/jfrKlassExtension.hpp index dc5f7aa7e90..54f5031dd3b 100644 --- a/src/hotspot/share/jfr/support/jfrKlassExtension.hpp +++ b/src/hotspot/share/jfr/support/jfrKlassExtension.hpp @@ -40,6 +40,5 @@ #define EVENT_STICKY_BIT 8192 #define IS_EVENT_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)) != 0) #define IS_EVENT_OR_HOST_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS | EVENT_HOST_KLASS)) != 0) -#define ON_KLASS_CREATION(k, p, t) Jfr::on_klass_creation(k, p, t) #endif // SHARE_JFR_SUPPORT_JFRKLASSEXTENSION_HPP diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp index 3fc639ffb5c..c791a05f818 100644 --- a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp @@ -24,131 +24,32 @@ #include "classfile/classLoaderData.hpp" #include "classfile/javaClasses.hpp" -#include "jfr/support/jfrSymbolTable.hpp" +#include "jfr/recorder/jfrRecorder.hpp" +#include "jfr/support/jfrSymbolTable.inline.hpp" #include "oops/klass.hpp" #include "oops/symbol.hpp" +#include "runtime/atomicAccess.hpp" #include "runtime/mutexLocker.hpp" -// incremented on each rotation -static u8 checkpoint_id = 1; +JfrSymbolTable::Impl* JfrSymbolTable::_epoch_0 = nullptr; +JfrSymbolTable::Impl* JfrSymbolTable::_epoch_1 = nullptr; +JfrSymbolTable::StringEntry* JfrSymbolTable::_bootstrap = nullptr; -// creates a unique id by combining a checkpoint relative symbol id (2^24) -// with the current checkpoint id (2^40) -#define CREATE_SYMBOL_ID(sym_id) (((u8)((checkpoint_id << 24) | sym_id))) - -static traceid create_symbol_id(traceid artifact_id) { - return artifact_id != 0 ? CREATE_SYMBOL_ID(artifact_id) : 0; -} - -static uintptr_t string_hash(const char* str) { - return java_lang_String::hash_code(reinterpret_cast(str), static_cast(strlen(str))); -} - -static JfrSymbolTable::StringEntry* bootstrap = nullptr; - -static JfrSymbolTable* _instance = nullptr; - -static JfrSymbolTable& instance() { - assert(_instance != nullptr, "invariant"); - return *_instance; -} - -JfrSymbolTable* JfrSymbolTable::create() { - assert(_instance == nullptr, "invariant"); - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - _instance = new JfrSymbolTable(); - return _instance; -} - -void JfrSymbolTable::destroy() { - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - if (_instance != nullptr) { - delete _instance; - _instance = nullptr; - } - assert(_instance == nullptr, "invariant"); -} - -JfrSymbolTable::JfrSymbolTable() : - _symbols(new Symbols(this)), - _strings(new Strings(this)), - _symbol_list(nullptr), - _string_list(nullptr), - _symbol_query(nullptr), - _string_query(nullptr), - _id_counter(1), - _class_unload(false) { - assert(_symbols != nullptr, "invariant"); - assert(_strings != nullptr, "invariant"); - bootstrap = new StringEntry(0, (const char*)&BOOTSTRAP_LOADER_NAME); - assert(bootstrap != nullptr, "invariant"); - bootstrap->set_id(create_symbol_id(1)); - _string_list = bootstrap; -} - -JfrSymbolTable::~JfrSymbolTable() { - clear(); - delete _symbols; - delete _strings; - delete bootstrap; -} - -void JfrSymbolTable::clear() { - assert(_symbols != nullptr, "invariant"); - if (_symbols->has_entries()) { - _symbols->clear_entries(); - } - assert(!_symbols->has_entries(), "invariant"); - - assert(_strings != nullptr, "invariant"); - if (_strings->has_entries()) { - _strings->clear_entries(); - } - assert(!_strings->has_entries(), "invariant"); - - _symbol_list = nullptr; - _id_counter = 1; - - _symbol_query = nullptr; - _string_query = nullptr; - - assert(bootstrap != nullptr, "invariant"); - bootstrap->reset(); - _string_list = bootstrap; -} - -void JfrSymbolTable::set_class_unload(bool class_unload) { - _class_unload = class_unload; -} - -void JfrSymbolTable::increment_checkpoint_id() { - assert_lock_strong(ClassLoaderDataGraph_lock); - clear(); - ++checkpoint_id; -} +JfrSymbolCallback::JfrSymbolCallback() : _id_counter(2) {} // 1 is reserved for "bootstrap" entry template -inline void JfrSymbolTable::assign_id(T* entry) { +inline void JfrSymbolCallback::assign_id(const T* entry) { assert(entry != nullptr, "invariant"); assert(entry->id() == 0, "invariant"); - entry->set_id(create_symbol_id(++_id_counter)); + entry->set_id(AtomicAccess::fetch_then_add(&_id_counter, (traceid)1)); } -void JfrSymbolTable::on_link(const SymbolEntry* entry) { +void JfrSymbolCallback::on_link(const JfrSymbolTable::SymbolEntry* entry) { assign_id(entry); const_cast(entry->literal())->increment_refcount(); - entry->set_list_next(_symbol_list); - _symbol_list = entry; } -bool JfrSymbolTable::on_equals(uintptr_t hash, const SymbolEntry* entry) { - assert(entry != nullptr, "invariant"); - assert(entry->hash() == hash, "invariant"); - assert(_symbol_query != nullptr, "invariant"); - return _symbol_query == entry->literal(); -} - -void JfrSymbolTable::on_unlink(const SymbolEntry* entry) { +void JfrSymbolCallback::on_unlink(const JfrSymbolTable::SymbolEntry* entry) { assert(entry != nullptr, "invariant"); const_cast(entry->literal())->decrement_refcount(); } @@ -162,75 +63,241 @@ static const char* resource_to_c_heap_string(const char* resource_str) { return c_string; } -void JfrSymbolTable::on_link(const StringEntry* entry) { +void JfrSymbolCallback::on_link(const JfrSymbolTable::StringEntry* entry) { assign_id(entry); - const_cast(entry)->set_literal(resource_to_c_heap_string(entry->literal())); - entry->set_list_next(_string_list); - _string_list = entry; + const_cast(entry)->set_literal(resource_to_c_heap_string(entry->literal())); } -static bool string_compare(const char* query, const char* candidate) { - assert(query != nullptr, "invariant"); - assert(candidate != nullptr, "invariant"); - const size_t length = strlen(query); - return strncmp(query, candidate, length) == 0; -} - -bool JfrSymbolTable::on_equals(uintptr_t hash, const StringEntry* entry) { +void JfrSymbolCallback::on_unlink(const JfrSymbolTable::StringEntry* entry) { assert(entry != nullptr, "invariant"); - assert(entry->hash() == hash, "invariant"); - assert(_string_query != nullptr, "invariant"); - return string_compare(_string_query, entry->literal()); + JfrCHeapObj::free(const_cast(entry->literal()), strlen(entry->literal()) + 1); } -void JfrSymbolTable::on_unlink(const StringEntry* entry) { - assert(entry != nullptr, "invariant"); - JfrCHeapObj::free(const_cast(entry->literal()), strlen(entry->literal() + 1)); +static JfrSymbolCallback* _callback = nullptr; + +template +JfrSymbolTableEntry::JfrSymbolTableEntry(unsigned hash, const T& data) : + JfrConcurrentHashtableEntry(hash, data), _serialized(false), _unloading(false), _leakp(false) {} + +template +bool JfrSymbolTableEntry::on_equals(const char* str) { + assert(str != nullptr, "invariant"); + return strcmp((const char*)this->literal(), str) == 0; +} + +static const constexpr unsigned max_capacity = 1 << 30; + +static inline unsigned calculate_capacity(unsigned size, unsigned capacity) { + assert(is_power_of_2(capacity), "invariant"); + assert(capacity <= max_capacity, "invariant"); + double load_factor = (double)size / (double)capacity; + if (load_factor < 0.75) { + return capacity; + } + do { + capacity <<= 1; + assert(is_power_of_2(capacity), "invariant"); + guarantee(capacity <= max_capacity, "overflow"); + load_factor = (double)size / (double)capacity; + } while (load_factor >= 0.75); + return capacity; +} + +bool JfrSymbolTable::create() { + assert(_callback == nullptr, "invariant"); + // Allocate callback instance before tables. + _callback = new JfrSymbolCallback(); + if (_callback == nullptr) { + return false; + } + assert(_bootstrap == nullptr, "invariant"); + _bootstrap = new StringEntry(0, (const char*)&BOOTSTRAP_LOADER_NAME); + if (_bootstrap == nullptr) { + return false; + } + _bootstrap->set_id(1); + assert(this_epoch_table() == nullptr, "invariant"); + Impl* table = new JfrSymbolTable::Impl(); + if (table == nullptr) { + return false; + } + set_this_epoch(table); + assert(previous_epoch_table() == nullptr, "invariant"); + return true; +} + +void JfrSymbolTable::destroy() { + if (_callback != nullptr) { + delete _callback; + _callback = nullptr; + } + if (_bootstrap != nullptr) { + delete _bootstrap; + _bootstrap = nullptr; + } + if (_epoch_0 != nullptr) { + delete _epoch_0; + _epoch_0 = nullptr; + } + if (_epoch_1 != nullptr) { + delete _epoch_1; + _epoch_1 = nullptr; + } +} + +void JfrSymbolTable::allocate_next_epoch() { + assert(nullptr == previous_epoch_table(), "invariant"); + const Impl* const current = this_epoch_table(); + assert(current != nullptr, "invariant"); + const unsigned next_symbols_capacity = calculate_capacity(current->symbols_size(), current->symbols_capacity()); + const unsigned next_strings_capacity = calculate_capacity(current->strings_size(), current->strings_capacity()); + assert(_callback != nullptr, "invariant"); + // previous epoch to become the next epoch. + set_previous_epoch(new JfrSymbolTable::Impl(next_symbols_capacity, next_strings_capacity)); + assert(this_epoch_table() != nullptr, "invariant"); + assert(previous_epoch_table() != nullptr, "invariant"); +} + +void JfrSymbolTable::clear_previous_epoch() { + Impl* const table = previous_epoch_table(); + assert(table != nullptr, "invariant"); + set_previous_epoch(nullptr); + delete table; + assert(_bootstrap != nullptr, "invariant"); + _bootstrap->reset(); + assert(!_bootstrap->is_serialized(), "invariant"); +} + +void JfrSymbolTable::set_this_epoch(JfrSymbolTable::Impl* table) { + assert(table != nullptr, "invariant"); + const u1 epoch = JfrTraceIdEpoch::current(); + if (epoch == 0) { + _epoch_0 = table; + } else { + _epoch_1 = table; + } +} + +void JfrSymbolTable::set_previous_epoch(JfrSymbolTable::Impl* table) { + const u1 epoch = JfrTraceIdEpoch::previous(); + if (epoch == 0) { + _epoch_0 = table; + } else { + _epoch_1 = table; + } +} + +inline bool JfrSymbolTable::Impl::has_symbol_entries() const { + return _symbols->is_nonempty(); +} + +inline bool JfrSymbolTable::Impl::has_string_entries() const { + return _strings->is_nonempty(); +} + +inline bool JfrSymbolTable::Impl::has_entries() const { + return has_symbol_entries() || has_string_entries(); +} + +inline unsigned JfrSymbolTable::Impl::symbols_capacity() const { + return _symbols->capacity(); +} + +inline unsigned JfrSymbolTable::Impl::symbols_size() const { + return _symbols->size(); +} + +inline unsigned JfrSymbolTable::Impl::strings_capacity() const { + return _strings->capacity(); +} + +inline unsigned JfrSymbolTable::Impl::strings_size() const { + return _strings->size(); +} + +bool JfrSymbolTable::has_entries(bool previous_epoch /* false */) { + const Impl* table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->has_entries(); +} + +bool JfrSymbolTable::has_symbol_entries(bool previous_epoch /* false */) { + const Impl* table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->has_symbol_entries(); +} + +bool JfrSymbolTable::has_string_entries(bool previous_epoch /* false */) { + const Impl* table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->has_string_entries(); } traceid JfrSymbolTable::bootstrap_name(bool leakp) { - assert(bootstrap != nullptr, "invariant"); + assert(_bootstrap != nullptr, "invariant"); if (leakp) { - bootstrap->set_leakp(); + _bootstrap->set_leakp(); } - return bootstrap->id(); + return _bootstrap->id(); } -traceid JfrSymbolTable::mark(const Symbol* sym, bool leakp /* false */) { +JfrSymbolTable::Impl::Impl(unsigned symbols_capacity /* 0*/, unsigned strings_capacity /* 0 */) : + _symbols(new Symbols(_callback, symbols_capacity)), _strings(new Strings(_callback, strings_capacity)) {} + +JfrSymbolTable::Impl::~Impl() { + delete _symbols; + delete _strings; +} + +traceid JfrSymbolTable::Impl::mark(const Symbol* sym, bool leakp /* false */, bool class_unload /* false */) { assert(sym != nullptr, "invariant"); - return mark(sym->identity_hash(), sym, leakp); + return mark(sym->identity_hash(), sym, leakp, class_unload); } -traceid JfrSymbolTable::mark(uintptr_t hash, const Symbol* sym, bool leakp) { +traceid JfrSymbolTable::Impl::mark(unsigned hash, const Symbol* sym, bool leakp, bool class_unload /* false */) { assert(sym != nullptr, "invariant"); assert(_symbols != nullptr, "invariant"); - _symbol_query = sym; - const SymbolEntry& entry = _symbols->lookup_put(hash, sym); - if (_class_unload) { - entry.set_unloading(); - } + const SymbolEntry* entry = _symbols->lookup_put(hash, sym); + assert(entry != nullptr, "invariant"); if (leakp) { - entry.set_leakp(); + entry->set_leakp(); + } else if (class_unload) { + entry->set_unloading(); } - return entry.id(); + return entry->id(); } -traceid JfrSymbolTable::mark(const char* str, bool leakp /* false*/) { - return mark(string_hash(str), str, leakp); +traceid JfrSymbolTable::mark(const Symbol* sym, bool leakp /* false */, bool class_unload /* false */, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->mark(sym->identity_hash(), sym, leakp, class_unload); } -traceid JfrSymbolTable::mark(uintptr_t hash, const char* str, bool leakp) { +static inline unsigned string_hash(const char* str) { + return java_lang_String::hash_code(reinterpret_cast(str), static_cast(strlen(str))); +} + +traceid JfrSymbolTable::Impl::mark(const char* str, bool leakp /* false*/, bool class_unload /* false */) { + return mark(string_hash(str), str, leakp, class_unload); +} + +traceid JfrSymbolTable::Impl::mark(unsigned hash, const char* str, bool leakp, bool class_unload /* false */) { assert(str != nullptr, "invariant"); assert(_strings != nullptr, "invariant"); - _string_query = str; - const StringEntry& entry = _strings->lookup_put(hash, str); - if (_class_unload) { - entry.set_unloading(); - } + const StringEntry* entry = _strings->lookup_put(hash, str); + assert(entry != nullptr, "invariant"); if (leakp) { - entry.set_leakp(); + entry->set_leakp(); + } else if (class_unload) { + entry->set_unloading(); } - return entry.id(); + return entry->id(); +} + +traceid JfrSymbolTable::mark(unsigned hash, const char* str, bool leakp, bool class_unload /* false */, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->mark(hash, str, leakp, class_unload); } /* @@ -241,40 +308,47 @@ traceid JfrSymbolTable::mark(uintptr_t hash, const char* str, bool leakp) { * * Caller needs ResourceMark. */ -traceid JfrSymbolTable::mark_hidden_klass_name(const Klass* k, bool leakp) { +inline traceid JfrSymbolTable::Impl::mark_hidden_klass_name(const Klass* k, bool leakp, bool class_unload /* false */) { assert(k != nullptr, "invariant"); assert(k->is_hidden(), "invariant"); - const uintptr_t hash = k->name()->identity_hash(); - return mark(hash, k->external_name(), leakp); + return mark(k->name()->identity_hash(), k->external_name(), leakp, class_unload); } -traceid JfrSymbolTable::mark(const Klass* k, bool leakp) { +traceid JfrSymbolTable::Impl::mark(const Klass* k, bool leakp, bool class_unload /* false */) { assert(k != nullptr, "invariant"); traceid symbol_id = 0; if (k->is_hidden()) { - symbol_id = mark_hidden_klass_name(k, leakp); + symbol_id = mark_hidden_klass_name(k, leakp, class_unload); } else { Symbol* const sym = k->name(); if (sym != nullptr) { - symbol_id = mark(sym, leakp); + symbol_id = mark(sym, leakp, class_unload); } } assert(symbol_id > 0, "a symbol handler must mark the symbol for writing"); return symbol_id; } -template -traceid JfrSymbolTable::add_impl(const T* sym) { - assert(sym != nullptr, "invariant"); - assert(_instance != nullptr, "invariant"); - assert_locked_or_safepoint(ClassLoaderDataGraph_lock); - return instance().mark(sym); +traceid JfrSymbolTable::mark(const Klass* k, bool leakp, bool class_unload /* false */, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + return table->mark(k, leakp, class_unload); } -traceid JfrSymbolTable::add(const Symbol* sym) { - return add_impl(sym); +inline traceid JfrSymbolTable::Impl::add(const Symbol* sym) { + assert(sym != nullptr, "invariant"); + return _symbols->lookup_put(sym->identity_hash(), sym)->id(); +} + +traceid JfrSymbolTable::Impl::add(const char* str) { + assert(str != nullptr, "invariant"); + return _strings->lookup_put(string_hash(str), str)->id(); +} + +inline traceid JfrSymbolTable::add(const Symbol* sym) { + return this_epoch_table()->add(sym); } traceid JfrSymbolTable::add(const char* str) { - return add_impl(str); + return this_epoch_table()->add(str); } diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.hpp b/src/hotspot/share/jfr/support/jfrSymbolTable.hpp index 8cefa287c8a..d2ee6cd4bc1 100644 --- a/src/hotspot/share/jfr/support/jfrSymbolTable.hpp +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.hpp @@ -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 @@ -25,32 +25,58 @@ #ifndef SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP #define SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP -#include "jfr/utilities/jfrHashtable.hpp" +#include "jfr/utilities/jfrAllocation.hpp" +#include "jfr/utilities/jfrConcurrentHashtable.hpp" #include "jfr/utilities/jfrTypes.hpp" template -class ListEntry : public JfrHashtableEntry { +class JfrSymbolTableEntry : public JfrConcurrentHashtableEntry { public: - ListEntry(uintptr_t hash, const T& data) : JfrHashtableEntry(hash, data), - _list_next(nullptr), _serialized(false), _unloading(false), _leakp(false) {} - const ListEntry* list_next() const { return _list_next; } - void reset() const { - _list_next = nullptr; _serialized = false; _unloading = false; _leakp = false; - } - void set_list_next(const ListEntry* next) const { _list_next = next; } + JfrSymbolTableEntry(unsigned hash, const T& data); bool is_serialized() const { return _serialized; } void set_serialized() const { _serialized = true; } bool is_unloading() const { return _unloading; } void set_unloading() const { _unloading = true; } bool is_leakp() const { return _leakp; } void set_leakp() const { _leakp = true; } + void reset() const { + _serialized = false; + _unloading = false; + _leakp = false; + } + + bool on_equals(const Symbol* sym) { + assert(sym != nullptr, "invariant"); + return sym == (const Symbol*)this->literal(); + } + + bool on_equals(const char* str); + private: - mutable const ListEntry* _list_next; mutable bool _serialized; mutable bool _unloading; mutable bool _leakp; }; +class JfrSymbolCallback : public JfrCHeapObj { + friend class JfrSymbolTable; + public: + typedef JfrConcurrentHashTableHost Symbols; + typedef JfrConcurrentHashTableHost Strings; + + void on_link(const Symbols::Entry* entry); + void on_unlink(const Symbols::Entry* entry); + void on_link(const Strings::Entry* entry); + void on_unlink(const Strings::Entry* entry); + + private: + traceid _id_counter; + + JfrSymbolCallback(); + template + void assign_id(const T* entry); +}; + /* * This table maps an oop/Symbol* or a char* to the Jfr type 'Symbol'. * @@ -58,88 +84,93 @@ class ListEntry : public JfrHashtableEntry { * which is represented in the binary format as a sequence of checkpoint events. * The returned id can be used as a foreign key, but please note that the id is * epoch-relative, and is therefore only valid in the current epoch / chunk. - * The table is cleared as part of rotation. - * - * Caller must ensure mutual exclusion by means of the ClassLoaderDataGraph_lock or by safepointing. */ -class JfrSymbolTable : public JfrCHeapObj { - template class, typename, size_t> - friend class HashTableHost; - typedef HashTableHost Symbols; - typedef HashTableHost Strings; +class JfrSymbolTable : public AllStatic { friend class JfrArtifactSet; + template class, typename, unsigned> + friend class JfrConcurrentHashTableHost; + friend class JfrRecorder; + friend class JfrRecorderService; + friend class JfrSymbolCallback; + + typedef JfrConcurrentHashTableHost Symbols; + typedef JfrConcurrentHashTableHost Strings; public: - typedef Symbols::HashEntry SymbolEntry; - typedef Strings::HashEntry StringEntry; + typedef Symbols::Entry SymbolEntry; + typedef Strings::Entry StringEntry; static traceid add(const Symbol* sym); static traceid add(const char* str); private: - Symbols* _symbols; - Strings* _strings; - const SymbolEntry* _symbol_list; - const StringEntry* _string_list; - const Symbol* _symbol_query; - const char* _string_query; - traceid _id_counter; - bool _class_unload; + class Impl : public JfrCHeapObj { + friend class JfrSymbolTable; + private: + Symbols* _symbols; + Strings* _strings; - JfrSymbolTable(); - ~JfrSymbolTable(); - static JfrSymbolTable* create(); + Impl(unsigned symbol_capacity = 0, unsigned string_capacity = 0); + ~Impl(); + + void clear(); + + traceid add(const Symbol* sym); + traceid add(const char* str); + + traceid mark(unsigned hash, const Symbol* sym, bool leakp, bool class_unload = false); + traceid mark(const Klass* k, bool leakp, bool class_unload = false); + traceid mark(const Symbol* sym, bool leakp = false, bool class_unload = false); + traceid mark(const char* str, bool leakp = false, bool class_unload = false); + traceid mark(unsigned hash, const char* str, bool leakp, bool class_unload = false); + traceid mark_hidden_klass_name(const Klass* k, bool leakp, bool class_unload = false); + + bool has_entries() const; + bool has_symbol_entries() const; + bool has_string_entries() const; + + unsigned symbols_capacity() const; + unsigned symbols_size() const; + unsigned strings_capacity() const; + unsigned strings_size() const; + + template + void iterate_symbols(Functor& functor); + + template + void iterate_strings(Functor& functor); + }; + + static Impl* _epoch_0; + static Impl* _epoch_1; + static StringEntry* _bootstrap; + + static bool create(); static void destroy(); - void clear(); - void increment_checkpoint_id(); - void set_class_unload(bool class_unload); + static Impl* this_epoch_table(); + static Impl* previous_epoch_table(); + static Impl* epoch_table_selector(u1 epoch); + static void set_this_epoch(Impl* table); + static void set_previous_epoch(Impl* table); - traceid mark(uintptr_t hash, const Symbol* sym, bool leakp); - traceid mark(const Klass* k, bool leakp); - traceid mark(const Symbol* sym, bool leakp = false); - traceid mark(const char* str, bool leakp = false); - traceid mark(uintptr_t hash, const char* str, bool leakp); - traceid mark_hidden_klass_name(const Klass* k, bool leakp); - traceid bootstrap_name(bool leakp); + static void clear_previous_epoch(); + static void allocate_next_epoch(); - bool has_entries() const { return has_symbol_entries() || has_string_entries(); } - bool has_symbol_entries() const { return _symbol_list != nullptr; } - bool has_string_entries() const { return _string_list != nullptr; } + static bool has_entries(bool previous_epoch = false); + static bool has_symbol_entries(bool previous_epoch = false); + static bool has_string_entries(bool previous_epoch = false); - // hashtable(s) callbacks - void on_link(const SymbolEntry* entry); - bool on_equals(uintptr_t hash, const SymbolEntry* entry); - void on_unlink(const SymbolEntry* entry); - void on_link(const StringEntry* entry); - bool on_equals(uintptr_t hash, const StringEntry* entry); - void on_unlink(const StringEntry* entry); - - template - static traceid add_impl(const T* sym); - - template - void assign_id(T* entry); + static traceid mark(const Klass* k, bool leakp, bool class_unload = false, bool previous_epoch = false); + static traceid mark(const Symbol* sym, bool leakp = false, bool class_unload = false, bool previous_epoch = false); + static traceid mark(unsigned hash, const char* str, bool leakp, bool class_unload = false, bool previous_epoch = false); + static traceid bootstrap_name(bool leakp); template - void iterate_symbols(Functor& functor) { - iterate(functor, _symbol_list); - } + static void iterate_symbols(Functor& functor, bool previous_epoch = false); template - void iterate_strings(Functor& functor) { - iterate(functor, _string_list); - } - - template - void iterate(Functor& functor, const T* list) { - const T* symbol = list; - while (symbol != nullptr) { - const T* next = symbol->list_next(); - functor(symbol); - symbol = next; - } - } + static void iterate_strings(Functor& functor, bool previous_epoch = false); }; #endif // SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_HPP diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp b/src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp new file mode 100644 index 00000000000..9e7ac8c9d47 --- /dev/null +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.inline.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_INLINE_HPP +#define SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_INLINE_HPP + +#include "jfr/support/jfrSymbolTable.hpp" + +#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" +#include "jfr/utilities/jfrConcurrentHashtable.inline.hpp" + +inline JfrSymbolTable::Impl* JfrSymbolTable::epoch_table_selector(u1 epoch) { + return epoch == 0 ? _epoch_0 : _epoch_1; +} + +inline JfrSymbolTable::Impl* JfrSymbolTable::this_epoch_table() { + return epoch_table_selector(JfrTraceIdEpoch::current()); +} + +inline JfrSymbolTable::Impl* JfrSymbolTable::previous_epoch_table() { + return epoch_table_selector(JfrTraceIdEpoch::previous()); +} + +template +inline void JfrSymbolTable::Impl::iterate_symbols(Functor& functor) { + _symbols->iterate_entry(functor); +} + +template +inline void JfrSymbolTable::iterate_symbols(Functor& functor, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + table->iterate_symbols(functor); +} + +template +inline void JfrSymbolTable::Impl::iterate_strings(Functor& functor) { + _strings->iterate_entry(functor); +} + +template +inline void JfrSymbolTable::iterate_strings(Functor& functor, bool previous_epoch /* false */) { + Impl* const table = previous_epoch ? previous_epoch_table() : this_epoch_table(); + assert(table != nullptr, "invariant"); + if (!functor(_bootstrap)) { + return; + } + table->iterate_strings(functor); +} + +#endif // SHARE_JFR_SUPPORT_JFRSYMBOLTABLE_INLINE_HPP diff --git a/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp index bb0e3e082fe..46b4d973ce4 100644 --- a/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp +++ b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp @@ -42,7 +42,6 @@ #define ASSIGN_PRIMITIVE_CLASS_ID(data) JfrTraceId::assign_primitive_klass_id() #define REMOVE_ID(k) JfrTraceId::remove(k); #define REMOVE_METHOD_ID(method) JfrTraceId::remove(method); -#define RESTORE_ID(k) JfrTraceId::restore(k); static constexpr const uint16_t cleared_epoch_bits = 512 | 256; diff --git a/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp new file mode 100644 index 00000000000..5434023e636 --- /dev/null +++ b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.hpp @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_HPP +#define SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_HPP + +#include "jfr/utilities/jfrLinkedList.hpp" +#include "memory/allocation.hpp" + +template class TableEntry> +class JfrConcurrentAscendingId { +private: + IdType _id; +public: + JfrConcurrentAscendingId() : _id(1) {} + // Callbacks. + void on_link(TableEntry* entry); + bool on_equals(unsigned hash, const TableEntry* entry); +}; + +template +class JfrConcurrentHashtableEntry : public CHeapObj { + template + friend class JfrLinkedList; + private: + typedef JfrConcurrentHashtableEntry Entry; + Entry* _next; + T _literal; // ref to item in table. + mutable IdType _id; + unsigned _hash; + + public: + JfrConcurrentHashtableEntry(unsigned hash, const T& data) : _next(nullptr), _literal(data), _id(0), _hash(hash) {} + unsigned hash() const { return _hash; } + T literal() const { return _literal; } + T* literal_addr() { return &_literal; } + void set_literal(T s) { _literal = s; } + void set_next(Entry* next) { _next = next; } + Entry* next() const { return _next; } + Entry** next_addr() { return &_next; } + IdType id() const { return _id; } + void set_id(IdType id) const { _id = id; } + T& value() const { return *const_cast(this)->literal_addr(); } + const T* value_addr() const { return const_cast(this)->literal_addr(); } +}; + +template class TableEntry> +class JfrConcurrentHashtable : public CHeapObj { + public: + typedef TableEntry Entry; + typedef JfrLinkedList Bucket; + + unsigned capacity() const { return _capacity; } + unsigned size() const; + + protected: + JfrConcurrentHashtable(unsigned size); + ~JfrConcurrentHashtable(); + + unsigned index(unsigned hash) const { + return hash & _mask; + } + + Bucket& bucket(unsigned idx) { return _buckets[idx]; } + Bucket* bucket_addr(unsigned idx) { return &_buckets[idx]; } + Entry* head(unsigned idx) { return bucket(idx).head(); } + + bool try_add(unsigned idx, Entry* entry, Entry* next); + + template + void iterate(Callback& cb); + + template + void iterate(unsigned idx, Callback& cb); + + template + static void iterate(Entry* entry, Callback& cb); + + void unlink_entry(Entry* entry); + + private: + Bucket* _buckets; + unsigned _capacity; + unsigned _mask; + unsigned _size; +}; + +template class TableEntry, + typename Callback = JfrConcurrentAscendingId, unsigned TABLE_CAPACITY = 1024> +class JfrConcurrentHashTableHost : public JfrConcurrentHashtable { + public: + typedef TableEntry Entry; + JfrConcurrentHashTableHost(unsigned initial_capacity = 0); + JfrConcurrentHashTableHost(Callback* cb, unsigned initial_capacity = 0); + ~JfrConcurrentHashTableHost(); + + // lookup entry, will put if not found + Entry* lookup_put(unsigned hash, const T& data); + + // id retrieval + IdType id(unsigned hash, const T& data); + + bool is_empty() const; + bool is_nonempty() const { return !is_empty(); } + + template + void iterate_value(Functor& f); + + template + void iterate_entry(Functor& f); + + private: + Callback* _callback; + + Entry* new_entry(unsigned hash, const T& data); +}; + +#endif // SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_HPP diff --git a/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp new file mode 100644 index 00000000000..6d6908234a3 --- /dev/null +++ b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp @@ -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. + * + * 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_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_INLINE_HPP +#define SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_INLINE_HPP + +#include "jfr/utilities/jfrConcurrentHashtable.hpp" + +#include "jfr/utilities/jfrLinkedList.inline.hpp" +#include "memory/allocation.inline.hpp" +#include "nmt/memTracker.hpp" +#include "runtime/atomicAccess.hpp" +#include "utilities/debug.hpp" +#include "utilities/macros.hpp" + +template class TableEntry> +inline void JfrConcurrentAscendingId::on_link(TableEntry* entry) { + assert(entry != nullptr, "invariant"); + assert(entry->id() == 0, "invariant"); + entry->set_id(AtomicAccess::fetch_then_add(&_id, static_cast(1))); +} + +template class TableEntry> +inline bool JfrConcurrentAscendingId::on_equals(unsigned hash, const TableEntry* entry) { + assert(entry != nullptr, "invariant"); + assert(entry->hash() == hash, "invariant"); + return true; +} + +template class TableEntry> +inline JfrConcurrentHashtable::JfrConcurrentHashtable(unsigned initial_capacity) : + _buckets(nullptr), _capacity(initial_capacity), _mask(initial_capacity - 1), _size(0) { + assert(initial_capacity >= 2, "invariant"); + assert(is_power_of_2(initial_capacity), "invariant"); + _buckets = NEW_C_HEAP_ARRAY2(Bucket, initial_capacity, mtTracing, CURRENT_PC); + memset((void*)_buckets, 0, initial_capacity * sizeof(Bucket)); +} + +template class TableEntry> +inline JfrConcurrentHashtable::~JfrConcurrentHashtable() { + FREE_C_HEAP_ARRAY(Bucket, _buckets); +} + +template class TableEntry> +inline unsigned JfrConcurrentHashtable::size() const { + return AtomicAccess::load(&_size); +} + +template class TableEntry> +template +inline void JfrConcurrentHashtable::iterate(unsigned idx, Callback& cb) { + assert(idx < _capacity, "invariant"); + bucket(idx).iterate(cb); +} + +template class TableEntry> +template +inline void JfrConcurrentHashtable::iterate(Callback& cb) { + for (unsigned i = 0; i < _capacity; ++i) { + iterate(i, cb); + } +} + +template class TableEntry> +template +inline void JfrConcurrentHashtable::iterate(TableEntry* entry, Callback& cb) { + Bucket::iterate(entry, cb); +} + +template class TableEntry> +inline bool JfrConcurrentHashtable::try_add(unsigned idx, TableEntry* entry, TableEntry* next) { + assert(entry != nullptr, "invariant"); + entry->set_next(next); + const bool added = bucket(idx).try_add(entry, next); + if (added) { + AtomicAccess::inc(&_size); + } + return added; +} + +template class TableEntry> +inline void JfrConcurrentHashtable::unlink_entry(TableEntry* entry) { + AtomicAccess::dec(&_size); +} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline JfrConcurrentHashTableHost::JfrConcurrentHashTableHost(unsigned initial_capacity /* 0 */) : + JfrConcurrentHashtable(initial_capacity == 0 ? TABLE_CAPACITY : initial_capacity), _callback(new Callback()) {} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline JfrConcurrentHashTableHost::JfrConcurrentHashTableHost(Callback* cb, unsigned initial_capacity /* 0 */) : + JfrConcurrentHashtable(initial_capacity == 0 ? TABLE_CAPACITY : initial_capacity), _callback(cb) {} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline bool JfrConcurrentHashTableHost::is_empty() const { + return this->size() == 0; +} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline TableEntry* JfrConcurrentHashTableHost::new_entry(unsigned hash, const T& data) { + Entry* const entry = new Entry(hash, data); + assert(entry != nullptr, "invariant"); + assert(0 == entry->id(), "invariant"); + _callback->on_link(entry); + assert(0 != entry->id(), "invariant"); + return entry; +} + +template +class JfrConcurrentHashtableLookup { + private: + Callback* const _cb; + const T& _data; + Entry* _found; + unsigned _hash; + public: + JfrConcurrentHashtableLookup(unsigned hash, const T& data, Callback* cb) : _cb(cb), _data(data), _found(nullptr), _hash(hash) {} + + bool process(Entry* entry) { + assert(entry != nullptr, "invariant"); + if (entry->hash() == _hash && entry->on_equals(_data)) { + _found = entry; + return false; + } + return true; + } + + bool found() const { return _found != nullptr; } + Entry* result() const { return _found; } +}; + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline TableEntry* JfrConcurrentHashTableHost::lookup_put(unsigned hash, const T& data) { + JfrConcurrentHashtableLookup lookup(hash, data, _callback); + const unsigned idx = this->index(hash); + Entry* entry = nullptr; + while (true) { + assert(!lookup.found(), "invariant"); + Entry* next = this->head(idx); + if (next != nullptr) { + JfrConcurrentHashtable::iterate(next, lookup); + if (lookup.found()) { + if (entry != nullptr) { + _callback->on_unlink(entry); + delete entry; + } + entry = lookup.result(); + break; + } + } + if (entry == nullptr) { + entry = new_entry(hash, data); + } + assert(entry != nullptr, "invariant"); + if (this->try_add(idx, entry, next)) { + break; + } + // Concurrent insertion to this bucket. Retry. + } + assert(entry != nullptr, "invariant"); + return entry; +} + +// id retrieval +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline IdType JfrConcurrentHashTableHost::id(unsigned hash, const T& data) { + assert(data != nullptr, "invariant"); + const Entry* const entry = lookup_put(hash, data); + assert(entry != nullptr, "invariant"); + assert(entry->id() > 0, "invariant"); + return entry->id(); +} + +template +class JfrConcurrentHashtableClear { + private: + Callback* const _cb; + public: + JfrConcurrentHashtableClear(Callback* cb) : _cb(cb) {} + + bool process(const Entry* entry) { + assert(entry != nullptr, "invariant"); + _cb->on_unlink(entry); + delete entry; + return true; + } +}; + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +inline JfrConcurrentHashTableHost::~JfrConcurrentHashTableHost() { + JfrConcurrentHashtableClear cls(_callback); + this->iterate(cls); +} + +template +class JfrConcurrentHashtableValueDelegator { + private: + Functor& _f; + public: + JfrConcurrentHashtableValueDelegator(Functor& f) : _f(f) {} + bool process(const Entry* entry) { + assert(entry != nullptr, "invariant"); + return _f(entry->value()); + } +}; + +template +class JfrConcurrentHashtableEntryDelegator { + private: + Functor& _f; + public: + JfrConcurrentHashtableEntryDelegator(Functor& f) : _f(f) {} + bool process(const Entry* entry) { + assert(entry != nullptr, "invariant"); + return _f(entry); + } +}; + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +template +inline void JfrConcurrentHashTableHost::iterate_value(Functor& f) { + JfrConcurrentHashtableValueDelegator delegator(f); + this->iterate(delegator); +} + +template class TableEntry, typename Callback, unsigned TABLE_CAPACITY> +template +inline void JfrConcurrentHashTableHost::iterate_entry(Functor& f) { + JfrConcurrentHashtableEntryDelegator delegator(f); + this->iterate(delegator); +} + +#endif // SHARE_JFR_UTILITIES_JFRCONCURRENTHASHTABLE_INLINE_HPP diff --git a/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp b/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp index 96e3acc0daa..a0d18bd383c 100644 --- a/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp +++ b/src/hotspot/share/jfr/utilities/jfrLinkedList.hpp @@ -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 @@ -43,10 +43,13 @@ class JfrLinkedList : public AllocPolicy { bool is_empty() const; bool is_nonempty() const; void add(NodePtr node); + bool try_add(NodePtr node, NodePtr next); void add_list(NodePtr first); NodePtr remove(); template void iterate(Callback& cb); + template + static void iterate(NodePtr node, Callback& cb); NodePtr head() const; NodePtr excise(NodePtr prev, NodePtr node); bool in_list(const NodeType* node) const; diff --git a/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp b/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp index fed379672dc..f481caa6528 100644 --- a/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp +++ b/src/hotspot/share/jfr/utilities/jfrLinkedList.inline.hpp @@ -30,10 +30,10 @@ #include "runtime/atomicAccess.hpp" template -JfrLinkedList::JfrLinkedList() : _head(nullptr) {} +inline JfrLinkedList::JfrLinkedList() : _head(nullptr) {} template -bool JfrLinkedList::initialize() { +inline bool JfrLinkedList::initialize() { return true; } @@ -62,6 +62,13 @@ inline void JfrLinkedList::add(NodeType* node) { } while (AtomicAccess::cmpxchg(&_head, next, node) != next); } +template +inline bool JfrLinkedList::try_add(NodeType* node, NodeType* next) { + assert(node != nullptr, "invariant"); + assert(node->_next == next, "invariant"); + return head() == next && AtomicAccess::cmpxchg(&_head, next, node) == next; +} + template inline NodeType* JfrLinkedList::remove() { NodePtr node; @@ -76,19 +83,24 @@ inline NodeType* JfrLinkedList::remove() { template template -void JfrLinkedList::iterate(Callback& cb) { - NodePtr current = head(); - while (current != nullptr) { - NodePtr next = (NodePtr)current->_next; - if (!cb.process(current)) { +inline void JfrLinkedList::iterate(Callback& cb) { + JfrLinkedList::iterate(head(), cb); +} + +template +template +inline void JfrLinkedList::iterate(NodeType* node, Callback& cb) { + while (node != nullptr) { + NodePtr next = (NodePtr)node->_next; + if (!cb.process(node)) { return; } - current = next; + node = next; } } template -NodeType* JfrLinkedList::excise(NodeType* prev, NodeType* node) { +inline NodeType* JfrLinkedList::excise(NodeType* prev, NodeType* node) { NodePtr next = (NodePtr)node->_next; if (prev == nullptr) { prev = AtomicAccess::cmpxchg(&_head, node, next); @@ -106,7 +118,7 @@ NodeType* JfrLinkedList::excise(NodeType* prev, NodeType* } template -bool JfrLinkedList::in_list(const NodeType* node) const { +inline bool JfrLinkedList::in_list(const NodeType* node) const { assert(node != nullptr, "invariant"); const NodeType* current = head(); while (current != nullptr) { @@ -119,7 +131,7 @@ bool JfrLinkedList::in_list(const NodeType* node) const { } template -NodeType* JfrLinkedList::cut() { +inline NodeType* JfrLinkedList::cut() { NodePtr node; do { node = head(); @@ -128,7 +140,7 @@ NodeType* JfrLinkedList::cut() { } template -void JfrLinkedList::clear() { +inline void JfrLinkedList::clear() { cut(); } diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index b30ec2f4887..772541cdd10 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -57,6 +57,10 @@ #include "utilities/rotate_bits.hpp" #include "utilities/stack.inline.hpp" +#if INCLUDE_JFR +#include "jfr/jfr.hpp" +#endif + void Klass::set_java_mirror(Handle m) { assert(!m.is_null(), "New mirror should never be null."); assert(_java_mirror.is_empty(), "should only be used to initialize mirror"); @@ -862,7 +866,6 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec assert(is_klass(), "ensure C++ vtable is restored"); assert(in_aot_cache(), "must be set"); assert(secondary_supers()->length() >= (int)population_count(_secondary_supers_bitmap), "must be"); - JFR_ONLY(RESTORE_ID(this);) if (log_is_enabled(Trace, aot, unshareable)) { ResourceMark rm(THREAD); oop class_loader = loader_data->class_loader(); @@ -876,10 +879,13 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec if (class_loader_data() == nullptr) { set_class_loader_data(loader_data); } + // Add to class loader list first before creating the mirror // (same order as class file parsing) loader_data->add_class(this); + JFR_ONLY(Jfr::on_restoration(this, THREAD);) + Handle loader(THREAD, loader_data->class_loader()); ModuleEntry* module_entry = nullptr; Klass* k = this; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini index 91decb1aa20..5d72a9f85dc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/view.ini @@ -110,6 +110,15 @@ table = "COLUMN 'Time', 'Requested By', 'Operation', 'Classes' GROUP BY redefinitionId ORDER BY duration DESC" +[jvm.classes-by-source] + label = "Classes by Source" + table = "COLUMN 'Source', 'Count' + FORMAT truncate-beginning, none + SELECT source, COUNT(*) AS C + FROM jdk.ClassDefine + GROUP BY source + ORDER BY C DESC" + [jvm.compiler-configuration] label = "Compiler Configuration" form = "SELECT LAST(threadCount), LAST(dynamicCompilerThreadCount), LAST(tieredCompilation) diff --git a/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java b/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java index b0522741a1e..74fb8e71e87 100644 --- a/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java +++ b/test/jdk/jdk/jfr/event/runtime/TestClassDefineEvent.java @@ -70,6 +70,8 @@ public final class TestClassDefineEvent { "Expected type " + cl.getClass().getName() + ", got type " + definingClassLoaderType.getName()); Asserts.assertEquals(cl.getName(), definingClassLoader.getName(), "Defining Class Loader should have the same name as the original class loader"); + Asserts.assertTrue(event.getString("source").startsWith("file:/"), "Invalid source location"); + Asserts.assertTrue(event.getString("source").endsWith(TEST_CLASS_NAME.substring(TEST_CLASS_NAME.lastIndexOf('.') + 1) + ".class"), "Invalid source location"); foundTestClasses = true; } } From aff25f135af20ec89c7a68f2a0a0ede7eb1491a6 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 3 Dec 2025 18:20:31 +0000 Subject: [PATCH 034/141] 4690476: NegativeArraySizeException from AffineTransformOp with shear Reviewed-by: psadhukhan, jdv --- .../java/awt/image/AffineTransformOp.java | 82 ++++++++++++++++--- .../AffineTransformOp/AffineTxOpSizeTest.java | 68 +++++++++++++++ 2 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java diff --git a/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java b/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java index 4c4179699f0..7a3ee8646a7 100644 --- a/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java +++ b/src/java.desktop/share/classes/java/awt/image/AffineTransformOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, 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 @@ -186,7 +186,13 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { * {@code getBounds2D(BufferedImage)} * are not necessarily the same as the coordinates of the * {@code BufferedImage} returned by this method. If the - * upper-left corner coordinates of the rectangle are + * application provides a {@code dst} that is always returned. + * If {@code dst} is {@code null} and a destination {code BufferedImage} + * with the transformed dimensions cannot be created, the {@code src} + * dimensions will be substituted. + * + *

    + * If the upper-left corner coordinates of the rectangle are * negative then this part of the rectangle is not drawn. If the * upper-left corner coordinates of the rectangle are positive * then the filtered image is drawn at that position in the @@ -224,7 +230,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { BufferedImage origDst = dst; if (dst == null) { - dst = createCompatibleDestImage(src, null); + dst = createCompatibleDestImageInt(src, null); dstCM = srcCM; origDst = dst; } @@ -272,7 +278,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { } else { needToConvert = true; - dst = createCompatibleDestImage(src, null); + dst = createCompatibleDestImageInt(src, null); } } @@ -320,7 +326,12 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { * {@code getBounds2D(Raster)} * are not necessarily the same as the coordinates of the * {@code WritableRaster} returned by this method. If the - * upper-left corner coordinates of rectangle are negative then + * application provides a {@code dst} that is always returned. + * If {@code dst} is {@code null} and a destination {code Raster} + * with the transformed dimensions cannot be created, the {@code src} + * dimensions will be substituted. + *

    + * If the upper-left corner coordinates of rectangle are negative then * this part of the rectangle is not drawn. If the coordinates * of the rectangle are positive then the filtered image is drawn at * that position in the destination {@code Raster}. @@ -342,7 +353,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { throw new NullPointerException("src image is null"); } if (dst == null) { - dst = createCompatibleDestRaster(src); + dst = createCompatibleDestRasterInt(src); } if (src == dst) { throw new IllegalArgumentException("src image cannot be the "+ @@ -422,7 +433,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Creates a zeroed destination image with the correct size and number of * bands. A {@code RasterFormatException} may be thrown if the - * transformed width or height is equal to 0. + * transformed width or height is less than or equal to 0, or too large. *

    * If {@code destCM} is null, * an appropriate {@code ColorModel} is used; this @@ -437,9 +448,36 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { */ public BufferedImage createCompatibleDestImage (BufferedImage src, ColorModel destCM) { - BufferedImage image; Rectangle r = getBounds2D(src).getBounds(); + try { + return createCompatibleDestImage(src, destCM, r); + } catch (Exception e) { + if (e instanceof RasterFormatException) { + throw e; + } else { + RasterFormatException re = + new RasterFormatException("Could not create transformed image of size " + r); + re.initCause(e); + throw re; + } + } + } + private BufferedImage createCompatibleDestImageInt(BufferedImage src, + ColorModel destCM) { + + try { + return createCompatibleDestImage(src, destCM); + } catch (Exception e) { + return createCompatibleDestImage(src, destCM, src.getRaster().getBounds()); + } + } + + private BufferedImage createCompatibleDestImage(BufferedImage src, + ColorModel destCM, + Rectangle r) { + + BufferedImage image; // If r.x (or r.y) is < 0, then we want to only create an image // that is in the positive range. // If r.x (or r.y) is > 0, then we need to create an image that @@ -482,14 +520,38 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp { /** * Creates a zeroed destination {@code Raster} with the correct size * and number of bands. A {@code RasterFormatException} may be thrown - * if the transformed width or height is equal to 0. + * if the transformed width or height is less than or equal to 0, or too large. * * @param src The {@code Raster} to be transformed. * * @return The zeroed destination {@code Raster}. */ public WritableRaster createCompatibleDestRaster (Raster src) { - Rectangle2D r = getBounds2D(src); + Rectangle r = getBounds2D(src).getBounds(); + try { + return createCompatibleDestRaster(src, r); + } catch (Exception e) { + if (e instanceof RasterFormatException) { + throw e; + } else { + RasterFormatException re = + new RasterFormatException("Could not create transformed raster of size " + r); + re.initCause(e); + throw re; + } + } + } + + private WritableRaster createCompatibleDestRasterInt(Raster src) { + try { + return createCompatibleDestRaster(src); + } catch (Exception e) { + Rectangle r = src.getBounds(); + return createCompatibleDestRaster(src, r); + } + } + + private WritableRaster createCompatibleDestRaster (Raster src, Rectangle r) { return src.createCompatibleWritableRaster((int)r.getX(), (int)r.getY(), diff --git a/test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java b/test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java new file mode 100644 index 00000000000..86f0c1030d6 --- /dev/null +++ b/test/jdk/java/awt/image/AffineTransformOp/AffineTxOpSizeTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 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 + * @bug 4690476 + * @summary Verify behaviour with transform which creates too large an image. + */ + +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import static java.awt.image.AffineTransformOp.*; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.awt.image.RasterFormatException; + +public class AffineTxOpSizeTest { + + static final int W = 2552, H = 3300; + // This transform will require an approx 60_000 x 60_000 raster which is too large + static final AffineTransform AT = new AffineTransform(0.2, 23, 18, 0.24, -70.0, -90.0); + + public static void main(String[] args) { + BufferedImage src = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); + testAOP(src, TYPE_BICUBIC); + testAOP(src, TYPE_BILINEAR); + testAOP(src, TYPE_NEAREST_NEIGHBOR); + } + + static void testAOP(BufferedImage src, int iType) { + AffineTransformOp aop = new AffineTransformOp(AT, iType); + System.out.println("Bounds=" + aop.getBounds2D(src)); + + aop.filter(src, null); + aop.filter(src.getRaster(), null); + try { + aop.createCompatibleDestImage(src, src.getColorModel()); + throw new RuntimeException("No exception for image"); + } catch (RasterFormatException e) { + } + try { + aop.createCompatibleDestRaster(src.getRaster()); + throw new RuntimeException("No exception for raster"); + } catch (RasterFormatException e) { + } + } + +} From 8a5db916aff1dc3eb37f25afbf0a633aa77baa20 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 3 Dec 2025 19:58:28 +0000 Subject: [PATCH 035/141] 8171432: (fs) WindowsWatchService.Poller::run does not call ReadDirectoryChangesW after a ERROR_NOTIFY_ENUM_DIR Reviewed-by: alanb, djelinski --- .../sun/nio/fs/WindowsWatchService.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java b/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java index d051c833ee7..cd7cc38550c 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -610,23 +610,24 @@ class WindowsWatchService boolean criticalError = false; int errorCode = info.error(); int messageSize = info.bytesTransferred(); - if (errorCode == ERROR_NOTIFY_ENUM_DIR) { - // buffer overflow - key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); - } else if (errorCode != 0 && errorCode != ERROR_MORE_DATA) { + if (errorCode != 0 && + errorCode != ERROR_MORE_DATA && + errorCode != ERROR_NOTIFY_ENUM_DIR) { // ReadDirectoryChangesW failed criticalError = true; } else { // ERROR_MORE_DATA is a warning about incomplete // data transfer over TCP/UDP stack. For the case - // [messageSize] is zero in the most of cases. + // [messageSize] is zero in most cases. if (messageSize > 0) { // process non-empty events. processEvents(key, messageSize); - } else if (errorCode == 0) { - // insufficient buffer size - // not described, but can happen. + } else if (errorCode == 0 || + errorCode == ERROR_NOTIFY_ENUM_DIR) { + // errorCode == 0: insufficient buffer size; + // not described, but can happen. + // errorCode == ERROR_NOTIFY_ENUM_DIR: buffer overflow key.signalEvent(StandardWatchEventKinds.OVERFLOW, null); } From ba777f6610fa3744d5f4bdfb87066b137ab543af Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 3 Dec 2025 19:58:53 +0000 Subject: [PATCH 036/141] 8372851: Modify java/io/File/GetXSpace.java to print path on failure of native call Reviewed-by: jpai, naoto --- test/jdk/java/io/File/GetXSpace.java | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/test/jdk/java/io/File/GetXSpace.java b/test/jdk/java/io/File/GetXSpace.java index e61880edb2c..96ce4ede1b2 100644 --- a/test/jdk/java/io/File/GetXSpace.java +++ b/test/jdk/java/io/File/GetXSpace.java @@ -106,7 +106,7 @@ public class GetXSpace { Space(String name) { this.name = name; long[] sizes = new long[4]; - if (Platform.isWindows() & isCDDrive(name)) { + if (Platform.isWindows() && isCDDrive(name)) { try { getCDDriveSpace(name, sizes); } catch (IOException e) { @@ -114,7 +114,7 @@ public class GetXSpace { throw new RuntimeException("can't get CDDrive sizes"); } } else { - if (getSpace0(name, sizes)) + if (getSpace(name, sizes)) System.err.println("WARNING: total space is estimated"); } this.size = sizes[0]; @@ -184,7 +184,7 @@ public class GetXSpace { out.format("%s (%d):%n", s.name(), s.size()); String fmt = " %-4s total = %12d free = %12d usable = %12d%n"; - String method = Platform.isWindows() & isCDDrive(s.name()) ? "getCDDriveSpace" : "getSpace0"; + String method = Platform.isWindows() && isCDDrive(s.name()) ? "getCDDriveSpace" : "getSpace"; out.format(fmt, method, s.total(), s.free(), s.available()); out.format(fmt, "getXSpace", ts, fs, us); @@ -336,7 +336,7 @@ public class GetXSpace { private static int testVolumes() { out.println("--- Testing volumes"); // Find all of the partitions on the machine and verify that the sizes - // returned by File::getXSpace are equivalent to those from getSpace0 or getCDDriveSpace + // returned by File::getXSpace are equivalent to those from getSpace or getCDDriveSpace ArrayList l; try { l = paths(); @@ -412,6 +412,19 @@ public class GetXSpace { private static native boolean isCDDrive(String root); + private static boolean getSpace(String root, long[] space) { + try { + return getSpace0(root, space); + } catch (RuntimeException e) { + File f = new File(root); + boolean exists = f.exists(); + boolean readable = f.canRead(); + System.err.printf("getSpace0 failed for %s (%s, %s)%n", + root, exists, readable); + throw e; + } + } + private static void getCDDriveSpace(String root, long[] sizes) throws IOException { String[] cmd = new String[] {"df", "-k", "-P", root}; From e534ee99327fed2263302a00061fb46fcdc6e302 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Wed, 3 Dec 2025 20:01:45 +0000 Subject: [PATCH 037/141] 8364343: Virtual Thread transition management needs to be independent of JVM TI Co-authored-by: Alan Bateman Reviewed-by: coleenp, dholmes, sspitsyn --- src/hotspot/share/classfile/javaClasses.cpp | 44 +- src/hotspot/share/classfile/javaClasses.hpp | 23 +- src/hotspot/share/classfile/vmIntrinsics.hpp | 8 +- src/hotspot/share/classfile/vmSymbols.hpp | 12 +- src/hotspot/share/code/aotCodeCache.cpp | 10 +- src/hotspot/share/include/jvm.h | 8 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 11 +- src/hotspot/share/opto/c2compiler.cpp | 8 +- src/hotspot/share/opto/library_call.cpp | 109 ++-- src/hotspot/share/opto/library_call.hpp | 6 +- src/hotspot/share/opto/runtime.cpp | 56 +-- src/hotspot/share/opto/runtime.hpp | 53 +- src/hotspot/share/prims/jvm.cpp | 70 +-- src/hotspot/share/prims/jvmtiEnv.cpp | 77 +-- src/hotspot/share/prims/jvmtiEnvBase.cpp | 30 +- src/hotspot/share/prims/jvmtiExport.cpp | 11 +- src/hotspot/share/prims/jvmtiExtensions.cpp | 5 +- src/hotspot/share/prims/jvmtiTagMap.cpp | 7 +- src/hotspot/share/prims/jvmtiThreadState.cpp | 473 ------------------ src/hotspot/share/prims/jvmtiThreadState.hpp | 61 --- src/hotspot/share/runtime/continuation.cpp | 63 +-- .../share/runtime/continuationFreezeThaw.cpp | 19 +- src/hotspot/share/runtime/handshake.cpp | 22 + src/hotspot/share/runtime/handshake.hpp | 1 + src/hotspot/share/runtime/javaThread.cpp | 39 +- src/hotspot/share/runtime/javaThread.hpp | 35 +- .../share/runtime/mountUnmountDisabler.cpp | 450 +++++++++++++++++ .../share/runtime/mountUnmountDisabler.hpp | 92 ++++ src/hotspot/share/runtime/mutexLocker.cpp | 8 +- src/hotspot/share/runtime/mutexLocker.hpp | 2 +- src/hotspot/share/runtime/sharedRuntime.cpp | 28 -- src/hotspot/share/runtime/sharedRuntime.hpp | 8 - .../share/runtime/stubDeclarations.hpp | 27 +- src/hotspot/share/runtime/stubInfo.cpp | 11 +- src/hotspot/share/runtime/stubInfo.hpp | 19 +- .../share/runtime/suspendResumeManager.cpp | 3 +- src/hotspot/share/services/threadService.cpp | 70 +-- .../classes/java/lang/VirtualThread.java | 39 +- .../share/native/libjava/VirtualThread.c | 8 +- .../DumpThreadsWhenParking.java | 159 ++++++ .../DumpThreadsWithEliminatedLock.java | 4 + 41 files changed, 1140 insertions(+), 1049 deletions(-) create mode 100644 src/hotspot/share/runtime/mountUnmountDisabler.cpp create mode 100644 src/hotspot/share/runtime/mountUnmountDisabler.hpp create mode 100644 test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index ee80dbbc45c..614a0199beb 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1684,8 +1684,8 @@ int java_lang_Thread::_name_offset; int java_lang_Thread::_contextClassLoader_offset; int java_lang_Thread::_eetop_offset; int java_lang_Thread::_jvmti_thread_state_offset; -int java_lang_Thread::_jvmti_VTMS_transition_disable_count_offset; -int java_lang_Thread::_jvmti_is_in_VTMS_transition_offset; +int java_lang_Thread::_vthread_transition_disable_count_offset; +int java_lang_Thread::_is_in_vthread_transition_offset; int java_lang_Thread::_interrupted_offset; int java_lang_Thread::_interruptLock_offset; int java_lang_Thread::_tid_offset; @@ -1745,34 +1745,34 @@ void java_lang_Thread::set_jvmti_thread_state(oop java_thread, JvmtiThreadState* java_thread->address_field_put(_jvmti_thread_state_offset, (address)state); } -int java_lang_Thread::VTMS_transition_disable_count(oop java_thread) { - return java_thread->int_field(_jvmti_VTMS_transition_disable_count_offset); +int java_lang_Thread::vthread_transition_disable_count(oop java_thread) { + jint* addr = java_thread->field_addr(_vthread_transition_disable_count_offset); + return AtomicAccess::load(addr); } -void java_lang_Thread::inc_VTMS_transition_disable_count(oop java_thread) { - assert(JvmtiVTMSTransition_lock->owned_by_self(), "Must be locked"); - int val = VTMS_transition_disable_count(java_thread); - java_thread->int_field_put(_jvmti_VTMS_transition_disable_count_offset, val + 1); +void java_lang_Thread::inc_vthread_transition_disable_count(oop java_thread) { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + jint* addr = java_thread->field_addr(_vthread_transition_disable_count_offset); + int val = AtomicAccess::load(addr); + AtomicAccess::store(addr, val + 1); } -void java_lang_Thread::dec_VTMS_transition_disable_count(oop java_thread) { - assert(JvmtiVTMSTransition_lock->owned_by_self(), "Must be locked"); - int val = VTMS_transition_disable_count(java_thread); - assert(val > 0, "VTMS_transition_disable_count should never be negative"); - java_thread->int_field_put(_jvmti_VTMS_transition_disable_count_offset, val - 1); +void java_lang_Thread::dec_vthread_transition_disable_count(oop java_thread) { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + jint* addr = java_thread->field_addr(_vthread_transition_disable_count_offset); + int val = AtomicAccess::load(addr); + AtomicAccess::store(addr, val - 1); } -bool java_lang_Thread::is_in_VTMS_transition(oop java_thread) { - return java_thread->bool_field_volatile(_jvmti_is_in_VTMS_transition_offset); +bool java_lang_Thread::is_in_vthread_transition(oop java_thread) { + jboolean* addr = java_thread->field_addr(_is_in_vthread_transition_offset); + return AtomicAccess::load(addr); } -void java_lang_Thread::set_is_in_VTMS_transition(oop java_thread, bool val) { - assert(is_in_VTMS_transition(java_thread) != val, "already %s transition", val ? "inside" : "outside"); - java_thread->bool_field_put_volatile(_jvmti_is_in_VTMS_transition_offset, val); -} - -int java_lang_Thread::is_in_VTMS_transition_offset() { - return _jvmti_is_in_VTMS_transition_offset; +void java_lang_Thread::set_is_in_vthread_transition(oop java_thread, bool val) { + assert(is_in_vthread_transition(java_thread) != val, "already %s transition", val ? "inside" : "outside"); + jboolean* addr = java_thread->field_addr(_is_in_vthread_transition_offset); + AtomicAccess::store(addr, (jboolean)val); } void java_lang_Thread::clear_scopedValueBindings(oop java_thread) { diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 699dd39b887..33dc912404c 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -375,8 +375,8 @@ class java_lang_Class : AllStatic { #define THREAD_INJECTED_FIELDS(macro) \ macro(java_lang_Thread, jvmti_thread_state, intptr_signature, false) \ - macro(java_lang_Thread, jvmti_VTMS_transition_disable_count, int_signature, false) \ - macro(java_lang_Thread, jvmti_is_in_VTMS_transition, bool_signature, false) \ + macro(java_lang_Thread, vthread_transition_disable_count, int_signature, false) \ + macro(java_lang_Thread, is_in_vthread_transition, bool_signature, false) \ JFR_ONLY(macro(java_lang_Thread, jfr_epoch, short_signature, false)) class java_lang_Thread : AllStatic { @@ -390,8 +390,8 @@ class java_lang_Thread : AllStatic { static int _contextClassLoader_offset; static int _eetop_offset; static int _jvmti_thread_state_offset; - static int _jvmti_VTMS_transition_disable_count_offset; - static int _jvmti_is_in_VTMS_transition_offset; + static int _vthread_transition_disable_count_offset; + static int _is_in_vthread_transition_offset; static int _interrupted_offset; static int _interruptLock_offset; static int _tid_offset; @@ -444,12 +444,15 @@ class java_lang_Thread : AllStatic { static JvmtiThreadState* jvmti_thread_state(oop java_thread); static void set_jvmti_thread_state(oop java_thread, JvmtiThreadState* state); - static int VTMS_transition_disable_count(oop java_thread); - static void inc_VTMS_transition_disable_count(oop java_thread); - static void dec_VTMS_transition_disable_count(oop java_thread); - static bool is_in_VTMS_transition(oop java_thread); - static void set_is_in_VTMS_transition(oop java_thread, bool val); - static int is_in_VTMS_transition_offset(); + + static int vthread_transition_disable_count(oop java_thread); + static void inc_vthread_transition_disable_count(oop java_thread); + static void dec_vthread_transition_disable_count(oop java_thread); + static int vthread_transition_disable_count_offset() { return _vthread_transition_disable_count_offset; } + + static bool is_in_vthread_transition(oop java_thread); + static void set_is_in_vthread_transition(oop java_thread, bool val); + static int is_in_vthread_transition_offset() { return _is_in_vthread_transition_offset; } // Clear all scoped value bindings on error static void clear_scopedValueBindings(oop java_thread); diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 0895418ef84..6f9c2326a45 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -649,10 +649,10 @@ class methodHandle; do_intrinsic(_Continuation_unpin, jdk_internal_vm_Continuation, unpin_name, void_method_signature, F_SN) \ \ /* java/lang/VirtualThread */ \ - do_intrinsic(_notifyJvmtiVThreadStart, java_lang_VirtualThread, notifyJvmtiStart_name, void_method_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadEnd, java_lang_VirtualThread, notifyJvmtiEnd_name, void_method_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN) \ - do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \ + do_intrinsic(_vthreadEndFirstTransition, java_lang_VirtualThread, endFirstTransition_name, void_method_signature, F_RN) \ + do_intrinsic(_vthreadStartFinalTransition, java_lang_VirtualThread, startFinalTransition_name, void_method_signature, F_RN) \ + do_intrinsic(_vthreadStartTransition, java_lang_VirtualThread, startTransition_name, bool_void_signature, F_RN) \ + do_intrinsic(_vthreadEndTransition, java_lang_VirtualThread, endTransition_name, bool_void_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadDisableSuspend, java_lang_VirtualThread, notifyJvmtiDisableSuspend_name, bool_void_signature, F_SN) \ \ /* support for UnsafeConstants */ \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index d22700b8d1f..8388b98faae 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -395,10 +395,10 @@ class SerializeClosure; template(run_finalization_name, "runFinalization") \ template(dispatchUncaughtException_name, "dispatchUncaughtException") \ template(loadClass_name, "loadClass") \ - template(notifyJvmtiStart_name, "notifyJvmtiStart") \ - template(notifyJvmtiEnd_name, "notifyJvmtiEnd") \ - template(notifyJvmtiMount_name, "notifyJvmtiMount") \ - template(notifyJvmtiUnmount_name, "notifyJvmtiUnmount") \ + template(startTransition_name, "startTransition") \ + template(endTransition_name, "endTransition") \ + template(startFinalTransition_name, "startFinalTransition") \ + template(endFirstTransition_name, "endFirstTransition") \ template(notifyJvmtiDisableSuspend_name, "notifyJvmtiDisableSuspend") \ template(doYield_name, "doYield") \ template(enter_name, "enter") \ @@ -497,8 +497,8 @@ class SerializeClosure; template(java_lang_Boolean_signature, "Ljava/lang/Boolean;") \ template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \ template(jvmti_thread_state_name, "jvmti_thread_state") \ - template(jvmti_VTMS_transition_disable_count_name, "jvmti_VTMS_transition_disable_count") \ - template(jvmti_is_in_VTMS_transition_name, "jvmti_is_in_VTMS_transition") \ + template(vthread_transition_disable_count_name, "vthread_transition_disable_count") \ + template(is_in_vthread_transition_name, "is_in_vthread_transition") \ template(module_entry_name, "module_entry") \ template(resolved_references_name, "") \ template(init_lock_name, "") \ diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index 04776f4c16c..0314c5227d2 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -1346,18 +1346,16 @@ void AOTCodeAddressTable::init_extrs() { SET_ADDRESS(_extrs, OptoRuntime::multianewarray4_C); SET_ADDRESS(_extrs, OptoRuntime::multianewarray5_C); SET_ADDRESS(_extrs, OptoRuntime::multianewarrayN_C); -#if INCLUDE_JVMTI - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_start); - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_end); - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_mount); - SET_ADDRESS(_extrs, SharedRuntime::notify_jvmti_vthread_unmount); -#endif SET_ADDRESS(_extrs, OptoRuntime::complete_monitor_locking_C); SET_ADDRESS(_extrs, OptoRuntime::monitor_notify_C); SET_ADDRESS(_extrs, OptoRuntime::monitor_notifyAll_C); SET_ADDRESS(_extrs, OptoRuntime::rethrow_C); SET_ADDRESS(_extrs, OptoRuntime::slow_arraycopy_C); SET_ADDRESS(_extrs, OptoRuntime::register_finalizer_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_end_first_transition_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_start_final_transition_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_start_transition_C); + SET_ADDRESS(_extrs, OptoRuntime::vthread_end_transition_C); #if defined(AARCH64) SET_ADDRESS(_extrs, JavaThread::verify_cross_modify_fence_failure); #endif // AARCH64 diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index ce76a95fda7..dccdcacef71 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1100,16 +1100,16 @@ JVM_GetEnclosingMethodInfo(JNIEnv* env, jclass ofClass); * Virtual thread support. */ JNIEXPORT void JNICALL -JVM_VirtualThreadStart(JNIEnv* env, jobject vthread); +JVM_VirtualThreadEndFirstTransition(JNIEnv* env, jobject vthread); JNIEXPORT void JNICALL -JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread); +JVM_VirtualThreadStartFinalTransition(JNIEnv* env, jobject vthread); JNIEXPORT void JNICALL -JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide); +JVM_VirtualThreadStartTransition(JNIEnv* env, jobject vthread, jboolean is_mount); JNIEXPORT void JNICALL -JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide); +JVM_VirtualThreadEndTransition(JNIEnv* env, jobject vthread, jboolean is_mount); JNIEXPORT void JNICALL JVM_VirtualThreadDisableSuspend(JNIEnv* env, jclass clazz, jboolean enter); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 7ef16f6e32c..7f009eba5f1 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -37,6 +37,7 @@ #include "runtime/continuationEntry.hpp" #include "runtime/deoptimization.hpp" #include "runtime/flags/jvmFlag.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/osThread.hpp" #include "runtime/sharedRuntime.hpp" @@ -259,13 +260,13 @@ nonstatic_field(JavaThread, _om_cache, OMCache) \ nonstatic_field(JavaThread, _cont_entry, ContinuationEntry*) \ nonstatic_field(JavaThread, _unlocked_inflated_monitor, ObjectMonitor*) \ - JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \ + nonstatic_field(JavaThread, _is_in_vthread_transition, bool) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \ \ nonstatic_field(ContinuationEntry, _pin_count, uint32_t) \ nonstatic_field(LockStack, _top, uint32_t) \ \ - JVMTI_ONLY(static_field(JvmtiVTMSTransitionDisabler, _VTMS_notify_jvmti_events, bool)) \ + static_field(MountUnmountDisabler, _notify_jvmti_events, bool) \ \ static_field(java_lang_Class, _klass_offset, int) \ static_field(java_lang_Class, _array_klass_offset, int) \ @@ -435,7 +436,7 @@ JFR_ONLY(nonstatic_field(Thread, _jfr_thread_local, JfrThreadLocal)) \ \ static_field(java_lang_Thread, _tid_offset, int) \ - static_field(java_lang_Thread, _jvmti_is_in_VTMS_transition_offset, int) \ + static_field(java_lang_Thread, _is_in_vthread_transition_offset, int) \ JFR_ONLY(static_field(java_lang_Thread, _jfr_epoch_offset, int)) \ \ JFR_ONLY(nonstatic_field(JfrThreadLocal, _vthread_id, traceid)) \ @@ -877,10 +878,6 @@ declare_function(SharedRuntime::enable_stack_reserved_zone) \ declare_function(SharedRuntime::frem) \ declare_function(SharedRuntime::drem) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_start)) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_end)) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_mount)) \ - JVMTI_ONLY(declare_function(SharedRuntime::notify_jvmti_vthread_unmount)) \ \ declare_function(os::dll_load) \ declare_function(os::dll_lookup) \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index acc28964627..ead1b78cdea 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -859,11 +859,11 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_VectorBinaryLibOp: return EnableVectorSupport && Matcher::supports_vector_calling_convention(); case vmIntrinsics::_blackhole: + case vmIntrinsics::_vthreadEndFirstTransition: + case vmIntrinsics::_vthreadStartFinalTransition: + case vmIntrinsics::_vthreadStartTransition: + case vmIntrinsics::_vthreadEndTransition: #if INCLUDE_JVMTI - case vmIntrinsics::_notifyJvmtiVThreadStart: - case vmIntrinsics::_notifyJvmtiVThreadEnd: - case vmIntrinsics::_notifyJvmtiVThreadMount: - case vmIntrinsics::_notifyJvmtiVThreadUnmount: case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: #endif break; diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index dc53cb08396..6d4a9104580 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -55,6 +55,7 @@ #include "prims/jvmtiThreadState.hpp" #include "prims/unsafe.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" @@ -479,15 +480,15 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_Continuation_pin: return inline_native_Continuation_pinning(false); case vmIntrinsics::_Continuation_unpin: return inline_native_Continuation_pinning(true); + case vmIntrinsics::_vthreadEndFirstTransition: return inline_native_vthread_end_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_end_first_transition_Java()), + "endFirstTransition", true); + case vmIntrinsics::_vthreadStartFinalTransition: return inline_native_vthread_start_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_start_final_transition_Java()), + "startFinalTransition", true); + case vmIntrinsics::_vthreadStartTransition: return inline_native_vthread_start_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_start_transition_Java()), + "startTransition", false); + case vmIntrinsics::_vthreadEndTransition: return inline_native_vthread_end_transition(CAST_FROM_FN_PTR(address, OptoRuntime::vthread_end_transition_Java()), + "endTransition", false); #if INCLUDE_JVMTI - case vmIntrinsics::_notifyJvmtiVThreadStart: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_start()), - "notifyJvmtiStart", true, false); - case vmIntrinsics::_notifyJvmtiVThreadEnd: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_end()), - "notifyJvmtiEnd", false, true); - case vmIntrinsics::_notifyJvmtiVThreadMount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_mount()), - "notifyJvmtiMount", false, false); - case vmIntrinsics::_notifyJvmtiVThreadUnmount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_unmount()), - "notifyJvmtiUnmount", false, false); case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: return inline_native_notify_jvmti_sync(); #endif @@ -3042,46 +3043,80 @@ bool LibraryCallKit::inline_native_time_funcs(address funcAddr, const char* func return true; } - -#if INCLUDE_JVMTI - -// When notifications are disabled then just update the VTMS transition bit and return. -// Otherwise, the bit is updated in the given function call implementing JVMTI notification protocol. -bool LibraryCallKit::inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end) { - if (!DoJVMTIVirtualThreadTransitions) { - return true; - } +//--------------------inline_native_vthread_start_transition-------------------- +// inline void startTransition(boolean is_mount); +// inline void startFinalTransition(); +// Pseudocode of implementation: +// +// java_lang_Thread::set_is_in_vthread_transition(vthread, true); +// carrier->set_is_in_vthread_transition(true); +// OrderAccess::storeload(); +// int disable_requests = java_lang_Thread::vthread_transition_disable_count(vthread) +// + global_vthread_transition_disable_count(); +// if (disable_requests > 0) { +// slow path: runtime call +// } +bool LibraryCallKit::inline_native_vthread_start_transition(address funcAddr, const char* funcName, bool is_final_transition) { Node* vt_oop = _gvn.transform(must_be_not_null(argument(0), true)); // VirtualThread this argument IdealKit ideal(this); - Node* ONE = ideal.ConI(1); - Node* hide = is_start ? ideal.ConI(0) : (is_end ? ideal.ConI(1) : _gvn.transform(argument(1))); - Node* addr = makecon(TypeRawPtr::make((address)&JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events)); - Node* notify_jvmti_enabled = ideal.load(ideal.ctrl(), addr, TypeInt::BOOL, T_BOOLEAN, Compile::AliasIdxRaw); + Node* thread = ideal.thread(); + Node* jt_addr = basic_plus_adr(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); + insert_mem_bar(Op_MemBarVolatile); + ideal.sync_kit(this); - ideal.if_then(notify_jvmti_enabled, BoolTest::eq, ONE); { + Node* global_disable_addr = makecon(TypeRawPtr::make((address)MountUnmountDisabler::global_vthread_transition_disable_count_address())); + Node* global_disable = ideal.load(ideal.ctrl(), global_disable_addr, TypeInt::INT, T_INT, Compile::AliasIdxRaw, true /*require_atomic_access*/); + Node* vt_disable_addr = basic_plus_adr(vt_oop, java_lang_Thread::vthread_transition_disable_count_offset()); + Node* vt_disable = ideal.load(ideal.ctrl(), vt_disable_addr, TypeInt::INT, T_INT, Compile::AliasIdxRaw, true /*require_atomic_access*/); + Node* disabled = _gvn.transform(new AddINode(global_disable, vt_disable)); + + ideal.if_then(disabled, BoolTest::ne, ideal.ConI(0)); { sync_kit(ideal); - // if notifyJvmti enabled then make a call to the given SharedRuntime function - const TypeFunc* tf = OptoRuntime::notify_jvmti_vthread_Type(); - make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, hide); + Node* is_mount = is_final_transition ? ideal.ConI(0) : _gvn.transform(argument(1)); + const TypeFunc* tf = OptoRuntime::vthread_transition_Type(); + make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, is_mount); ideal.sync_kit(this); - } ideal.else_(); { - // set hide value to the VTMS transition bit in current JavaThread and VirtualThread object - Node* thread = ideal.thread(); - Node* jt_addr = basic_plus_adr(thread, in_bytes(JavaThread::is_in_VTMS_transition_offset())); - Node* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_VTMS_transition_offset()); + } + ideal.end_if(); - sync_kit(ideal); - access_store_at(nullptr, jt_addr, _gvn.type(jt_addr)->is_ptr(), hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); - access_store_at(nullptr, vt_addr, _gvn.type(vt_addr)->is_ptr(), hide, _gvn.type(hide), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); - - ideal.sync_kit(this); - } ideal.end_if(); final_sync(ideal); - return true; } +bool LibraryCallKit::inline_native_vthread_end_transition(address funcAddr, const char* funcName, bool is_first_transition) { + Node* vt_oop = _gvn.transform(must_be_not_null(argument(0), true)); // VirtualThread this argument + IdealKit ideal(this); + + Node* _notify_jvmti_addr = makecon(TypeRawPtr::make((address)MountUnmountDisabler::notify_jvmti_events_address())); + Node* _notify_jvmti = ideal.load(ideal.ctrl(), _notify_jvmti_addr, TypeInt::BOOL, T_BOOLEAN, Compile::AliasIdxRaw); + + ideal.if_then(_notify_jvmti, BoolTest::eq, ideal.ConI(1)); { + sync_kit(ideal); + Node* is_mount = is_first_transition ? ideal.ConI(1) : _gvn.transform(argument(1)); + const TypeFunc* tf = OptoRuntime::vthread_transition_Type(); + make_runtime_call(RC_NO_LEAF, tf, funcAddr, funcName, TypePtr::BOTTOM, vt_oop, is_mount); + 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* vt_addr = basic_plus_adr(vt_oop, java_lang_Thread::is_in_vthread_transition_offset()); + + sync_kit(ideal); + access_store_at(nullptr, jt_addr, _gvn.type(jt_addr)->is_ptr(), ideal.ConI(0), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + access_store_at(nullptr, vt_addr, _gvn.type(vt_addr)->is_ptr(), ideal.ConI(0), TypeInt::BOOL, T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + ideal.sync_kit(this); + } ideal.end_if(); + + final_sync(ideal); + return true; +} + +#if INCLUDE_JVMTI + // Always update the is_disable_suspend bit. bool LibraryCallKit::inline_native_notify_jvmti_sync() { if (!DoJVMTIVirtualThreadTransitions) { diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 7dbb57c1e5c..bfe29814dec 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -275,9 +275,11 @@ class LibraryCallKit : public GraphKit { bool inline_native_Continuation_pinning(bool unpin); bool inline_native_time_funcs(address method, const char* funcName); + + bool inline_native_vthread_start_transition(address funcAddr, const char* funcName, bool is_final_transition); + bool inline_native_vthread_end_transition(address funcAddr, const char* funcName, bool is_first_transition); + #if INCLUDE_JVMTI - bool inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end); - bool inline_native_notify_jvmti_hide(); bool inline_native_notify_jvmti_sync(); #endif diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 32acbe57951..6dbbfb0a130 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -66,6 +66,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaCalls.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stackWatermarkSet.hpp" @@ -92,12 +93,9 @@ #define C2_STUB_FIELD_NAME(name) _ ## name ## _Java #define C2_STUB_FIELD_DEFINE(name, f, t, r) \ address OptoRuntime:: C2_STUB_FIELD_NAME(name) = nullptr; -#define C2_JVMTI_STUB_FIELD_DEFINE(name) \ - address OptoRuntime:: STUB_FIELD_NAME(name) = nullptr; -C2_STUBS_DO(C2_BLOB_FIELD_DEFINE, C2_STUB_FIELD_DEFINE, C2_JVMTI_STUB_FIELD_DEFINE) +C2_STUBS_DO(C2_BLOB_FIELD_DEFINE, C2_STUB_FIELD_DEFINE) #undef C2_BLOB_FIELD_DEFINE #undef C2_STUB_FIELD_DEFINE -#undef C2_JVMTI_STUB_FIELD_DEFINE // This should be called in an assertion at the start of OptoRuntime routines // which are entered from compiled code (all of them) @@ -153,23 +151,9 @@ static bool check_compiled_frame(JavaThread* thread) { pass_retpc); \ if (C2_STUB_FIELD_NAME(name) == nullptr) { return false; } \ -#define C2_JVMTI_STUB_C_FUNC(name) CAST_FROM_FN_PTR(address, SharedRuntime::name) - -#define GEN_C2_JVMTI_STUB(name) \ - STUB_FIELD_NAME(name) = \ - generate_stub(env, \ - notify_jvmti_vthread_Type, \ - C2_JVMTI_STUB_C_FUNC(name), \ - C2_STUB_NAME(name), \ - C2_STUB_ID(name), \ - 0, \ - true, \ - false); \ - if (STUB_FIELD_NAME(name) == nullptr) { return false; } \ - bool OptoRuntime::generate(ciEnv* env) { - C2_STUBS_DO(GEN_C2_BLOB, GEN_C2_STUB, GEN_C2_JVMTI_STUB) + C2_STUBS_DO(GEN_C2_BLOB, GEN_C2_STUB) return true; } @@ -182,8 +166,6 @@ bool OptoRuntime::generate(ciEnv* env) { #undef C2_STUB_NAME #undef GEN_C2_STUB -#undef C2_JVMTI_STUB_C_FUNC -#undef GEN_C2_JVMTI_STUB // #undef gen const TypeFunc* OptoRuntime::_new_instance_Type = nullptr; @@ -257,12 +239,10 @@ const TypeFunc* OptoRuntime::_updateBytesCRC32C_Type = nullptr; const TypeFunc* OptoRuntime::_updateBytesAdler32_Type = nullptr; const TypeFunc* OptoRuntime::_osr_end_Type = nullptr; const TypeFunc* OptoRuntime::_register_finalizer_Type = nullptr; +const TypeFunc* OptoRuntime::_vthread_transition_Type = nullptr; #if INCLUDE_JFR const TypeFunc* OptoRuntime::_class_id_load_barrier_Type = nullptr; #endif // INCLUDE_JFR -#if INCLUDE_JVMTI -const TypeFunc* OptoRuntime::_notify_jvmti_vthread_Type = nullptr; -#endif // INCLUDE_JVMTI const TypeFunc* OptoRuntime::_dtrace_method_entry_exit_Type = nullptr; const TypeFunc* OptoRuntime::_dtrace_object_alloc_Type = nullptr; @@ -572,6 +552,26 @@ JRT_BLOCK_ENTRY(void, OptoRuntime::monitor_notifyAll_C(oopDesc* obj, JavaThread* JRT_BLOCK_END; JRT_END +JRT_ENTRY(void, OptoRuntime::vthread_end_first_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + MountUnmountDisabler::end_transition(current, vt, true /*is_mount*/, true /*is_thread_start*/); +JRT_END + +JRT_ENTRY(void, OptoRuntime::vthread_start_final_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + java_lang_Thread::set_is_in_vthread_transition(vt, false); + current->set_is_in_vthread_transition(false); + MountUnmountDisabler::start_transition(current, vt, false /*is_mount */, true /*is_thread_end*/); +JRT_END + +JRT_ENTRY(void, OptoRuntime::vthread_start_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + java_lang_Thread::set_is_in_vthread_transition(vt, false); + current->set_is_in_vthread_transition(false); + MountUnmountDisabler::start_transition(current, vt, is_mount, false /*is_thread_end*/); +JRT_END + +JRT_ENTRY(void, OptoRuntime::vthread_end_transition_C(oopDesc* vt, jboolean is_mount, JavaThread* current)) + MountUnmountDisabler::end_transition(current, vt, is_mount, false /*is_thread_start*/); +JRT_END + static const TypeFunc* make_new_instance_Type() { // create input type (domain) const Type **fields = TypeTuple::fields(1); @@ -587,8 +587,7 @@ static const TypeFunc* make_new_instance_Type() { return TypeFunc::make(domain, range); } -#if INCLUDE_JVMTI -static const TypeFunc* make_notify_jvmti_vthread_Type() { +static const TypeFunc* make_vthread_transition_Type() { // create input type (domain) const Type **fields = TypeTuple::fields(2); fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // VirtualThread oop @@ -602,7 +601,6 @@ static const TypeFunc* make_notify_jvmti_vthread_Type() { return TypeFunc::make(domain,range); } -#endif static const TypeFunc* make_athrow_Type() { // create input type (domain) @@ -2336,12 +2334,10 @@ void OptoRuntime::initialize_types() { _updateBytesAdler32_Type = make_updateBytesAdler32_Type(); _osr_end_Type = make_osr_end_Type(); _register_finalizer_Type = make_register_finalizer_Type(); + _vthread_transition_Type = make_vthread_transition_Type(); JFR_ONLY( _class_id_load_barrier_Type = make_class_id_load_barrier_Type(); ) -#if INCLUDE_JVMTI - _notify_jvmti_vthread_Type = make_notify_jvmti_vthread_Type(); -#endif // INCLUDE_JVMTI _dtrace_method_entry_exit_Type = make_dtrace_method_entry_exit_Type(); _dtrace_object_alloc_Type = make_dtrace_object_alloc_Type(); } diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index eb2b49311cf..b8cdd9a962a 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -115,15 +115,12 @@ class OptoRuntime : public AllStatic { #define C2_STUB_FIELD_NAME(name) _ ## name ## _Java #define C2_STUB_FIELD_DECLARE(name, f, t, r) \ static address C2_STUB_FIELD_NAME(name) ; -#define C2_JVMTI_STUB_FIELD_DECLARE(name) \ - static address STUB_FIELD_NAME(name); - C2_STUBS_DO(C2_BLOB_FIELD_DECLARE, C2_STUB_FIELD_DECLARE, C2_JVMTI_STUB_FIELD_DECLARE) + C2_STUBS_DO(C2_BLOB_FIELD_DECLARE, C2_STUB_FIELD_DECLARE) #undef C2_BLOB_FIELD_DECLARE #undef C2_STUB_FIELD_NAME #undef C2_STUB_FIELD_DECLARE -#undef C2_JVMTI_STUB_FIELD_DECLARE // static TypeFunc* data members static const TypeFunc* _new_instance_Type; @@ -197,12 +194,10 @@ class OptoRuntime : public AllStatic { static const TypeFunc* _updateBytesAdler32_Type; static const TypeFunc* _osr_end_Type; static const TypeFunc* _register_finalizer_Type; + static const TypeFunc* _vthread_transition_Type; #if INCLUDE_JFR static const TypeFunc* _class_id_load_barrier_Type; #endif // INCLUDE_JFR -#if INCLUDE_JVMTI - static const TypeFunc* _notify_jvmti_vthread_Type; -#endif // INCLUDE_JVMTI static const TypeFunc* _dtrace_method_entry_exit_Type; static const TypeFunc* _dtrace_object_alloc_Type; @@ -239,6 +234,11 @@ public: static void monitor_notify_C(oopDesc* obj, JavaThread* current); static void monitor_notifyAll_C(oopDesc* obj, JavaThread* current); + static void vthread_end_first_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + static void vthread_start_final_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + static void vthread_start_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + static void vthread_end_transition_C(oopDesc* vt, jboolean hide, JavaThread* current); + private: // Implicit exception support @@ -293,12 +293,11 @@ private: static address slow_arraycopy_Java() { return _slow_arraycopy_Java; } static address register_finalizer_Java() { return _register_finalizer_Java; } -#if INCLUDE_JVMTI - static address notify_jvmti_vthread_start() { return _notify_jvmti_vthread_start; } - static address notify_jvmti_vthread_end() { return _notify_jvmti_vthread_end; } - static address notify_jvmti_vthread_mount() { return _notify_jvmti_vthread_mount; } - static address notify_jvmti_vthread_unmount() { return _notify_jvmti_vthread_unmount; } -#endif + + static address vthread_end_first_transition_Java() { return _vthread_end_first_transition_Java; } + static address vthread_start_final_transition_Java() { return _vthread_start_final_transition_Java; } + static address vthread_start_transition_Java() { return _vthread_start_transition_Java; } + static address vthread_end_transition_Java() { return _vthread_end_transition_Java; } static UncommonTrapBlob* uncommon_trap_blob() { return _uncommon_trap_blob; } static ExceptionBlob* exception_blob() { return _exception_blob; } @@ -718,6 +717,27 @@ private: return _register_finalizer_Type; } + static inline const TypeFunc* vthread_transition_Type() { + assert(_vthread_transition_Type != nullptr, "should be initialized"); + return _vthread_transition_Type; + } + + static inline const TypeFunc* vthread_end_first_transition_Type() { + return vthread_transition_Type(); + } + + static inline const TypeFunc* vthread_start_final_transition_Type() { + return vthread_transition_Type(); + } + + static inline const TypeFunc* vthread_start_transition_Type() { + return vthread_transition_Type(); + } + + static inline const TypeFunc* vthread_end_transition_Type() { + return vthread_transition_Type(); + } + #if INCLUDE_JFR static inline const TypeFunc* class_id_load_barrier_Type() { assert(_class_id_load_barrier_Type != nullptr, "should be initialized"); @@ -725,13 +745,6 @@ private: } #endif // INCLUDE_JFR -#if INCLUDE_JVMTI - static inline const TypeFunc* notify_jvmti_vthread_Type() { - assert(_notify_jvmti_vthread_Type != nullptr, "should be initialized"); - return _notify_jvmti_vthread_Type; - } -#endif - // Dtrace support. entry and exit probes have the same signature static inline const TypeFunc* dtrace_method_entry_exit_Type() { assert(_dtrace_method_entry_exit_Type != nullptr, "should be initialized"); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index a868f6337e2..16d9efde410 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -84,6 +84,7 @@ #include "runtime/javaThread.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/os.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/perfData.hpp" @@ -3661,68 +3662,24 @@ JVM_LEAF(jint, JVM_FindSignal(const char *name)) return os::get_signal_number(name); JVM_END -JVM_ENTRY(void, JVM_VirtualThreadStart(JNIEnv* env, jobject vthread)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_start(vthread); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, false); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadEndFirstTransition(JNIEnv* env, jobject vthread)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::end_transition(thread, vt, true /*is_mount*/, true /*is_thread_start*/); JVM_END -JVM_ENTRY(void, JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_end(vthread); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, true); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadStartFinalTransition(JNIEnv* env, jobject vthread)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::start_transition(thread, vt, false /*is_mount */, true /*is_thread_end*/); JVM_END -// If notifications are disabled then just update the VTMS transition bit and return. -// Otherwise, the bit is updated in the given jvmtiVTMSTransitionDisabler function call. -JVM_ENTRY(void, JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hide)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount(vthread, hide); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadStartTransition(JNIEnv* env, jobject vthread, jboolean is_mount)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::start_transition(thread, vt, is_mount, false /*is_thread_end*/); JVM_END -// If notifications are disabled then just update the VTMS transition bit and return. -// Otherwise, the bit is updated in the given jvmtiVTMSTransitionDisabler function call below. -JVM_ENTRY(void, JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide)) -#if INCLUDE_JVMTI - if (!DoJVMTIVirtualThreadTransitions) { - assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); - return; - } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(vthread, hide); - } else { - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide); - } -#endif +JVM_ENTRY(void, JVM_VirtualThreadEndTransition(JNIEnv* env, jobject vthread, jboolean is_mount)) + oop vt = JNIHandles::resolve_external_guard(vthread); + MountUnmountDisabler::end_transition(thread, vt, is_mount, false /*is_thread_start*/); JVM_END // Notification from VirtualThread about disabling JVMTI Suspend in a sync critical section. @@ -3772,6 +3729,7 @@ JVM_ENTRY(jobject, JVM_TakeVirtualThreadListToUnblock(JNIEnv* env, jclass ignore parkEvent->park(); } JVM_END + /* * Return the current class's class file version. The low order 16 bits of the * returned jint contain the class's major version. The high order 16 bits diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 5642cd9ff8f..e0863c07f4f 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -66,6 +66,7 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" @@ -147,7 +148,7 @@ jvmtiError JvmtiEnv::SetThreadLocalStorage(jthread thread, const void* data) { JavaThread* current = JavaThread::current(); JvmtiThreadState* state = nullptr; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; @@ -200,7 +201,7 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) { VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread) DEBUG_ONLY(VMNativeEntryWrapper __vew;) - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -561,7 +562,7 @@ JvmtiEnv::SetNativeMethodPrefixes(jint prefix_count, char** prefixes) { // size_of_callbacks - pre-checked to be greater than or equal to 0 jvmtiError JvmtiEnv::SetEventCallbacks(const jvmtiEventCallbacks* callbacks, jint size_of_callbacks) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; JvmtiEventController::set_event_callbacks(this, callbacks, size_of_callbacks); return JVMTI_ERROR_NONE; } /* end SetEventCallbacks */ @@ -585,7 +586,7 @@ JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, j if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) { record_class_file_load_hook_enabled(); } - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; if (event_thread == nullptr) { // Can be called at Agent_OnLoad() time with event_thread == nullptr @@ -867,7 +868,7 @@ JvmtiEnv::GetJLocationFormat(jvmtiJlocationFormat* format_ptr) { jvmtiError JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) { JavaThread* current_thread = JavaThread::current(); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -939,7 +940,7 @@ JvmtiEnv::SuspendThread(jthread thread) { jvmtiError err; { - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; oop thread_oop = nullptr; @@ -949,7 +950,7 @@ JvmtiEnv::SuspendThread(jthread thread) { return err; } - // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. + // Do not use MountUnmountDisabler in context of self suspend to avoid deadlocks. if (java_thread != current) { err = suspend_thread(thread_oop, java_thread, /* single_suspend */ true); return err; @@ -974,7 +975,7 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm int self_idx = -1; { - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh(current); for (int i = 0; i < request_count; i++) { @@ -1007,7 +1008,7 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm } } // Self suspend after all other suspends if necessary. - // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. + // Do not use MountUnmountDisabler in context of self suspend to avoid deadlocks. if (self_tobj() != nullptr) { // there should not be any error for current java_thread results[self_idx] = suspend_thread(self_tobj(), current, /* single_suspend */ true); @@ -1028,7 +1029,7 @@ JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list { ResourceMark rm(current); - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh(current); GrowableArray* elist = new GrowableArray(except_count); @@ -1078,7 +1079,7 @@ JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list } } // Self suspend after all other suspends if necessary. - // Do not use JvmtiVTMSTransitionDisabler in context of self suspend to avoid deadlocks. + // Do not use MountUnmountDisabler in context of self suspend to avoid deadlocks. if (self_tobj() != nullptr) { suspend_thread(self_tobj(), current, /* single_suspend */ false); } @@ -1089,7 +1090,7 @@ JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list // thread - NOT protected by ThreadsListHandle and NOT pre-checked jvmtiError JvmtiEnv::ResumeThread(jthread thread) { - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); JavaThread* current = JavaThread::current(); ThreadsListHandle tlh(current); @@ -1111,7 +1112,7 @@ jvmtiError JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmtiError* results) { oop thread_oop = nullptr; JavaThread* java_thread = nullptr; - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); ThreadsListHandle tlh; for (int i = 0; i < request_count; i++) { @@ -1150,7 +1151,7 @@ JvmtiEnv::ResumeAllVirtualThreads(jint except_count, const jthread* except_list) return err; } ResourceMark rm; - JvmtiVTMSTransitionDisabler disabler(true); + MountUnmountDisabler disabler(true); GrowableArray* elist = new GrowableArray(except_count); // Collect threads from except_list for which suspended status must be restored (only for VirtualThread case) @@ -1196,7 +1197,7 @@ jvmtiError JvmtiEnv::StopThread(jthread thread, jobject exception) { JavaThread* current_thread = JavaThread::current(); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; oop thread_oop = nullptr; @@ -1234,7 +1235,7 @@ JvmtiEnv::InterruptThread(jthread thread) { JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1280,7 +1281,7 @@ JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) { JavaThread* java_thread = nullptr; oop thread_oop = nullptr; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); // if thread is null the current thread is used @@ -1369,7 +1370,7 @@ JvmtiEnv::GetOwnedMonitorInfo(jthread thread, jint* owned_monitor_count_ptr, job JavaThread* calling_thread = JavaThread::current(); HandleMark hm(calling_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(calling_thread); JavaThread* java_thread = nullptr; @@ -1424,7 +1425,7 @@ JvmtiEnv::GetOwnedMonitorStackDepthInfo(jthread thread, jint* monitor_info_count JavaThread* calling_thread = JavaThread::current(); HandleMark hm(calling_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(calling_thread); JavaThread* java_thread = nullptr; @@ -1707,7 +1708,7 @@ JvmtiEnv::GetThreadListStackTraces(jint thread_count, const jthread* thread_list *stack_info_ptr = op.stack_info(); } } else { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // JVMTI get stack traces at safepoint. VM_GetThreadListStackTraces op(this, thread_count, thread_list, max_frame_count); @@ -1740,7 +1741,7 @@ JvmtiEnv::PopFrame(jthread thread) { if (thread == nullptr) { return JVMTI_ERROR_INVALID_THREAD; } - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1795,7 +1796,7 @@ JvmtiEnv::GetFrameLocation(jthread thread, jint depth, jmethodID* method_ptr, jl jvmtiError JvmtiEnv::NotifyFramePop(jthread thread, jint depth) { ResourceMark rm; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); JavaThread* current = JavaThread::current(); ThreadsListHandle tlh(current); @@ -1823,7 +1824,7 @@ JvmtiEnv::NotifyFramePop(jthread thread, jint depth) { jvmtiError JvmtiEnv::ClearAllFramePops(jthread thread) { ResourceMark rm; - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); JavaThread* current = JavaThread::current(); ThreadsListHandle tlh(current); @@ -2084,7 +2085,7 @@ JvmtiEnv::GetLocalObject(jthread thread, jint depth, jint slot, jobject* value_p // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2125,7 +2126,7 @@ JvmtiEnv::GetLocalInstance(jthread thread, jint depth, jobject* value_ptr){ // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2167,7 +2168,7 @@ JvmtiEnv::GetLocalInt(jthread thread, jint depth, jint slot, jint* value_ptr) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2209,7 +2210,7 @@ JvmtiEnv::GetLocalLong(jthread thread, jint depth, jint slot, jlong* value_ptr) // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2251,7 +2252,7 @@ JvmtiEnv::GetLocalFloat(jthread thread, jint depth, jint slot, jfloat* value_ptr // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2293,7 +2294,7 @@ JvmtiEnv::GetLocalDouble(jthread thread, jint depth, jint slot, jdouble* value_p // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2334,7 +2335,7 @@ JvmtiEnv::SetLocalObject(jthread thread, jint depth, jint slot, jobject value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2371,7 +2372,7 @@ JvmtiEnv::SetLocalInt(jthread thread, jint depth, jint slot, jint value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2408,7 +2409,7 @@ JvmtiEnv::SetLocalLong(jthread thread, jint depth, jint slot, jlong value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2445,7 +2446,7 @@ JvmtiEnv::SetLocalFloat(jthread thread, jint depth, jint slot, jfloat value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2482,7 +2483,7 @@ JvmtiEnv::SetLocalDouble(jthread thread, jint depth, jint slot, jdouble value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2574,7 +2575,7 @@ JvmtiEnv::ClearBreakpoint(Method* method, jlocation location) { jvmtiError JvmtiEnv::SetFieldAccessWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we haven't set this watch before if (fdesc_ptr->is_field_access_watched()) return JVMTI_ERROR_DUPLICATE; fdesc_ptr->set_is_field_access_watched(true); @@ -2587,7 +2588,7 @@ JvmtiEnv::SetFieldAccessWatch(fieldDescriptor* fdesc_ptr) { jvmtiError JvmtiEnv::ClearFieldAccessWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we have a watch to clear if (!fdesc_ptr->is_field_access_watched()) return JVMTI_ERROR_NOT_FOUND; fdesc_ptr->set_is_field_access_watched(false); @@ -2600,7 +2601,7 @@ JvmtiEnv::ClearFieldAccessWatch(fieldDescriptor* fdesc_ptr) { jvmtiError JvmtiEnv::SetFieldModificationWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we haven't set this watch before if (fdesc_ptr->is_field_modification_watched()) return JVMTI_ERROR_DUPLICATE; fdesc_ptr->set_is_field_modification_watched(true); @@ -2613,7 +2614,7 @@ JvmtiEnv::SetFieldModificationWatch(fieldDescriptor* fdesc_ptr) { jvmtiError JvmtiEnv::ClearFieldModificationWatch(fieldDescriptor* fdesc_ptr) { - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; // make sure we have a watch to clear if (!fdesc_ptr->is_field_modification_watched()) return JVMTI_ERROR_NOT_FOUND; fdesc_ptr->set_is_field_modification_watched(false); diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 2b17eddbe94..4894a4dd21a 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -51,6 +51,7 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jfieldIDWorkaround.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/osThread.hpp" #include "runtime/signature.hpp" @@ -697,7 +698,7 @@ JvmtiEnvBase::check_and_skip_hidden_frames(bool is_in_VTMS_transition, javaVFram javaVFrame* JvmtiEnvBase::check_and_skip_hidden_frames(JavaThread* jt, javaVFrame* jvf) { - jvf = check_and_skip_hidden_frames(jt->is_in_VTMS_transition(), jvf); + jvf = check_and_skip_hidden_frames(jt->is_in_vthread_transition(), jvf); return jvf; } @@ -719,7 +720,7 @@ JvmtiEnvBase::get_vthread_jvf(oop vthread) { return nullptr; } vframeStream vfs(java_thread); - assert(!java_thread->is_in_VTMS_transition(), "invariant"); + assert(!java_thread->is_in_vthread_transition(), "invariant"); jvf = vfs.at_end() ? nullptr : vfs.asJavaVFrame(); jvf = check_and_skip_hidden_frames(false, jvf); } else { @@ -1693,8 +1694,7 @@ private: // jt->jvmti_vthread() for VTMS transition protocol. void correct_jvmti_thread_states() { for (JavaThread* jt : ThreadsListHandle()) { - if (jt->is_in_VTMS_transition()) { - jt->set_VTMS_transition_mark(true); + if (jt->is_in_vthread_transition()) { continue; // no need in JvmtiThreadState correction below if in transition } correct_jvmti_thread_state(jt); @@ -1711,7 +1711,7 @@ public: if (_enable) { correct_jvmti_thread_states(); } - JvmtiVTMSTransitionDisabler::set_VTMS_notify_jvmti_events(_enable); + MountUnmountDisabler::set_notify_jvmti_events(_enable); } }; @@ -1722,7 +1722,7 @@ JvmtiEnvBase::enable_virtual_threads_notify_jvmti() { if (!Continuations::enabled()) { return false; } - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { + if (MountUnmountDisabler::notify_jvmti_events()) { return false; // already enabled } VM_SetNotifyJvmtiEventsMode op(true); @@ -1738,10 +1738,10 @@ JvmtiEnvBase::disable_virtual_threads_notify_jvmti() { if (!Continuations::enabled()) { return false; } - if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { + if (!MountUnmountDisabler::notify_jvmti_events()) { return false; // already disabled } - JvmtiVTMSTransitionDisabler disabler(true); // ensure there are no other disablers + MountUnmountDisabler disabler(true); // ensure there are no other disablers VM_SetNotifyJvmtiEventsMode op(false); VMThread::execute(&op); return true; @@ -1769,7 +1769,6 @@ JvmtiEnvBase::suspend_thread(oop thread_oop, JavaThread* java_thread, bool singl // Platform thread or mounted vthread cases. assert(java_thread != nullptr, "sanity check"); - assert(!java_thread->is_in_VTMS_transition(), "sanity check"); // Don't allow hidden thread suspend request. if (java_thread->is_hidden_from_external_view()) { @@ -1828,7 +1827,6 @@ JvmtiEnvBase::resume_thread(oop thread_oop, JavaThread* java_thread, bool single // Platform thread or mounted vthread cases. assert(java_thread != nullptr, "sanity check"); - assert(!java_thread->is_in_VTMS_transition(), "sanity check"); // Don't allow hidden thread resume request. if (java_thread->is_hidden_from_external_view()) { @@ -2008,12 +2006,12 @@ class AdapterClosure : public HandshakeClosure { }; // Supports platform and virtual threads. -// JvmtiVTMSTransitionDisabler is always set by this function. +// MountUnmountDisabler is always set by this function. void JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, jthread target) { JavaThread* current = JavaThread::current(); HandleMark hm(current); - JvmtiVTMSTransitionDisabler disabler(target); + MountUnmountDisabler disabler(target); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; oop thread_obj = nullptr; @@ -2030,7 +2028,7 @@ JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, jthread target) { // Supports platform and virtual threads. // A virtual thread is always identified by the target_h oop handle. // The target_jt is always nullptr for an unmounted virtual thread. -// JvmtiVTMSTransitionDisabler has to be set before call to this function. +// MountUnmountDisabler has to be set before call to this function. void JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, ThreadsListHandle* tlh, JavaThread* target_jt, Handle target_h) { @@ -2038,7 +2036,7 @@ JvmtiHandshake::execute(JvmtiUnitedHandshakeClosure* hs_cl, ThreadsListHandle* t bool is_virtual = java_lang_VirtualThread::is_instance(target_h()); bool self = target_jt == current; - assert(!Continuations::enabled() || self || !is_virtual || current->is_VTMS_transition_disabler(), "sanity check"); + assert(!Continuations::enabled() || self || !is_virtual || current->is_vthread_transition_disabler(), "sanity check"); hs_cl->set_target_jt(target_jt); // can be needed in the virtual thread case hs_cl->set_is_virtual(is_virtual); // can be needed in the virtual thread case @@ -2211,7 +2209,7 @@ JvmtiEnvBase::force_early_return(jthread thread, jvalue value, TosState tos) { JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler(thread); + MountUnmountDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2612,7 +2610,7 @@ PrintStackTraceClosure::do_thread_impl(Thread *target) { "is_VTMS_transition_disabler: %d, is_in_VTMS_transition = %d\n", tname, java_thread->name(), java_thread->is_exiting(), java_thread->is_suspended(), java_thread->is_carrier_thread_suspended(), is_vt_suspended, - java_thread->is_VTMS_transition_disabler(), java_thread->is_in_VTMS_transition()); + java_thread->is_vthread_transition_disabler(), java_thread->is_in_vthread_transition()); if (java_thread->has_last_Java_frame()) { RegisterMap reg_map(java_thread, diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 14b7d886bce..02f39460ff6 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -61,6 +61,7 @@ #include "runtime/javaThread.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/keepStackGCProcessed.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" @@ -412,7 +413,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { if (Continuations::enabled()) { // Virtual threads support for agents loaded into running VM. // There is a performance impact when VTMS transitions are enabled. - if (!JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { + if (!MountUnmountDisabler::notify_jvmti_events()) { JvmtiEnvBase::enable_virtual_threads_notify_jvmti(); } } @@ -426,7 +427,7 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) { if (Continuations::enabled()) { // Virtual threads support for agents loaded at startup. // There is a performance impact when VTMS transitions are enabled. - JvmtiVTMSTransitionDisabler::set_VTMS_notify_jvmti_events(true); + MountUnmountDisabler::set_notify_jvmti_events(true, true /*is_onload*/); } return JNI_OK; @@ -1639,7 +1640,7 @@ void JvmtiExport::post_vthread_end(jobject vthread) { JVMTI_JAVA_THREAD_EVENT_CALLBACK_BLOCK(thread) jvmtiEventVirtualThreadEnd callback = env->callbacks()->VirtualThreadEnd; if (callback != nullptr) { - (*callback)(env->jvmti_external(), jem.jni_env(), vthread); + (*callback)(env->jvmti_external(), jem.jni_env(), jem.jni_thread()); } } } @@ -2924,13 +2925,13 @@ void JvmtiExport::vthread_post_monitor_waited(JavaThread *current, ObjectMonitor Handle vthread(current, current->vthread()); // Finish the VTMS transition temporarily to post the event. - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)vthread.raw_value(), false); + MountUnmountDisabler::end_transition(current, vthread(), true /*is_mount*/, false /*is_thread_start*/); // Post event. JvmtiExport::post_monitor_waited(current, obj_mntr, timed_out); // Go back to VTMS transition state. - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount((jthread)vthread.raw_value(), true); + MountUnmountDisabler::start_transition(current, vthread(), false /*is_mount*/, false /*is_thread_start*/); } void JvmtiExport::post_vm_object_alloc(JavaThread *thread, oop object) { diff --git a/src/hotspot/share/prims/jvmtiExtensions.cpp b/src/hotspot/share/prims/jvmtiExtensions.cpp index 603d62eff85..855c7bd4eba 100644 --- a/src/hotspot/share/prims/jvmtiExtensions.cpp +++ b/src/hotspot/share/prims/jvmtiExtensions.cpp @@ -29,6 +29,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" // the list of extension functions GrowableArray* JvmtiExtensions::_ext_functions; @@ -77,7 +78,7 @@ static jvmtiError JNICALL GetVirtualThread(const jvmtiEnv* env, ...) { va_end(ap); ThreadInVMfromNative tiv(current_thread); - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; ThreadsListHandle tlh(current_thread); jvmtiError err; @@ -135,7 +136,7 @@ static jvmtiError JNICALL GetCarrierThread(const jvmtiEnv* env, ...) { MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); ThreadInVMfromNative tiv(current_thread); - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; ThreadsListHandle tlh(current_thread); JavaThread* java_thread; diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index c923f91f69d..90a3461f321 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -57,6 +57,7 @@ #include "runtime/javaCalls.hpp" #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/mutex.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" @@ -3028,7 +3029,7 @@ void JvmtiTagMap::iterate_over_reachable_objects(jvmtiHeapRootCallback heap_root jvmtiObjectReferenceCallback object_ref_callback, const void* user_data) { // VTMS transitions must be disabled before the EscapeBarrier. - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; JavaThread* jt = JavaThread::current(); EscapeBarrier eb(true, jt); @@ -3056,7 +3057,7 @@ void JvmtiTagMap::iterate_over_objects_reachable_from_object(jobject object, Arena dead_object_arena(mtServiceability); GrowableArray dead_objects(&dead_object_arena, 10, 0, 0); - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; { MutexLocker ml(Heap_lock); @@ -3076,7 +3077,7 @@ void JvmtiTagMap::follow_references(jint heap_filter, const void* user_data) { // VTMS transitions must be disabled before the EscapeBarrier. - JvmtiVTMSTransitionDisabler disabler; + MountUnmountDisabler disabler; oop obj = JNIHandles::resolve(object); JavaThread* jt = JavaThread::current(); diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index 00a48dec111..fc965e568f7 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -209,479 +209,6 @@ JvmtiThreadState::periodic_clean_up() { } } -// -// Virtual Threads Mount State transition (VTMS transition) mechanism -// - -// VTMS transitions for one virtual thread are disabled while it is positive -volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_one_count = 0; - -// VTMS transitions for all virtual threads are disabled while it is positive -volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_all_count = 0; - -// There is an active suspender or resumer. -volatile bool JvmtiVTMSTransitionDisabler::_SR_mode = false; - -// Notifications from VirtualThread about VTMS events are enabled. -bool JvmtiVTMSTransitionDisabler::_VTMS_notify_jvmti_events = false; - -// The JvmtiVTMSTransitionDisabler sync protocol is enabled if this count > 0. -volatile int JvmtiVTMSTransitionDisabler::_sync_protocol_enabled_count = 0; - -// JvmtiVTMSTraansitionDisabler sync protocol is enabled permanently after seeing a suspender. -volatile bool JvmtiVTMSTransitionDisabler::_sync_protocol_enabled_permanently = false; - -#ifdef ASSERT -void -JvmtiVTMSTransitionDisabler::print_info() { - log_error(jvmti)("_VTMS_transition_disable_for_one_count: %d\n", _VTMS_transition_disable_for_one_count); - log_error(jvmti)("_VTMS_transition_disable_for_all_count: %d\n\n", _VTMS_transition_disable_for_all_count); - int attempts = 10000; - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *java_thread = jtiwh.next(); ) { - if (java_thread->VTMS_transition_mark()) { - log_error(jvmti)("jt: %p VTMS_transition_mark: %d\n", - (void*)java_thread, java_thread->VTMS_transition_mark()); - } - ResourceMark rm; - // Handshake with target. - PrintStackTraceClosure pstc; - Handshake::execute(&pstc, java_thread); - } -} -#endif - -// disable VTMS transitions for one virtual thread -// disable VTMS transitions for all threads if thread is nullptr or a platform thread -JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread) - : _is_SR(false), - _is_virtual(false), - _is_self(false), - _thread(thread) -{ - if (!Continuations::enabled()) { - return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads - } - if (Thread::current_or_null() == nullptr) { - return; // Detached thread, can be a call from Agent_OnLoad. - } - JavaThread* current = JavaThread::current(); - oop thread_oop = JNIHandles::resolve_external_guard(thread); - _is_virtual = java_lang_VirtualThread::is_instance(thread_oop); - - if (thread == nullptr || - (!_is_virtual && thread_oop == current->threadObj()) || - (_is_virtual && thread_oop == current->vthread())) { - _is_self = true; - return; // no need for current thread to disable and enable transitions for itself - } - if (!sync_protocol_enabled_permanently()) { - JvmtiVTMSTransitionDisabler::inc_sync_protocol_enabled_count(); - } - - // Target can be virtual or platform thread. - // If target is a platform thread then we have to disable VTMS transitions for all threads. - // It is by several reasons: - // - carrier threads can mount virtual threads which may cause incorrect behavior - // - there is no mechanism to disable transitions for a specific carrier thread yet - if (_is_virtual) { - VTMS_transition_disable_for_one(); // disable VTMS transitions for one virtual thread - } else { - VTMS_transition_disable_for_all(); // disable VTMS transitions for all virtual threads - } -} - -// disable VTMS transitions for all virtual threads -JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(bool is_SR) - : _is_SR(is_SR), - _is_virtual(false), - _is_self(false), - _thread(nullptr) -{ - if (!Continuations::enabled()) { - return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads - } - if (Thread::current_or_null() == nullptr) { - return; // Detached thread, can be a call from Agent_OnLoad. - } - if (!sync_protocol_enabled_permanently()) { - JvmtiVTMSTransitionDisabler::inc_sync_protocol_enabled_count(); - if (is_SR) { - AtomicAccess::store(&_sync_protocol_enabled_permanently, true); - } - } - VTMS_transition_disable_for_all(); -} - -JvmtiVTMSTransitionDisabler::~JvmtiVTMSTransitionDisabler() { - if (!Continuations::enabled()) { - return; // JvmtiVTMSTransitionDisabler is a no-op without virtual threads - } - if (Thread::current_or_null() == nullptr) { - return; // Detached thread, can be a call from Agent_OnLoad. - } - if (_is_self) { - return; // no need for current thread to disable and enable transitions for itself - } - if (_is_virtual) { - VTMS_transition_enable_for_one(); // enable VTMS transitions for one virtual thread - } else { - VTMS_transition_enable_for_all(); // enable VTMS transitions for all virtual threads - } - if (!sync_protocol_enabled_permanently()) { - JvmtiVTMSTransitionDisabler::dec_sync_protocol_enabled_count(); - } -} - -// disable VTMS transitions for one virtual thread -void -JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_one() { - assert(_thread != nullptr, "sanity check"); - JavaThread* thread = JavaThread::current(); - HandleMark hm(thread); - Handle vth = Handle(thread, JNIHandles::resolve_external_guard(_thread)); - assert(java_lang_VirtualThread::is_instance(vth()), "sanity check"); - - MonitorLocker ml(JvmtiVTMSTransition_lock); - - while (_SR_mode) { // suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist - ml.wait(10); // wait while there is an active suspender or resumer - } - AtomicAccess::inc(&_VTMS_transition_disable_for_one_count); - java_lang_Thread::inc_VTMS_transition_disable_count(vth()); - - while (java_lang_Thread::is_in_VTMS_transition(vth())) { - ml.wait(10); // wait while the virtual thread is in transition - } -#ifdef ASSERT - thread->set_is_VTMS_transition_disabler(true); -#endif -} - -// disable VTMS transitions for all virtual threads -void -JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_all() { - JavaThread* thread = JavaThread::current(); - int attempts = 50000; - { - MonitorLocker ml(JvmtiVTMSTransition_lock); - - assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check"); - while (_SR_mode) { // Suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist. - ml.wait(10); // Wait while there is an active suspender or resumer. - } - if (_is_SR) { - _SR_mode = true; - while (_VTMS_transition_disable_for_all_count > 0 || - _VTMS_transition_disable_for_one_count > 0) { - ml.wait(10); // Wait while there is any active jvmtiVTMSTransitionDisabler. - } - } - AtomicAccess::inc(&_VTMS_transition_disable_for_all_count); - - // Block while some mount/unmount transitions are in progress. - // Debug version fails and prints diagnostic information. - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { - while (jt->VTMS_transition_mark()) { - if (ml.wait(10)) { - attempts--; - } - DEBUG_ONLY(if (attempts == 0) break;) - } - } - assert(!thread->is_VTMS_transition_disabler(), "VTMS_transition sanity check"); -#ifdef ASSERT - if (attempts > 0) { - thread->set_is_VTMS_transition_disabler(true); - } -#endif - } -#ifdef ASSERT - if (attempts == 0) { - print_info(); - fatal("stuck in JvmtiVTMSTransitionDisabler::VTMS_transition_disable"); - } -#endif -} - -// enable VTMS transitions for one virtual thread -void -JvmtiVTMSTransitionDisabler::VTMS_transition_enable_for_one() { - JavaThread* thread = JavaThread::current(); - HandleMark hm(thread); - Handle vth = Handle(thread, JNIHandles::resolve_external_guard(_thread)); - if (!java_lang_VirtualThread::is_instance(vth())) { - return; // no-op if _thread is not a virtual thread - } - MonitorLocker ml(JvmtiVTMSTransition_lock); - java_lang_Thread::dec_VTMS_transition_disable_count(vth()); - AtomicAccess::dec(&_VTMS_transition_disable_for_one_count); - if (_VTMS_transition_disable_for_one_count == 0) { - ml.notify_all(); - } -#ifdef ASSERT - thread->set_is_VTMS_transition_disabler(false); -#endif -} - -// enable VTMS transitions for all virtual threads -void -JvmtiVTMSTransitionDisabler::VTMS_transition_enable_for_all() { - JavaThread* current = JavaThread::current(); - { - MonitorLocker ml(JvmtiVTMSTransition_lock); - assert(_VTMS_transition_disable_for_all_count > 0, "VTMS_transition sanity check"); - - if (_is_SR) { // Disabler is suspender or resumer. - _SR_mode = false; - } - AtomicAccess::dec(&_VTMS_transition_disable_for_all_count); - if (_VTMS_transition_disable_for_all_count == 0 || _is_SR) { - ml.notify_all(); - } -#ifdef ASSERT - current->set_is_VTMS_transition_disabler(false); -#endif - } -} - -void -JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_mount) { - JavaThread* thread = JavaThread::current(); - oop vt = JNIHandles::resolve_external_guard(vthread); - assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check"); - - // Avoid using MonitorLocker on performance critical path, use - // two-level synchronization with lock-free operations on state bits. - assert(!thread->VTMS_transition_mark(), "sanity check"); - thread->set_VTMS_transition_mark(true); // Try to enter VTMS transition section optmistically. - java_lang_Thread::set_is_in_VTMS_transition(vt, true); - - if (!sync_protocol_enabled()) { - thread->set_is_in_VTMS_transition(true); - return; - } - HandleMark hm(thread); - Handle vth = Handle(thread, vt); - int attempts = 50000; - - // Do not allow suspends inside VTMS transitions. - // Block while transitions are disabled or there are suspend requests. - int64_t thread_id = java_lang_Thread::thread_id(vth()); // Cannot use oops while blocked. - - if (_VTMS_transition_disable_for_all_count > 0 || - java_lang_Thread::VTMS_transition_disable_count(vth()) > 0 || - thread->is_suspended() || - JvmtiVTSuspender::is_vthread_suspended(thread_id) - ) { - // Slow path: undo unsuccessful optimistic set of the VTMS_transition_mark. - // It can cause an extra waiting cycle for VTMS transition disablers. - thread->set_VTMS_transition_mark(false); - java_lang_Thread::set_is_in_VTMS_transition(vth(), false); - - while (true) { - MonitorLocker ml(JvmtiVTMSTransition_lock); - - // Do not allow suspends inside VTMS transitions. - // Block while transitions are disabled or there are suspend requests. - if (_VTMS_transition_disable_for_all_count > 0 || - java_lang_Thread::VTMS_transition_disable_count(vth()) > 0 || - thread->is_suspended() || - JvmtiVTSuspender::is_vthread_suspended(thread_id) - ) { - // Block while transitions are disabled or there are suspend requests. - if (ml.wait(200)) { - attempts--; - } - DEBUG_ONLY(if (attempts == 0) break;) - continue; // ~ThreadBlockInVM has handshake-based suspend point. - } - thread->set_VTMS_transition_mark(true); - java_lang_Thread::set_is_in_VTMS_transition(vth(), true); - break; - } - } -#ifdef ASSERT - if (attempts == 0) { - log_error(jvmti)("start_VTMS_transition: thread->is_suspended: %d is_vthread_suspended: %d\n\n", - thread->is_suspended(), JvmtiVTSuspender::is_vthread_suspended(thread_id)); - print_info(); - fatal("stuck in JvmtiVTMSTransitionDisabler::start_VTMS_transition"); - } -#endif - // Enter VTMS transition section. - thread->set_is_in_VTMS_transition(true); -} - -void -JvmtiVTMSTransitionDisabler::finish_VTMS_transition(jthread vthread, bool is_mount) { - JavaThread* thread = JavaThread::current(); - - assert(thread->is_in_VTMS_transition(), "sanity check"); - thread->set_is_in_VTMS_transition(false); - oop vt = JNIHandles::resolve_external_guard(vthread); - java_lang_Thread::set_is_in_VTMS_transition(vt, false); - assert(thread->VTMS_transition_mark(), "sanity check"); - thread->set_VTMS_transition_mark(false); - - if (!sync_protocol_enabled()) { - return; - } - int64_t thread_id = java_lang_Thread::thread_id(vt); - - // Unblock waiting VTMS transition disablers. - if (_VTMS_transition_disable_for_one_count > 0 || - _VTMS_transition_disable_for_all_count > 0) { - MonitorLocker ml(JvmtiVTMSTransition_lock); - ml.notify_all(); - } - // In unmount case the carrier thread is attached after unmount transition. - // Check and block it if there was external suspend request. - int attempts = 10000; - if (!is_mount && thread->is_carrier_thread_suspended()) { - while (true) { - MonitorLocker ml(JvmtiVTMSTransition_lock); - - // Block while there are suspend requests. - if ((!is_mount && thread->is_carrier_thread_suspended()) || - (is_mount && JvmtiVTSuspender::is_vthread_suspended(thread_id)) - ) { - // Block while there are suspend requests. - if (ml.wait(200)) { - attempts--; - } - DEBUG_ONLY(if (attempts == 0) break;) - continue; - } - break; - } - } -#ifdef ASSERT - if (attempts == 0) { - log_error(jvmti)("finish_VTMS_transition: thread->is_suspended: %d is_vthread_suspended: %d\n\n", - thread->is_suspended(), JvmtiVTSuspender::is_vthread_suspended(thread_id)); - print_info(); - fatal("stuck in JvmtiVTMSTransitionDisabler::finish_VTMS_transition"); - } -#endif -} - -// set VTMS transition bit value in JavaThread and java.lang.VirtualThread object -void JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(JavaThread* thread, jobject vthread, bool in_trans) { - oop vt = JNIHandles::resolve_external_guard(vthread); - java_lang_Thread::set_is_in_VTMS_transition(vt, in_trans); - thread->set_is_in_VTMS_transition(in_trans); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_start(jobject vthread) { - VTMS_mount_end(vthread); - JavaThread* thread = JavaThread::current(); - - assert(!thread->is_in_VTMS_transition(), "sanity check"); - - // If interp_only_mode has been enabled then we must eagerly create JvmtiThreadState - // objects for globally enabled virtual thread filtered events. Otherwise, - // it is an important optimization to create JvmtiThreadState objects lazily. - // This optimization is disabled when watchpoint capabilities are present. It is to - // work around a bug with virtual thread frames which can be not deoptimized in time. - if (JvmtiThreadState::seen_interp_only_mode() || - JvmtiExport::should_post_field_access() || - JvmtiExport::should_post_field_modification()){ - JvmtiEventController::thread_started(thread); - } - if (JvmtiExport::should_post_vthread_start()) { - JvmtiExport::post_vthread_start(vthread); - } - // post VirtualThreadMount event after VirtualThreadStart - if (JvmtiExport::should_post_vthread_mount()) { - JvmtiExport::post_vthread_mount(vthread); - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_end(jobject vthread) { - JavaThread* thread = JavaThread::current(); - - assert(!thread->is_in_VTMS_transition(), "sanity check"); - - // post VirtualThreadUnmount event before VirtualThreadEnd - if (JvmtiExport::should_post_vthread_unmount()) { - JvmtiExport::post_vthread_unmount(vthread); - } - if (JvmtiExport::should_post_vthread_end()) { - JvmtiExport::post_vthread_end(vthread); - } - VTMS_unmount_begin(vthread, /* last_unmount */ true); - if (thread->jvmti_thread_state() != nullptr) { - JvmtiExport::cleanup_thread(thread); - assert(thread->jvmti_thread_state() == nullptr, "should be null"); - assert(java_lang_Thread::jvmti_thread_state(JNIHandles::resolve(vthread)) == nullptr, "should be null"); - } - thread->rebind_to_jvmti_thread_state_of(thread->threadObj()); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_mount(jobject vthread, bool hide) { - if (hide) { - VTMS_mount_begin(vthread); - } else { - VTMS_mount_end(vthread); - if (JvmtiExport::should_post_vthread_mount()) { - JvmtiExport::post_vthread_mount(vthread); - } - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(jobject vthread, bool hide) { - if (hide) { - if (JvmtiExport::should_post_vthread_unmount()) { - JvmtiExport::post_vthread_unmount(vthread); - } - VTMS_unmount_begin(vthread, /* last_unmount */ false); - } else { - VTMS_unmount_end(vthread); - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_mount_begin(jobject vthread) { - JavaThread* thread = JavaThread::current(); - assert(!thread->is_in_VTMS_transition(), "sanity check"); - start_VTMS_transition(vthread, /* is_mount */ true); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_mount_end(jobject vthread) { - JavaThread* thread = JavaThread::current(); - oop vt = JNIHandles::resolve(vthread); - - thread->rebind_to_jvmti_thread_state_of(vt); - - assert(thread->is_in_VTMS_transition(), "sanity check"); - finish_VTMS_transition(vthread, /* is_mount */ true); -} - -void -JvmtiVTMSTransitionDisabler::VTMS_unmount_begin(jobject vthread, bool last_unmount) { - JavaThread* thread = JavaThread::current(); - - assert(!thread->is_in_VTMS_transition(), "sanity check"); - - start_VTMS_transition(vthread, /* is_mount */ false); - if (!last_unmount) { - thread->rebind_to_jvmti_thread_state_of(thread->threadObj()); - } -} - -void -JvmtiVTMSTransitionDisabler::VTMS_unmount_end(jobject vthread) { - JavaThread* thread = JavaThread::current(); - assert(thread->is_in_VTMS_transition(), "sanity check"); - finish_VTMS_transition(vthread, /* is_mount */ false); -} - - // // Virtual Threads Suspend/Resume management // diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 17bdae4662e..43b568cf1fc 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -72,67 +72,6 @@ class JvmtiEnvThreadStateIterator : public StackObj { JvmtiEnvThreadState* next(JvmtiEnvThreadState* ets); }; -/////////////////////////////////////////////////////////////// -// -// class JvmtiVTMSTransitionDisabler -// -// Virtual Thread Mount State Transition (VTMS transition) mechanism -// -class JvmtiVTMSTransitionDisabler : public AnyObj { - private: - static volatile int _VTMS_transition_disable_for_one_count; // transitions for one virtual thread are disabled while it is positive - static volatile int _VTMS_transition_disable_for_all_count; // transitions for all virtual threads are disabled while it is positive - static volatile bool _SR_mode; // there is an active suspender or resumer - static volatile int _sync_protocol_enabled_count; // current number of JvmtiVTMSTransitionDisablers enabled sync protocol - static volatile bool _sync_protocol_enabled_permanently; // seen a suspender: JvmtiVTMSTransitionDisabler protocol is enabled permanently - - bool _is_SR; // is suspender or resumer - bool _is_virtual; // target thread is virtual - bool _is_self; // JvmtiVTMSTransitionDisabler is a no-op for current platform, carrier or virtual thread - jthread _thread; // virtual thread to disable transitions for, no-op if it is a platform thread - - DEBUG_ONLY(static void print_info();) - void VTMS_transition_disable_for_one(); - void VTMS_transition_disable_for_all(); - void VTMS_transition_enable_for_one(); - void VTMS_transition_enable_for_all(); - - public: - static bool _VTMS_notify_jvmti_events; // enable notifications from VirtualThread about VTMS events - static bool VTMS_notify_jvmti_events() { return _VTMS_notify_jvmti_events; } - static void set_VTMS_notify_jvmti_events(bool val) { _VTMS_notify_jvmti_events = val; } - - static void inc_sync_protocol_enabled_count() { AtomicAccess::inc(&_sync_protocol_enabled_count); } - static void dec_sync_protocol_enabled_count() { AtomicAccess::dec(&_sync_protocol_enabled_count); } - static int sync_protocol_enabled_count() { return AtomicAccess::load(&_sync_protocol_enabled_count); } - static bool sync_protocol_enabled_permanently() { return AtomicAccess::load(&_sync_protocol_enabled_permanently); } - - static bool sync_protocol_enabled() { return sync_protocol_enabled_permanently() || sync_protocol_enabled_count() > 0; } - - // parameter is_SR: suspender or resumer - JvmtiVTMSTransitionDisabler(bool is_SR = false); - JvmtiVTMSTransitionDisabler(jthread thread); - ~JvmtiVTMSTransitionDisabler(); - - // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object - static void set_is_in_VTMS_transition(JavaThread* thread, jobject vthread, bool in_trans); - - static void start_VTMS_transition(jthread vthread, bool is_mount); - static void finish_VTMS_transition(jthread vthread, bool is_mount); - - static void VTMS_vthread_start(jobject vthread); - static void VTMS_vthread_end(jobject vthread); - - static void VTMS_vthread_mount(jobject vthread, bool hide); - static void VTMS_vthread_unmount(jobject vthread, bool hide); - - static void VTMS_mount_begin(jobject vthread); - static void VTMS_mount_end(jobject vthread); - - static void VTMS_unmount_begin(jobject vthread, bool last_unmount); - static void VTMS_unmount_end(jobject vthread); -}; - /////////////////////////////////////////////////////////////// // // class VirtualThreadList diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp index 8f1cbe39640..935f304a751 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -35,6 +35,7 @@ #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/osThread.hpp" #include "runtime/vframe.inline.hpp" #include "runtime/vframe_hp.hpp" @@ -56,66 +57,50 @@ JVM_ENTRY(void, CONT_unpin(JNIEnv* env, jclass cls)) { } JVM_END -#if INCLUDE_JVMTI -class JvmtiUnmountBeginMark : public StackObj { +class UnmountBeginMark : public StackObj { Handle _vthread; JavaThread* _current; freeze_result _result; bool _failed; public: - JvmtiUnmountBeginMark(JavaThread* t) : + UnmountBeginMark(JavaThread* t) : _vthread(t, t->vthread()), _current(t), _result(freeze_pinned_native), _failed(false) { - assert(!_current->is_in_VTMS_transition(), "must be"); + assert(!_current->is_in_vthread_transition(), "must be"); - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount((jthread)_vthread.raw_value(), true); + MountUnmountDisabler::start_transition(_current, _vthread(), false /*is_mount*/, false /*is_thread_start*/); - // Don't preempt if there is a pending popframe or earlyret operation. This can - // be installed in start_VTMS_transition() so we need to check it here. - if (JvmtiExport::can_pop_frame() || JvmtiExport::can_force_early_return()) { - JvmtiThreadState* state = _current->jvmti_thread_state(); - if (_current->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) { - _failed = true; - } - } - - // Don't preempt in case there is an async exception installed since - // we would incorrectly throw it during the unmount logic in the carrier. - if (_current->has_async_exception_condition()) { + // Don't preempt if there is a pending popframe or earlyret operation. This can + // be installed in in process_at_transition_start() so we need to check it here. + if (JvmtiExport::can_pop_frame() || JvmtiExport::can_force_early_return()) { + JvmtiThreadState* state = _current->jvmti_thread_state(); + if (_current->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) { _failed = true; } - } else { - _current->set_is_in_VTMS_transition(true); - java_lang_Thread::set_is_in_VTMS_transition(_vthread(), true); + } + + // Don't preempt in case there is an async exception installed since + // we would incorrectly throw it during the unmount logic in the carrier. + if (_current->has_async_exception_condition()) { + _failed = true; } } - ~JvmtiUnmountBeginMark() { + ~UnmountBeginMark() { assert(!_current->is_suspended(), "must be"); - - assert(_current->is_in_VTMS_transition(), "must be"); - assert(java_lang_Thread::is_in_VTMS_transition(_vthread()), "must be"); - - // Read it again since for late binding agents the flag could have - // been set while blocked in the allocation path during freeze. - bool jvmti_present = JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events(); + assert(_current->is_in_vthread_transition(), "must be"); if (_result != freeze_ok) { // Undo transition - if (jvmti_present) { - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)_vthread.raw_value(), false); - } else { - _current->set_is_in_VTMS_transition(false); - java_lang_Thread::set_is_in_VTMS_transition(_vthread(), false); - } + MountUnmountDisabler::end_transition(_current, _vthread(), true /*is_mount*/, false /*is_thread_start*/); } } void set_result(freeze_result res) { _result = res; } bool failed() { return _failed; } }; +#if INCLUDE_JVMTI static bool is_vthread_safe_to_preempt_for_jvmti(JavaThread* current) { - if (current->is_in_VTMS_transition()) { + if (current->is_in_vthread_transition()) { // We are at the end of a mount transition. return false; } @@ -150,11 +135,11 @@ freeze_result Continuation::try_preempt(JavaThread* current, oop continuation) { return freeze_pinned_native; } - JVMTI_ONLY(JvmtiUnmountBeginMark jubm(current);) - JVMTI_ONLY(if (jubm.failed()) return freeze_pinned_native;) + UnmountBeginMark ubm(current); + if (ubm.failed()) return freeze_pinned_native; freeze_result res = CAST_TO_FN_PTR(FreezeContFnT, freeze_preempt_entry())(current, current->last_Java_sp()); log_trace(continuations, preempt)("try_preempt: %d", res); - JVMTI_ONLY(jubm.set_result(res);) + ubm.set_result(res); if (current->has_pending_exception()) { assert(res == freeze_exception, "expecting an exception result from freeze"); diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 2a31e5fb5b2..ccbe78817d6 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -58,6 +58,7 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/keepStackGCProcessed.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/objectMonitor.inline.hpp" #include "runtime/orderAccess.hpp" #include "runtime/prefetch.inline.hpp" @@ -1690,7 +1691,7 @@ static void jvmti_mount_end(JavaThread* current, ContinuationWrapper& cont, fram AnchorMark am(current, top); // Set anchor so that the stack is walkable. JRT_BLOCK - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)vth.raw_value(), false); + MountUnmountDisabler::end_transition(current, vth(), true /*is_mount*/, false /*is_thread_start*/); if (current->pending_contended_entered_event()) { // No monitor JVMTI events for ObjectLocker case. @@ -2629,19 +2630,21 @@ intptr_t* ThawBase::handle_preempted_continuation(intptr_t* sp, Continuation::pr DEBUG_ONLY(verify_frame_kind(top, preempt_kind);) NOT_PRODUCT(int64_t tid = _thread->monitor_owner_id();) -#if INCLUDE_JVMTI // Finish the VTMS transition. - assert(_thread->is_in_VTMS_transition(), "must be"); + assert(_thread->is_in_vthread_transition(), "must be"); bool is_vthread = Continuation::continuation_scope(_cont.continuation()) == java_lang_VirtualThread::vthread_scope(); if (is_vthread) { - if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) { +#if INCLUDE_JVMTI + if (MountUnmountDisabler::notify_jvmti_events()) { jvmti_mount_end(_thread, _cont, top, preempt_kind); - } else { - _thread->set_is_in_VTMS_transition(false); - java_lang_Thread::set_is_in_VTMS_transition(_thread->vthread(), false); + } else +#endif + { // Faster version of MountUnmountDisabler::end_transition() to avoid + // unnecessary extra instructions from jvmti_mount_end(). + java_lang_Thread::set_is_in_vthread_transition(_thread->vthread(), false); + _thread->set_is_in_vthread_transition(false); } } -#endif if (fast_case) { // If we thawed in the slow path the runtime stub/native wrapper frame already diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index f468f27e2c0..89b02717a7a 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -34,6 +34,7 @@ #include "runtime/handshake.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaThread.inline.hpp" +#include "runtime/mountUnmountDisabler.hpp" #include "runtime/os.hpp" #include "runtime/osThread.hpp" #include "runtime/stackWatermarkSet.hpp" @@ -361,6 +362,27 @@ void Handshake::execute(HandshakeClosure* hs_cl) { VMThread::execute(&handshake); } +void Handshake::execute(HandshakeClosure* hs_cl, oop vthread) { + assert(java_lang_VirtualThread::is_instance(vthread), ""); + Handle vth(JavaThread::current(), vthread); + + MountUnmountDisabler md(vthread); + oop carrier_thread = java_lang_VirtualThread::carrier_thread(vth()); + if (carrier_thread != nullptr) { + JavaThread* target = java_lang_Thread::thread(carrier_thread); + assert(target != nullptr, ""); + // Technically there is no need for a ThreadsListHandle since the target + // will block if it tries to unmount the vthread, so it can never exit. + ThreadsListHandle tlh(JavaThread::current()); + assert(tlh.includes(target), ""); + execute(hs_cl, &tlh, target); + assert(target->threadObj() == java_lang_VirtualThread::carrier_thread(vth()), ""); + } else { + // unmounted vthread, execute closure with the current thread + hs_cl->do_thread(nullptr); + } +} + void Handshake::execute(HandshakeClosure* hs_cl, JavaThread* target) { // tlh == nullptr means we rely on a ThreadsListHandle somewhere // in the caller's context (and we sanity check for that). diff --git a/src/hotspot/share/runtime/handshake.hpp b/src/hotspot/share/runtime/handshake.hpp index 1304dca12b7..c764bbcfcd2 100644 --- a/src/hotspot/share/runtime/handshake.hpp +++ b/src/hotspot/share/runtime/handshake.hpp @@ -69,6 +69,7 @@ class Handshake : public AllStatic { // This version of execute() relies on a ThreadListHandle somewhere in // the caller's context to protect target (and we sanity check for that). static void execute(HandshakeClosure* hs_cl, JavaThread* target); + static void execute(HandshakeClosure* hs_cl, oop vthread); // This version of execute() is used when you have a ThreadListHandle in // hand and are using it to protect target. If tlh == nullptr, then we // sanity check for a ThreadListHandle somewhere in the caller's context diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index a81a687a9c0..1bf4841e193 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -448,16 +448,11 @@ JavaThread::JavaThread(MemTag mem_tag) : _do_not_unlock_if_synchronized(false), #if INCLUDE_JVMTI _carrier_thread_suspended(false), - _is_in_VTMS_transition(false), _is_disable_suspend(false), _is_in_java_upcall(false), _jvmti_events_disabled(0), - _VTMS_transition_mark(false), _on_monitor_waited_event(false), _contended_entered_monitor(nullptr), -#ifdef ASSERT - _is_VTMS_transition_disabler(false), -#endif #endif _jni_attach_state(_not_attaching_via_jni), _is_in_internal_oome_mark(false), @@ -503,6 +498,10 @@ JavaThread::JavaThread(MemTag mem_tag) : _handshake(this), _suspend_resume_manager(this, &_handshake._lock), + _is_in_vthread_transition(false), + DEBUG_ONLY(_is_vthread_transition_disabler(false) COMMA) + DEBUG_ONLY(_is_disabler_at_start(false) COMMA) + _popframe_preserved_args(nullptr), _popframe_preserved_args_size(0), @@ -1150,17 +1149,26 @@ void JavaThread::send_async_exception(JavaThread* target, oop java_throwable) { Handshake::execute(&iaeh, target); } -#if INCLUDE_JVMTI -void JavaThread::set_is_in_VTMS_transition(bool val) { - assert(is_in_VTMS_transition() != val, "already %s transition", val ? "inside" : "outside"); - _is_in_VTMS_transition = val; +bool JavaThread::is_in_vthread_transition() const { + DEBUG_ONLY(Thread* current = Thread::current();) + assert(is_handshake_safe_for(current) || SafepointSynchronize::is_at_safepoint() + || JavaThread::cast(current)->is_disabler_at_start(), "not safe"); + return AtomicAccess::load(&_is_in_vthread_transition); +} + +void JavaThread::set_is_in_vthread_transition(bool val) { + assert(is_in_vthread_transition() != val, "already %s transition", val ? "inside" : "outside"); + AtomicAccess::store(&_is_in_vthread_transition, val); } #ifdef ASSERT -void JavaThread::set_is_VTMS_transition_disabler(bool val) { - _is_VTMS_transition_disabler = val; +void JavaThread::set_is_vthread_transition_disabler(bool val) { + _is_vthread_transition_disabler = val; +} + +void JavaThread::set_is_disabler_at_start(bool val) { + _is_disabler_at_start = val; } -#endif #endif // External suspension mechanism. @@ -1170,11 +1178,8 @@ void JavaThread::set_is_VTMS_transition_disabler(bool val) { // - Target thread will not enter any new monitors. // bool JavaThread::java_suspend(bool register_vthread_SR) { -#if INCLUDE_JVMTI - // Suspending a JavaThread in VTMS transition or disabling VTMS transitions can cause deadlocks. - assert(!is_in_VTMS_transition(), "no suspend allowed in VTMS transition"); - assert(!is_VTMS_transition_disabler(), "no suspend allowed for VTMS transition disablers"); -#endif + // Suspending a vthread transition disabler can cause deadlocks. + assert(!is_vthread_transition_disabler(), "no suspend allowed for vthread transition disablers"); 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 ba2aa42132f..d4c12887e10 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -322,16 +322,11 @@ class JavaThread: public Thread { // never locked) when throwing an exception. Used by interpreter only. #if INCLUDE_JVMTI volatile bool _carrier_thread_suspended; // Carrier thread is externally suspended - bool _is_in_VTMS_transition; // thread is in virtual thread mount state transition bool _is_disable_suspend; // JVMTI suspend is temporarily disabled; used on current thread only bool _is_in_java_upcall; // JVMTI is doing a Java upcall, so JVMTI events must be hidden int _jvmti_events_disabled; // JVMTI events disabled manually - bool _VTMS_transition_mark; // used for sync between VTMS transitions and disablers bool _on_monitor_waited_event; // Avoid callee arg processing for enterSpecial when posting waited event ObjectMonitor* _contended_entered_monitor; // Monitor for pending monitor_contended_entered callback -#ifdef ASSERT - bool _is_VTMS_transition_disabler; // thread currently disabled VTMS transitions -#endif #endif // JNI attach states: @@ -737,6 +732,20 @@ public: // current thread, i.e. reverts optimizations based on escape analysis. void wait_for_object_deoptimization(); +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 + 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); +#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 + #if INCLUDE_JVMTI inline bool set_carrier_thread_suspended(); inline bool clear_carrier_thread_suspended(); @@ -745,9 +754,6 @@ public: return AtomicAccess::load(&_carrier_thread_suspended); } - bool is_in_VTMS_transition() const { return _is_in_VTMS_transition; } - void set_is_in_VTMS_transition(bool val); - bool is_disable_suspend() const { return _is_disable_suspend; } void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; } @@ -757,15 +763,12 @@ public: void disable_jvmti_events() { _jvmti_events_disabled++; } void enable_jvmti_events() { _jvmti_events_disabled--; } - bool VTMS_transition_mark() const { return AtomicAccess::load(&_VTMS_transition_mark); } - void set_VTMS_transition_mark(bool val) { AtomicAccess::store(&_VTMS_transition_mark, val); } - // Temporarily skip posting JVMTI events for safety reasons when executions is in a critical section: - // - is in a VTMS transition (_is_in_VTMS_transition) + // - is in a vthread transition (_is_in_vthread_transition) // - is in an interruptLock or similar critical section (_is_disable_suspend) // - JVMTI is making a Java upcall (_is_in_java_upcall) bool should_hide_jvmti_events() const { - return _is_in_VTMS_transition || _is_disable_suspend || _is_in_java_upcall || _jvmti_events_disabled != 0; + return _is_in_vthread_transition || _is_disable_suspend || _is_in_java_upcall || _jvmti_events_disabled != 0; } bool on_monitor_waited_event() { return _on_monitor_waited_event; } @@ -773,10 +776,6 @@ public: bool pending_contended_entered_event() { return _contended_entered_monitor != nullptr; } ObjectMonitor* contended_entered_monitor() { return _contended_entered_monitor; } -#ifdef ASSERT - bool is_VTMS_transition_disabler() const { return _is_VTMS_transition_disabler; } - void set_is_VTMS_transition_disabler(bool val); -#endif #endif void set_contended_entered_monitor(ObjectMonitor* val) NOT_JVMTI_RETURN JVMTI_ONLY({ _contended_entered_monitor = val; }) @@ -931,9 +930,9 @@ public: static ByteSize preempt_alternate_return_offset() { return byte_offset_of(JavaThread, _preempt_alternate_return); } DEBUG_ONLY(static ByteSize interp_at_preemptable_vmcall_cnt_offset() { return byte_offset_of(JavaThread, _interp_at_preemptable_vmcall_cnt); }) static ByteSize unlocked_inflated_monitor_offset() { return byte_offset_of(JavaThread, _unlocked_inflated_monitor); } + static ByteSize is_in_vthread_transition_offset() { return byte_offset_of(JavaThread, _is_in_vthread_transition); } #if INCLUDE_JVMTI - static ByteSize is_in_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_VTMS_transition); } static ByteSize is_disable_suspend_offset() { return byte_offset_of(JavaThread, _is_disable_suspend); } #endif diff --git a/src/hotspot/share/runtime/mountUnmountDisabler.cpp b/src/hotspot/share/runtime/mountUnmountDisabler.cpp new file mode 100644 index 00000000000..5bf00323f10 --- /dev/null +++ b/src/hotspot/share/runtime/mountUnmountDisabler.cpp @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "classfile/javaClasses.inline.hpp" +#include "prims/jvmtiEventController.hpp" +#include "prims/jvmtiExport.hpp" +#include "prims/jvmtiThreadState.inline.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/javaThread.hpp" +#include "runtime/mountUnmountDisabler.hpp" +#include "runtime/threadSMR.hpp" + +volatile int MountUnmountDisabler::_global_vthread_transition_disable_count = 0; +volatile int MountUnmountDisabler::_active_disablers = 0; +bool MountUnmountDisabler::_exclusive_operation_ongoing = false; +bool MountUnmountDisabler::_notify_jvmti_events = false; + +#if INCLUDE_JVMTI +class JVMTIStartTransition : public StackObj { + JavaThread* _current; + Handle _vthread; + bool _is_mount; + bool _is_thread_end; + public: + JVMTIStartTransition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_end) : + _current(current), _vthread(current, vthread), _is_mount(is_mount), _is_thread_end(is_thread_end) { + assert(DoJVMTIVirtualThreadTransitions || !JvmtiExport::can_support_virtual_threads(), "sanity check"); + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + // post VirtualThreadUnmount event before VirtualThreadEnd + if (!_is_mount && JvmtiExport::should_post_vthread_unmount()) { + JvmtiExport::post_vthread_unmount((jthread)_vthread.raw_value()); + } + if (_is_thread_end && JvmtiExport::should_post_vthread_end()) { + JvmtiExport::post_vthread_end((jthread)_vthread.raw_value()); + } + } + } + ~JVMTIStartTransition() { + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + if (_is_thread_end && _current->jvmti_thread_state() != nullptr) { + JvmtiExport::cleanup_thread(_current); + assert(_current->jvmti_thread_state() == nullptr, "should be null"); + assert(java_lang_Thread::jvmti_thread_state(_vthread()) == nullptr, "should be null"); + } + if (!_is_mount) { + _current->rebind_to_jvmti_thread_state_of(_current->threadObj()); + } + } + } +}; + +class JVMTIEndTransition : public StackObj { + JavaThread* _current; + Handle _vthread; + bool _is_mount; + bool _is_thread_start; + public: + JVMTIEndTransition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_start) : + _current(current), _vthread(current, vthread), _is_mount(is_mount), _is_thread_start(is_thread_start) { + assert(DoJVMTIVirtualThreadTransitions || !JvmtiExport::can_support_virtual_threads(), "sanity check"); + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + if (_is_mount) { + _current->rebind_to_jvmti_thread_state_of(_vthread()); + } + DEBUG_ONLY(bool is_virtual = java_lang_VirtualThread::is_instance(_current->jvmti_vthread())); + assert(_is_mount == is_virtual, "wrong identity"); + } + } + ~JVMTIEndTransition() { + if (DoJVMTIVirtualThreadTransitions && MountUnmountDisabler::notify_jvmti_events()) { + if (!_is_mount && _current->is_carrier_thread_suspended()) { + MonitorLocker ml(VThreadTransition_lock); + while (_current->is_carrier_thread_suspended()) { + ml.wait(200); + } + } + + if (_is_thread_start) { + // If interp_only_mode has been enabled then we must eagerly create JvmtiThreadState + // objects for globally enabled virtual thread filtered events. Otherwise, + // it is an important optimization to create JvmtiThreadState objects lazily. + // This optimization is disabled when watchpoint capabilities are present. It is to + // work around a bug with virtual thread frames which can be not deoptimized in time. + if (JvmtiThreadState::seen_interp_only_mode() || + JvmtiExport::should_post_field_access() || + JvmtiExport::should_post_field_modification()){ + JvmtiEventController::thread_started(_current); + } + if (JvmtiExport::should_post_vthread_start()) { + JvmtiExport::post_vthread_start((jthread)_vthread.raw_value()); + } + } + if (_is_mount && JvmtiExport::should_post_vthread_mount()) { + JvmtiExport::post_vthread_mount((jthread)_vthread.raw_value()); + } + } + } +}; +#endif // INCLUDE_JVMTI + +bool MountUnmountDisabler::is_start_transition_disabled(JavaThread* thread, oop vthread) { + // We need to read the per-vthread and global counters to check if transitions are disabled. + // In case of JVMTI present, the global counter will always be at least 1. This is to force + // the slow path and check for possible event posting. Here we need to check if transitions + // are actually disabled, so we compare the global counter against 1 or 0 accordingly. + // In case of JVMTI we also need to check for suspension. + 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())); +} + +void MountUnmountDisabler::start_transition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_end) { + assert(!java_lang_Thread::is_in_vthread_transition(vthread), ""); + assert(!current->is_in_vthread_transition(), ""); + Handle vth = Handle(current, vthread); + JVMTI_ONLY(JVMTIStartTransition jst(current, vthread, is_mount, is_thread_end);) + + java_lang_Thread::set_is_in_vthread_transition(vth(), true); + current->set_is_in_vthread_transition(true); + + // Prevent loads of disable conditions from floating up. + OrderAccess::storeload(); + + while (is_start_transition_disabled(current, vth())) { + java_lang_Thread::set_is_in_vthread_transition(vth(), false); + current->set_is_in_vthread_transition(false); + { + // Block while transitions are disabled + MonitorLocker ml(VThreadTransition_lock); + while (is_start_transition_disabled(current, vth())) { + ml.wait(200); + } + } + + // Try to start transition again... + java_lang_Thread::set_is_in_vthread_transition(vth(), true); + current->set_is_in_vthread_transition(true); + OrderAccess::storeload(); + } + + // Start of the critical section. If this is a mount, we need an acquire barrier to + // synchronize with a possible disabler that executed an operation while this thread + // was unmounted. We make VirtualThread.mount guarantee such ordering and avoid barriers + // here. If this is an unmount, the handshake that the disabler executed against this + // thread already provided the needed synchronization. + // This pairs with the release barrier in xx_enable_for_one()/xx_enable_for_all(). +} + +void MountUnmountDisabler::end_transition(JavaThread* current, oop vthread, bool is_mount, bool is_thread_start) { + assert(java_lang_Thread::is_in_vthread_transition(vthread), ""); + assert(current->is_in_vthread_transition(), ""); + Handle vth = Handle(current, vthread); + JVMTI_ONLY(JVMTIEndTransition jst(current, vthread, is_mount, is_thread_start);) + + // End of the critical section. If this is an unmount, we need a release barrier before + // clearing the in_transition flags to make sure any memory operations executed in the + // transition are visible to a possible disabler that executes while this thread is unmounted. + // We make VirtualThread.unmount guarantee such ordering and avoid barriers here. If this is + // a mount, the only thing that needs to be published is the setting of carrierThread, since + // the handshake that the disabler will execute against it already provides the needed + // synchronization. This order is already guaranteed by the barriers in VirtualThread.mount. + // This pairs with the acquire barrier in xx_disable_for_one()/xx_disable_for_all(). + + java_lang_Thread::set_is_in_vthread_transition(vth(), false); + current->set_is_in_vthread_transition(false); + + // Unblock waiting transition disablers. + if (active_disablers() > 0) { + MonitorLocker ml(VThreadTransition_lock); + ml.notify_all(); + } +} + +// disable transitions for one virtual thread +// disable transitions for all threads if thread is nullptr or a platform thread +MountUnmountDisabler::MountUnmountDisabler(oop thread_oop) + : _is_exclusive(false), + _is_self(false) +{ + if (!Continuations::enabled()) { + return; // MountUnmountDisabler is no-op without virtual threads + } + if (Thread::current_or_null() == nullptr) { + return; // Detached thread, can be a call from Agent_OnLoad. + } + JavaThread* current = JavaThread::current(); + assert(!current->is_in_vthread_transition(), ""); + + bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); + if (thread_oop == nullptr || + (!is_virtual && thread_oop == current->threadObj()) || + (is_virtual && thread_oop == current->vthread())) { + _is_self = true; + return; // no need for current thread to disable and enable transitions for itself + } + + // Target can be virtual or platform thread. + // If target is a platform thread then we have to disable transitions for all threads. + // It is by several reasons: + // - carrier threads can mount virtual threads which may cause incorrect behavior + // - there is no mechanism to disable transitions for a specific carrier thread yet + if (is_virtual) { + _vthread = Handle(current, thread_oop); + disable_transition_for_one(); // disable transitions for one virtual thread + } else { + disable_transition_for_all(); // disable transitions for all virtual threads + } +} + +// disable transitions for all virtual threads +MountUnmountDisabler::MountUnmountDisabler(bool exclusive) + : _is_exclusive(exclusive), + _is_self(false) +{ + if (!Continuations::enabled()) { + return; // MountUnmountDisabler is no-op without virtual threads + } + if (Thread::current_or_null() == nullptr) { + return; // Detached thread, can be a call from Agent_OnLoad. + } + assert(!JavaThread::current()->is_in_vthread_transition(), ""); + disable_transition_for_all(); +} + +MountUnmountDisabler::~MountUnmountDisabler() { + if (!Continuations::enabled()) { + return; // MountUnmountDisabler is a no-op without virtual threads + } + if (Thread::current_or_null() == nullptr) { + return; // Detached thread, can be a call from Agent_OnLoad. + } + if (_is_self) { + return; // no need for current thread to disable and enable transitions for itself + } + if (_vthread() != nullptr) { + enable_transition_for_one(); // enable transitions for one virtual thread + } else { + enable_transition_for_all(); // enable transitions for all virtual threads + } +} + +// disable transitions for one virtual thread +void +MountUnmountDisabler::disable_transition_for_one() { + MonitorLocker ml(VThreadTransition_lock); + while (exclusive_operation_ongoing()) { + ml.wait(10); + } + + inc_active_disablers(); + java_lang_Thread::inc_vthread_transition_disable_count(_vthread()); + + // Prevent load of transition flag from floating up. + OrderAccess::storeload(); + + while (java_lang_Thread::is_in_vthread_transition(_vthread())) { + ml.wait(10); // wait while the virtual thread is in transition + } + + // Start of the critical section. If the target is unmounted, we need an acquire + // barrier to make sure memory operations executed in the last transition are visible. + // If the target is mounted, although the handshake that will be executed against it + // already provides the needed synchronization, we still need to prevent the load of + // 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);) +} + +// disable transitions for all virtual threads +void +MountUnmountDisabler::disable_transition_for_all() { + DEBUG_ONLY(JavaThread* thread = JavaThread::current();) + DEBUG_ONLY(thread->set_is_disabler_at_start(true);) + + MonitorLocker ml(VThreadTransition_lock); + while (exclusive_operation_ongoing()) { + ml.wait(10); + } + if (_is_exclusive) { + set_exclusive_operation_ongoing(true); + while (active_disablers() > 0) { + ml.wait(10); + } + } + inc_active_disablers(); + inc_global_vthread_transition_disable_count(); + + // Prevent loads of transition flag from floating up. Technically not + // required since JavaThreadIteratorWithHandle includes full fence. + OrderAccess::storeload(); + + // Block while some mount/unmount transitions are in progress. + // Debug version fails and prints diagnostic information. + for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { + while (jt->is_in_vthread_transition()) { + ml.wait(10); + } + } + + // Start of the critical section. If some target is unmounted, we need an acquire + // barrier to make sure memory operations executed in the last transition are visible. + // If a target is mounted, although the handshake that will be executed against it + // already provides the needed synchronization, we still need to prevent the load of + // carrierThread to float up. + // This pairs with the release barrier in end_transition(). + OrderAccess::acquire(); + DEBUG_ONLY(thread->set_is_vthread_transition_disabler(true);) + DEBUG_ONLY(thread->set_is_disabler_at_start(false);) +} + +// enable transitions for one virtual thread +void +MountUnmountDisabler::enable_transition_for_one() { + assert(java_lang_VirtualThread::is_instance(_vthread()), ""); + + // End of the critical section. If the target was unmounted, we need a + // release barrier before decrementing _vthread_transition_disable_count to + // make sure any memory operations executed by the disabler are visible to + // the target once it mounts again. If the target was mounted, the handshake + // executed against it already provided the needed synchronization. + // This pairs with the equivalent acquire barrier in start_transition(). + OrderAccess::release(); + + MonitorLocker ml(VThreadTransition_lock); + dec_active_disablers(); + java_lang_Thread::dec_vthread_transition_disable_count(_vthread()); + if (java_lang_Thread::vthread_transition_disable_count(_vthread()) == 0) { + ml.notify_all(); + } + DEBUG_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 + // the target once it mounts again. If a target was mounted, the handshake + // executed against it already provided the needed synchronization. + // This pairs with the equivalent acquire barrier in start_transition(). + OrderAccess::release(); + + MonitorLocker ml(VThreadTransition_lock); + if (exclusive_operation_ongoing()) { + set_exclusive_operation_ongoing(false); + } + dec_active_disablers(); + dec_global_vthread_transition_disable_count(); + int base_disable_count = notify_jvmti_events() ? 1 : 0; + if (global_vthread_transition_disable_count() == base_disable_count || _is_exclusive) { + ml.notify_all(); + } + DEBUG_ONLY(thread->set_is_vthread_transition_disabler(false);) +} + +int MountUnmountDisabler::global_vthread_transition_disable_count() { + assert(_global_vthread_transition_disable_count >= 0, ""); + return AtomicAccess::load(&_global_vthread_transition_disable_count); +} + +void MountUnmountDisabler::inc_global_vthread_transition_disable_count() { + assert(VThreadTransition_lock->owned_by_self() || SafepointSynchronize::is_at_safepoint(), "Must be locked"); + assert(_global_vthread_transition_disable_count >= 0, ""); + AtomicAccess::store(&_global_vthread_transition_disable_count, _global_vthread_transition_disable_count + 1); +} + +void MountUnmountDisabler::dec_global_vthread_transition_disable_count() { + assert(VThreadTransition_lock->owned_by_self() || SafepointSynchronize::is_at_safepoint(), "Must be locked"); + assert(_global_vthread_transition_disable_count > 0, ""); + AtomicAccess::store(&_global_vthread_transition_disable_count, _global_vthread_transition_disable_count - 1); +} + +bool MountUnmountDisabler::exclusive_operation_ongoing() { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + return _exclusive_operation_ongoing; +} + +void MountUnmountDisabler::set_exclusive_operation_ongoing(bool val) { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + assert(_exclusive_operation_ongoing != val, ""); + _exclusive_operation_ongoing = val; +} + +int MountUnmountDisabler::active_disablers() { + assert(_active_disablers >= 0, ""); + return AtomicAccess::load(&_active_disablers); +} + +void MountUnmountDisabler::inc_active_disablers() { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + assert(_active_disablers >= 0, ""); + _active_disablers++; +} + +void MountUnmountDisabler::dec_active_disablers() { + assert(VThreadTransition_lock->owned_by_self(), "Must be locked"); + assert(_active_disablers > 0, ""); + _active_disablers--; +} + +bool MountUnmountDisabler::notify_jvmti_events() { + return _notify_jvmti_events; +} + +void MountUnmountDisabler::set_notify_jvmti_events(bool val, bool is_onload) { + if (val == _notify_jvmti_events || !DoJVMTIVirtualThreadTransitions) return; + + // Force slow path on start/end vthread transitions for JVMTI bookkeeping. + // 'val' is always true except with WhiteBox methods for testing purposes. + if (is_onload) { + // Skip existing increment methods since asserts will fail. + assert(val && _global_vthread_transition_disable_count == 0, ""); + AtomicAccess::inc(&_global_vthread_transition_disable_count); + } else { + assert(SafepointSynchronize::is_at_safepoint(), ""); + if (val) { + inc_global_vthread_transition_disable_count(); + } else { + dec_global_vthread_transition_disable_count(); + } + } + log_trace(continuations,tracking)("%s _notify_jvmti_events, _global_vthread_transition_disable_count=%d", val ? "enabling" : "disabling", _global_vthread_transition_disable_count); + _notify_jvmti_events = val; +} diff --git a/src/hotspot/share/runtime/mountUnmountDisabler.hpp b/src/hotspot/share/runtime/mountUnmountDisabler.hpp new file mode 100644 index 00000000000..2ebb09734a6 --- /dev/null +++ b/src/hotspot/share/runtime/mountUnmountDisabler.hpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_MOUNTUNMOUNTDISABLER_HPP +#define SHARE_RUNTIME_MOUNTUNMOUNTDISABLER_HPP + +#include "memory/allocation.hpp" +#include "runtime/handles.hpp" + +class JavaThread; + +// This class adds support to disable virtual thread transitions (mount/unmount). +// This is needed to safely execute operations that access virtual thread state. +// Users should use the Handshake class when possible instead of using this directly. +class MountUnmountDisabler : public AnyObj { + // The global counter is used for operations that require disabling + // transitions for all virtual threads. Currently this is only used + // by some JVMTI operations. We also increment this counter when the + // first JVMTI agent attaches to always force the slowpath when starting + // a transition. This is needed because if JVMTI is present we need to + // check for possible event posting. + static volatile int _global_vthread_transition_disable_count; + static volatile int _active_disablers; + static bool _exclusive_operation_ongoing; + + bool _is_exclusive; // currently only for suspender or resumer + bool _is_virtual; // target thread is virtual + bool _is_self; // MountUnmountDisabler is a no-op for current platform, carrier or virtual thread + Handle _vthread; // virtual thread to disable transitions for, no-op if it is a platform thread + + //DEBUG_ONLY(static void print_info();) + void disable_transition_for_one(); + void disable_transition_for_all(); + void enable_transition_for_one(); + void enable_transition_for_all(); + + public: + MountUnmountDisabler(bool exlusive = false); + MountUnmountDisabler(oop thread_oop); + ~MountUnmountDisabler(); + + static int global_vthread_transition_disable_count(); + static void inc_global_vthread_transition_disable_count(); + static void dec_global_vthread_transition_disable_count(); + + static volatile int* global_vthread_transition_disable_count_address() { + return &_global_vthread_transition_disable_count; + } + + static bool exclusive_operation_ongoing(); + static void set_exclusive_operation_ongoing(bool val); + + static int active_disablers(); + static void inc_active_disablers(); + static void dec_active_disablers(); + + static void start_transition(JavaThread* thread, oop vthread, bool is_mount, bool is_thread_end); + static void end_transition(JavaThread* thread, oop vthread, bool is_mount, bool is_thread_start); + + static bool is_start_transition_disabled(JavaThread* thread, oop vthread); + + // enable notifications from VirtualThread about Mount/Unmount events + static bool _notify_jvmti_events; + static bool notify_jvmti_events(); + static void set_notify_jvmti_events(bool val, bool is_onload = false); + static bool* notify_jvmti_events_address() { + return &_notify_jvmti_events; + } +}; + +#endif // SHARE_RUNTIME_MOUNTUNMOUNTDISABLER_HPP diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index e4707a342a7..5d7e310fb11 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -49,7 +49,7 @@ Mutex* JfieldIdCreation_lock = nullptr; Monitor* JNICritical_lock = nullptr; Mutex* JvmtiThreadState_lock = nullptr; Monitor* EscapeBarrier_lock = nullptr; -Monitor* JvmtiVTMSTransition_lock = nullptr; +Monitor* VThreadTransition_lock = nullptr; Mutex* JvmtiVThreadSuspend_lock = nullptr; Monitor* Heap_lock = nullptr; #if INCLUDE_PARALLELGC @@ -265,7 +265,7 @@ void mutex_init() { MUTEX_DEFN(CompileStatistics_lock , PaddedMutex , safepoint); MUTEX_DEFN(DirectivesStack_lock , PaddedMutex , nosafepoint); - MUTEX_DEFN(JvmtiVTMSTransition_lock , PaddedMonitor, safepoint); // used for Virtual Thread Mount State transition management + MUTEX_DEFN(VThreadTransition_lock , PaddedMonitor, safepoint); MUTEX_DEFN(JvmtiVThreadSuspend_lock , PaddedMutex, nosafepoint-1); MUTEX_DEFN(EscapeBarrier_lock , PaddedMonitor, nosafepoint); // Used to synchronize object reallocation/relocking triggered by JVMTI MUTEX_DEFN(Management_lock , PaddedMutex , safepoint); // used for JVM management @@ -361,8 +361,8 @@ void mutex_init() { // JVMCIRuntime_lock must be acquired before JVMCI_lock to avoid deadlock MUTEX_DEFL(JVMCI_lock , PaddedMonitor, JVMCIRuntime_lock); #endif - MUTEX_DEFL(JvmtiThreadState_lock , PaddedMutex , JvmtiVTMSTransition_lock); // Used by JvmtiThreadState/JvmtiEventController - MUTEX_DEFL(SharedDecoder_lock , PaddedMutex , NmtVirtualMemory_lock); // Must be lower than NmtVirtualMemory_lock due to MemTracker::print_containing_region + MUTEX_DEFL(JvmtiThreadState_lock , PaddedMutex , VThreadTransition_lock); // Used by JvmtiThreadState/JvmtiEventController + MUTEX_DEFL(SharedDecoder_lock , PaddedMutex , NmtVirtualMemory_lock); // Must be lower than NmtVirtualMemory_lock due to MemTracker::print_containing_region // Allocate RecursiveMutex MultiArray_lock = new RecursiveMutex(); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 74fe4650b7c..f6c0a967718 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -47,7 +47,7 @@ extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI stati extern Monitor* JNICritical_lock; // a lock used while synchronizing with threads entering/leaving JNI critical regions extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data extern Monitor* EscapeBarrier_lock; // a lock to sync reallocating and relocking objects because of JVMTI access -extern Monitor* JvmtiVTMSTransition_lock; // a lock for Virtual Thread Mount State transition (VTMS transition) management +extern Monitor* VThreadTransition_lock; // a lock used when disabling virtual thread transitions extern Mutex* JvmtiVThreadSuspend_lock; // a lock for virtual threads suspension extern Monitor* Heap_lock; // a lock on the heap #if INCLUDE_PARALLELGC diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 3a7c60cf83e..7e3bf763d08 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -737,34 +737,6 @@ void SharedRuntime::throw_and_post_jvmti_exception(JavaThread* current, Symbol* throw_and_post_jvmti_exception(current, h_exception); } -#if INCLUDE_JVMTI -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_start(oopDesc* vt, jboolean hide, JavaThread* current)) - assert(hide == JNI_FALSE, "must be VTMS transition finish"); - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_start(vthread); - JNIHandles::destroy_local(vthread); -JRT_END - -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_end(oopDesc* vt, jboolean hide, JavaThread* current)) - assert(hide == JNI_TRUE, "must be VTMS transition start"); - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_end(vthread); - JNIHandles::destroy_local(vthread); -JRT_END - -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_mount(oopDesc* vt, jboolean hide, JavaThread* current)) - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_mount(vthread, hide); - JNIHandles::destroy_local(vthread); -JRT_END - -JRT_ENTRY(void, SharedRuntime::notify_jvmti_vthread_unmount(oopDesc* vt, jboolean hide, JavaThread* current)) - jobject vthread = JNIHandles::make_local(const_cast(vt)); - JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount(vthread, hide); - JNIHandles::destroy_local(vthread); -JRT_END -#endif // INCLUDE_JVMTI - // The interpreter code to call this tracing function is only // called/generated when UL is on for redefine, class and has the right level // and tags. Since obsolete methods are never compiled, we don't have diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index a696ce5a71b..140207e5d63 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -317,14 +317,6 @@ class SharedRuntime: AllStatic { static void throw_and_post_jvmti_exception(JavaThread* current, Handle h_exception); static void throw_and_post_jvmti_exception(JavaThread* current, Symbol* name, const char *message = nullptr); -#if INCLUDE_JVMTI - // Functions for JVMTI notifications - static void notify_jvmti_vthread_start(oopDesc* vt, jboolean hide, JavaThread* current); - static void notify_jvmti_vthread_end(oopDesc* vt, jboolean hide, JavaThread* current); - static void notify_jvmti_vthread_mount(oopDesc* vt, jboolean hide, JavaThread* current); - static void notify_jvmti_vthread_unmount(oopDesc* vt, jboolean hide, JavaThread* current); -#endif - // RedefineClasses() tracing support for obsolete method entry static int rc_trace_method_entry(JavaThread* thread, Method* m); diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index b051c6d0e18..f9080364dc4 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -199,23 +199,10 @@ // declaration order. #ifdef COMPILER2 -// do_jvmti_stub(name) -#if INCLUDE_JVMTI -#define C2_JVMTI_STUBS_DO(do_jvmti_stub) \ - do_jvmti_stub(notify_jvmti_vthread_start) \ - do_jvmti_stub(notify_jvmti_vthread_end) \ - do_jvmti_stub(notify_jvmti_vthread_mount) \ - do_jvmti_stub(notify_jvmti_vthread_unmount) \ - -#else -#define C2_JVMTI_STUBS_DO(do_jvmti_stub) -#endif // INCLUDE_JVMTI - // client macro to operate on c2 stubs // // do_blob(name, type) // do_stub(name, fancy_jump, pass_tls, return_pc) -// do_jvmti_stub(name) // // do_blob is used for stubs that are generated via direct invocation // of the assembler to write into a blob of the appropriate type @@ -225,10 +212,8 @@ // in the IR graph employ a special type of jump (0, 1 or 2) or // provide access to TLS and the return pc. // -// do_jvmti_stub generates a JVMTI stub as an IR intrinsic which -// employs jump 0, and requires no special access -#define C2_STUBS_DO(do_blob, do_stub, do_jvmti_stub) \ +#define C2_STUBS_DO(do_blob, do_stub) \ do_blob(uncommon_trap, UncommonTrapBlob) \ do_blob(exception, ExceptionBlob) \ do_stub(new_instance, 0, true, false) \ @@ -239,16 +224,19 @@ do_stub(multianewarray4, 0, true, false) \ do_stub(multianewarray5, 0, true, false) \ do_stub(multianewarrayN, 0, true, false) \ - C2_JVMTI_STUBS_DO(do_jvmti_stub) \ do_stub(complete_monitor_locking, 0, false, false) \ do_stub(monitor_notify, 0, false, false) \ do_stub(monitor_notifyAll, 0, false, false) \ do_stub(rethrow, 2, true, true) \ do_stub(slow_arraycopy, 0, false, false) \ do_stub(register_finalizer, 0, false, false) \ + do_stub(vthread_end_first_transition, 0, false, false) \ + do_stub(vthread_start_final_transition, 0, false, false) \ + do_stub(vthread_start_transition, 0, false, false) \ + do_stub(vthread_end_transition, 0, false, false) \ #else -#define C2_STUBS_DO(do_blob, do_stub, do_jvmti_stub) +#define C2_STUBS_DO(do_blob, do_stub) #endif // Stubgen stub declarations @@ -1190,9 +1178,6 @@ // ignore do_stub(name, fancy_jump, pass_tls, return_pc) declarations #define DO_STUB_EMPTY4(name, fancy_jump, pass_tls, return_pc) -// ignore do_jvmti_stub(name) declarations -#define DO_JVMTI_STUB_EMPTY1(stub_name) - // ignore do_stub(blob_name, stub_name) declarations #define DO_STUB_EMPTY2(blob_name, stub_name) diff --git a/src/hotspot/share/runtime/stubInfo.cpp b/src/hotspot/share/runtime/stubInfo.cpp index bca6ff344ea..47a31fe7967 100644 --- a/src/hotspot/share/runtime/stubInfo.cpp +++ b/src/hotspot/share/runtime/stubInfo.cpp @@ -509,14 +509,6 @@ void StubInfo::process_stubgen_entry(StubGroup& group_cursor, StubId:: JOIN3(c2, name, id), \ EntryId:: JOIN3(c2, name, id)); \ -#define PROCESS_C2_JVMTI_STUB(name) \ - process_c2_blob(_group_cursor, _blob_cursor, \ - _stub_cursor, _entry_cursor, \ - "C2 Runtime " # name "_blob", \ - BlobId:: JOIN3(c2, name, id), \ - StubId:: JOIN3(c2, name, id), \ - EntryId:: JOIN3(c2, name, id)); \ - #define PROCESS_STUBGEN_BLOB(blob) \ process_stubgen_blob(_group_cursor, _blob_cursor, \ _stub_cursor, _entry_cursor, \ @@ -610,7 +602,7 @@ void StubInfo::populate_stub_tables() { group_details(_group_cursor)._max = BlobId::NO_BLOBID; group_details(_group_cursor)._entry_base = EntryId::NO_ENTRYID; group_details(_group_cursor)._entry_max = EntryId::NO_ENTRYID; - C2_STUBS_DO(PROCESS_C2_BLOB, PROCESS_C2_STUB, PROCESS_C2_JVMTI_STUB); + C2_STUBS_DO(PROCESS_C2_BLOB, PROCESS_C2_STUB); _group_cursor = StubGroup::STUBGEN; group_details(_group_cursor)._name = "StubGen Stubs"; @@ -637,7 +629,6 @@ void StubInfo::populate_stub_tables() { #undef PROCESS_C1_BLOB #undef PROCESS_C2_BLOB #undef PROCESS_C2_STUB -#undef PROCESS_C2_JVMTI_STUB #undef PROCESS_STUBGEN_BLOB #undef PROCESS_STUBGEN_STUB #undef PROCESS_STUBGEN_ENTRY diff --git a/src/hotspot/share/runtime/stubInfo.hpp b/src/hotspot/share/runtime/stubInfo.hpp index eaea07f7e6c..9ed6e0cb9f9 100644 --- a/src/hotspot/share/runtime/stubInfo.hpp +++ b/src/hotspot/share/runtime/stubInfo.hpp @@ -164,7 +164,6 @@ enum class StubGroup : int { #define SHARED_DECLARE_TAG(name, type) JOIN3(shared, name, id) , #define C1_DECLARE_TAG(name) JOIN3(c1, name, id) , -#define C2_DECLARE_TAG1(name) JOIN3(c2, name, id) , #define C2_DECLARE_TAG2(name, _1) JOIN3(c2, name, id) , #define C2_DECLARE_TAG4(name, _1, _2, _3) JOIN3(c2, name, id) , #define STUBGEN_DECLARE_TAG(name) JOIN3(stubgen, name, id) , @@ -177,8 +176,7 @@ enum class BlobId : int { C1_STUBS_DO(C1_DECLARE_TAG) // declare an enum tag for each opto runtime blob or stub C2_STUBS_DO(C2_DECLARE_TAG2, - C2_DECLARE_TAG4, - C2_DECLARE_TAG1) + C2_DECLARE_TAG4) // declare an enum tag for each stubgen blob STUBGEN_BLOBS_DO(STUBGEN_DECLARE_TAG) NUM_BLOBIDS @@ -214,7 +212,6 @@ enum class BlobId : int { #define SHARED_DECLARE_TAG(name, type) JOIN3(shared, name, id) , #define C1_DECLARE_TAG(name) JOIN3(c1, name, id) , -#define C2_DECLARE_TAG1(name) JOIN3(c2, name, id) , #define C2_DECLARE_TAG2(name, _1) JOIN3(c2, name, id) , #define C2_DECLARE_TAG4(name, _1, _2, _3) JOIN3(c2, name, id) , #define STUBGEN_DECLARE_TAG(blob, name) JOIN3(stubgen, name, id) , @@ -227,8 +224,7 @@ enum class StubId : int { C1_STUBS_DO(C1_DECLARE_TAG) // declare an enum tag for each opto runtime blob or stub C2_STUBS_DO(C2_DECLARE_TAG2, - C2_DECLARE_TAG4, - C2_DECLARE_TAG1) + C2_DECLARE_TAG4) // declare an enum tag for each stubgen runtime stub STUBGEN_STUBS_DO(STUBGEN_DECLARE_TAG) NUM_STUBIDS @@ -307,7 +303,7 @@ enum class StubId : int { type ::ENTRY_COUNT - 1, \ // macros to declare a tag for a C1 generated blob or a C2 generated -// blob, stub or JVMTI stub all of which have a single unique entry +// blob, stub all of which have a single unique entry #define C1_DECLARE_TAG(name) \ JOIN3(c1, name, id), \ @@ -318,9 +314,6 @@ enum class StubId : int { #define C2_DECLARE_STUB_TAG(name, fancy_jump, pass_tls, return_pc) \ JOIN3(c2, name, id), \ -#define C2_DECLARE_JVMTI_STUB_TAG(name) \ - JOIN3(c2, name, id), \ - // macros to declare a tag for a StubGen normal entry or initialized // entry @@ -366,8 +359,7 @@ enum class EntryId : int { C1_STUBS_DO(C1_DECLARE_TAG) // declare an enum tag for each opto runtime blob or stub C2_STUBS_DO(C2_DECLARE_BLOB_TAG, - C2_DECLARE_STUB_TAG, - C2_DECLARE_JVMTI_STUB_TAG) + C2_DECLARE_STUB_TAG) // declare an enum tag for each stubgen entry or, in the case of an // array of entries for the first and last entries. STUBGEN_ALL_ENTRIES_DO(STUBGEN_DECLARE_TAG, @@ -382,7 +374,6 @@ enum class EntryId : int { #undef C1_DECLARE_TAG #undef C2_DECLARE_BLOB_TAG #undef C2_DECLARE_STUB_TAG -#undef C2_DECLARE_JVMTI_STUB_TAG #undef STUBGEN_DECLARE_TAG #undef STUBGEN_DECLARE_INIT_TAG #undef STUBGEN_DECLARE_ARRAY_TAG @@ -402,7 +393,7 @@ enum class EntryId : int { 0 C1_STUBS_DO(COUNT1) #define C2_STUB_COUNT_INITIALIZER \ - 0 C2_STUBS_DO(COUNT2, COUNT4, COUNT1) + 0 C2_STUBS_DO(COUNT2, COUNT4) #define STUBGEN_BLOB_COUNT_INITIALIZER \ 0 STUBGEN_BLOBS_DO(COUNT1) diff --git a/src/hotspot/share/runtime/suspendResumeManager.cpp b/src/hotspot/share/runtime/suspendResumeManager.cpp index 1b9606cf633..067579b6386 100644 --- a/src/hotspot/share/runtime/suspendResumeManager.cpp +++ b/src/hotspot/share/runtime/suspendResumeManager.cpp @@ -93,11 +93,12 @@ void SuspendResumeManager::set_suspended_current_thread(int64_t vthread_id, bool } bool SuspendResumeManager::suspend(bool register_vthread_SR) { - JVMTI_ONLY(assert(!_target->is_in_VTMS_transition(), "no suspend allowed in VTMS transition");) JavaThread* self = JavaThread::current(); if (_target == self) { // If target is the current thread we can bypass the handshake machinery // and just suspend directly. + // Self-suspending while in transition can cause deadlocks. + assert(!self->is_in_vthread_transition(), "no self-suspend allowed in transition"); // The vthread() oop must only be accessed before state is set to _thread_blocked. int64_t id = java_lang_Thread::thread_id(_target->vthread()); ThreadBlockInVM tbivm(self); diff --git a/src/hotspot/share/services/threadService.cpp b/src/hotspot/share/services/threadService.cpp index 48f4eb16cf1..8772195df0b 100644 --- a/src/hotspot/share/services/threadService.cpp +++ b/src/hotspot/share/services/threadService.cpp @@ -1179,12 +1179,13 @@ public: GrowableArray* _bcis; JavaThreadStatus _thread_status; OopHandle _thread_name; + OopHandle _carrier_thread; GrowableArray* _locks; Blocker _blocker; - GetThreadSnapshotHandshakeClosure(Handle thread_h, JavaThread* java_thread): + GetThreadSnapshotHandshakeClosure(Handle thread_h): HandshakeClosure("GetThreadSnapshotHandshakeClosure"), - _thread_h(thread_h), _java_thread(java_thread), + _thread_h(thread_h), _java_thread(nullptr), _frame_count(0), _methods(nullptr), _bcis(nullptr), _thread_status(), _thread_name(nullptr), _locks(nullptr), _blocker() { @@ -1275,14 +1276,15 @@ private: public: void do_thread(Thread* th) override { Thread* current = Thread::current(); + _java_thread = th != nullptr ? JavaThread::cast(th) : nullptr; bool is_virtual = java_lang_VirtualThread::is_instance(_thread_h()); if (_java_thread != nullptr) { if (is_virtual) { // mounted vthread, use carrier thread state - oop carrier_thread = java_lang_VirtualThread::carrier_thread(_thread_h()); - assert(carrier_thread != nullptr, "should only get here for a mounted vthread"); - _thread_status = java_lang_Thread::get_thread_status(carrier_thread); + _carrier_thread = OopHandle(oop_storage(), java_lang_VirtualThread::carrier_thread(_thread_h())); + assert(_carrier_thread.resolve() == _java_thread->threadObj(), ""); + _thread_status = java_lang_Thread::get_thread_status(_carrier_thread.resolve()); } else { _thread_status = java_lang_Thread::get_thread_status(_thread_h()); } @@ -1459,67 +1461,21 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { oop thread_oop; bool has_javathread = tlh.cv_internal_thread_to_JavaThread(jthread, &java_thread, &thread_oop); assert((has_javathread && thread_oop != nullptr) || !has_javathread, "Missing Thread oop"); - Handle thread_h(THREAD, thread_oop); - bool is_virtual = java_lang_VirtualThread::is_instance(thread_h()); // Deals with null + bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); // Deals with null if (!has_javathread && !is_virtual) { return nullptr; // thread terminated so not of interest } - // wrapper to auto delete JvmtiVTMSTransitionDisabler - class TransitionDisabler { - JvmtiVTMSTransitionDisabler* _transition_disabler; - public: - TransitionDisabler(): _transition_disabler(nullptr) {} - ~TransitionDisabler() { - reset(); - } - void init(jobject jthread) { - _transition_disabler = new (mtInternal) JvmtiVTMSTransitionDisabler(jthread); - } - void reset() { - if (_transition_disabler != nullptr) { - delete _transition_disabler; - _transition_disabler = nullptr; - } - } - } transition_disabler; - - Handle carrier_thread; - if (is_virtual) { - // 1st need to disable mount/unmount transitions - transition_disabler.init(jthread); - - carrier_thread = Handle(THREAD, java_lang_VirtualThread::carrier_thread(thread_h())); - if (carrier_thread != nullptr) { - // Note: The java_thread associated with this carrier_thread may not be - // protected by the ThreadsListHandle above. There could have been an - // unmount and remount after the ThreadsListHandle above was created - // and before the JvmtiVTMSTransitionDisabler was created. However, as - // we have disabled transitions, if we are mounted on it, then it cannot - // terminate and so is safe to handshake with. - java_thread = java_lang_Thread::thread(carrier_thread()); - } else { - // We may have previously found a carrier but the virtual thread has unmounted - // after that, so clear that previous reference. - java_thread = nullptr; - } - } else { - java_thread = java_lang_Thread::thread(thread_h()); - } - // Handshake with target - GetThreadSnapshotHandshakeClosure cl(thread_h, java_thread); - if (java_thread == nullptr) { - // unmounted vthread, execute on the current thread - cl.do_thread(nullptr); + Handle thread_h(THREAD, thread_oop); + GetThreadSnapshotHandshakeClosure cl(thread_h); + if (java_lang_VirtualThread::is_instance(thread_oop)) { + Handshake::execute(&cl, thread_oop); } else { Handshake::execute(&cl, &tlh, java_thread); } - // all info is collected, can enable transitions. - transition_disabler.reset(); - // StackTrace InstanceKlass* ste_klass = vmClasses::StackTraceElement_klass(); assert(ste_klass != nullptr, "must be loaded"); @@ -1569,7 +1525,7 @@ oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) { Handle snapshot = jdk_internal_vm_ThreadSnapshot::allocate(InstanceKlass::cast(snapshot_klass), CHECK_NULL); jdk_internal_vm_ThreadSnapshot::set_name(snapshot(), cl._thread_name.resolve()); jdk_internal_vm_ThreadSnapshot::set_thread_status(snapshot(), (int)cl._thread_status); - jdk_internal_vm_ThreadSnapshot::set_carrier_thread(snapshot(), carrier_thread()); + jdk_internal_vm_ThreadSnapshot::set_carrier_thread(snapshot(), cl._carrier_thread.resolve()); jdk_internal_vm_ThreadSnapshot::set_stack_trace(snapshot(), trace()); jdk_internal_vm_ThreadSnapshot::set_locks(snapshot(), locks()); if (!cl._blocker.is_empty()) { diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 51543f835c1..514bf07e665 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -246,11 +246,11 @@ final class VirtualThread extends BaseVirtualThread { @Hidden @JvmtiHideEvents public void run() { - vthread.notifyJvmtiStart(); // notify JVMTI + vthread.endFirstTransition(); try { vthread.run(task); } finally { - vthread.notifyJvmtiEnd(); // notify JVMTI + vthread.startFinalTransition(); } } }; @@ -491,8 +491,9 @@ final class VirtualThread extends BaseVirtualThread { @ChangesCurrentThread @ReservedStackAccess private void mount() { - // notify JVMTI before mount - notifyJvmtiMount(/*hide*/true); + startTransition(/*is_mount*/true); + // We assume following volatile accesses provide equivalent + // of acquire ordering, otherwise we need U.loadFence() here. // sets the carrier thread Thread carrier = Thread.currentCarrierThread(); @@ -533,8 +534,9 @@ final class VirtualThread extends BaseVirtualThread { } carrier.clearInterrupt(); - // notify JVMTI after unmount - notifyJvmtiUnmount(/*hide*/false); + // We assume previous volatile accesses provide equivalent + // of release ordering, otherwise we need U.storeFence() here. + endTransition(/*is_mount*/false); } /** @@ -543,11 +545,11 @@ final class VirtualThread extends BaseVirtualThread { */ @Hidden private boolean yieldContinuation() { - notifyJvmtiUnmount(/*hide*/true); + startTransition(/*is_mount*/false); try { return Continuation.yield(VTHREAD_SCOPE); } finally { - notifyJvmtiMount(/*hide*/false); + endTransition(/*is_mount*/true); } } @@ -1401,23 +1403,34 @@ final class VirtualThread extends BaseVirtualThread { this.carrierThread = carrier; } - // -- JVM TI support -- + // The following four methods notify the VM when a "transition" starts and ends. + // A "mount transition" embodies the steps to transfer control from a platform + // thread to a virtual thread, changing the thread identity, and starting or + // resuming the virtual thread's continuation on the carrier. + // An "unmount transition" embodies the steps to transfer control from a virtual + // thread to its carrier, suspending the virtual thread's continuation, and + // restoring the thread identity to the platform thread. + // The notifications to the VM are necessary in order to coordinate with functions + // (JVMTI mostly) that disable transitions for one or all virtual threads. Starting + // a transition may block if transitions are disabled. Ending a transition may + // notify a thread that is waiting to disable transitions. The notifications are + // also used to post JVMTI events for virtual thread start and end. @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiStart(); + private native void endFirstTransition(); @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiEnd(); + private native void startFinalTransition(); @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiMount(boolean hide); + private native void startTransition(boolean is_mount); @IntrinsicCandidate @JvmtiMountTransition - private native void notifyJvmtiUnmount(boolean hide); + private native void endTransition(boolean is_mount); @IntrinsicCandidate private static native void notifyJvmtiDisableSuspend(boolean enter); diff --git a/src/java.base/share/native/libjava/VirtualThread.c b/src/java.base/share/native/libjava/VirtualThread.c index 3cacf89e752..5936031f926 100644 --- a/src/java.base/share/native/libjava/VirtualThread.c +++ b/src/java.base/share/native/libjava/VirtualThread.c @@ -32,10 +32,10 @@ #define VIRTUAL_THREAD "Ljava/lang/VirtualThread;" static JNINativeMethod methods[] = { - { "notifyJvmtiStart", "()V", (void *)&JVM_VirtualThreadStart }, - { "notifyJvmtiEnd", "()V", (void *)&JVM_VirtualThreadEnd }, - { "notifyJvmtiMount", "(Z)V", (void *)&JVM_VirtualThreadMount }, - { "notifyJvmtiUnmount", "(Z)V", (void *)&JVM_VirtualThreadUnmount }, + { "endFirstTransition", "()V", (void *)&JVM_VirtualThreadEndFirstTransition }, + { "startFinalTransition", "()V", (void *)&JVM_VirtualThreadStartFinalTransition }, + { "startTransition", "(Z)V", (void *)&JVM_VirtualThreadStartTransition }, + { "endTransition", "(Z)V", (void *)&JVM_VirtualThreadEndTransition }, { "notifyJvmtiDisableSuspend", "(Z)V", (void *)&JVM_VirtualThreadDisableSuspend }, { "postPinnedEvent", "(" STR ")V", (void *)&JVM_VirtualThreadPinnedEvent }, { "takeVirtualThreadListToUnblock", "()" VIRTUAL_THREAD, (void *)&JVM_TakeVirtualThreadListToUnblock}, diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java new file mode 100644 index 00000000000..bd7dc014460 --- /dev/null +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWhenParking.java @@ -0,0 +1,159 @@ +/* + * 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 id=transitions + * @bug 8364343 + * @summary HotSpotDiagnosticMXBean.dumpThreads while virtual threads are parking and unparking + * @requires vm.continuations + * @modules jdk.management + * @library /test/lib + * @run main/othervm/timeout=200 DumpThreadsWhenParking 1000 1 100 + */ + +/* + * @test id=concurrent + * @summary HotSpotDiagnosticMXBean.dumpThreads from concurrent threads while virtual threads + * are parking and unparking + * @requires vm.continuations + * @modules jdk.management + * @library /test/lib + * @run main/othervm/timeout=200 DumpThreadsWhenParking 100 4 100 + */ + +/* + * @test id=concurrent_gcstress + * @summary HotSpotDiagnosticMXBean.dumpThreads from concurrent threads while virtual threads + * are parking and unparking + * @requires vm.debug == true & vm.continuations + * @modules jdk.management + * @library /test/lib + * @run main/othervm/timeout=200 -XX:+UnlockDiagnosticVMOptions -XX:+FullGCALot -XX:FullGCALotInterval=10000 DumpThreadsWhenParking 100 4 100 + */ + +import java.lang.management.ManagementFactory; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.Phaser; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.LockSupport; +import java.util.stream.IntStream; +import com.sun.management.HotSpotDiagnosticMXBean; +import jdk.test.lib.thread.VThreadRunner; +import jdk.test.lib.threaddump.ThreadDump; + +public class DumpThreadsWhenParking { + + public static void main(String... args) throws Throwable { + int vthreadCount = Integer.parseInt(args[0]); + int concurrentDumpers = Integer.parseInt(args[1]); + int iterations = Integer.parseInt(args[2]); + + // need >=2 carriers to make progress + VThreadRunner.ensureParallelism(2); + + try (var executor = Executors.newVirtualThreadPerTaskExecutor(); + var pool = Executors.newCachedThreadPool()) { + + // start virtual threads that park and unpark + var done = new AtomicBoolean(); + var phaser = new Phaser(vthreadCount + 1); + for (int i = 0; i < vthreadCount; i++) { + executor.submit(() -> { + phaser.arriveAndAwaitAdvance(); + while (!done.get()) { + LockSupport.parkNanos(1); + } + }); + } + // wait for all virtual threads to start so all have a non-empty stack + System.out.format("Waiting for %d virtual threads to start ...%n", vthreadCount); + phaser.arriveAndAwaitAdvance(); + System.out.format("%d virtual threads started.%n", vthreadCount); + + // Bash on HotSpotDiagnosticMXBean.dumpThreads from >= 1 threads + try { + String containerName = Objects.toIdentityString(executor); + for (int i = 1; i <= iterations; i++) { + System.out.format("%s %d of %d ...%n", Instant.now(), i, iterations); + List> futures = IntStream.of(0, concurrentDumpers) + .mapToObj(_ -> pool.submit(() -> dumpThreads(containerName, vthreadCount))) + .toList(); + for (Future future : futures) { + future.get(); + } + } + } finally { + done.set(true); + } + } + } + + /** + * Invoke HotSpotDiagnosticMXBean.dumpThreads to generate a thread dump to a file in + * JSON format. Parse the thread dump to ensure it contains a thread grouping with + * the expected number of virtual threads. + */ + static Void dumpThreads(String containerName, int expectedVThreadCount) throws Exception { + long tid = Thread.currentThread().threadId(); + Path file = Path.of("threads-" + tid + ".json").toAbsolutePath(); + Files.deleteIfExists(file); + ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class) + .dumpThreads(file.toString(), HotSpotDiagnosticMXBean.ThreadDumpFormat.JSON); + + // read and parse the dump + String jsonText = Files.readString(file); + ThreadDump threadDump = ThreadDump.parse(jsonText); + var container = threadDump.findThreadContainer(containerName).orElse(null); + if (container == null) { + fail(containerName + " not found in thread dump"); + } + + // check expected virtual thread count + long threadCount = container.threads().count(); + if (threadCount != expectedVThreadCount) { + fail(threadCount + " virtual threads found, expected " + expectedVThreadCount); + } + + // check each thread is a virtual thread with stack frames + container.threads().forEach(t -> { + if (!t.isVirtual()) { + fail("#" + t.tid() + "(" + t.name() + ") is not a virtual thread"); + } + long stackFrameCount = t.stack().count(); + if (stackFrameCount == 0) { + fail("#" + t.tid() + " has empty stack"); + } + }); + return null; + } + + private static void fail(String message) { + throw new RuntimeException(message); + } +} diff --git a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java index 4cbd0de460c..787d53ae045 100644 --- a/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java +++ b/test/jdk/com/sun/management/HotSpotDiagnosticMXBean/DumpThreadsWithEliminatedLock.java @@ -43,6 +43,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; import java.util.List; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -73,9 +74,11 @@ public class DumpThreadsWithEliminatedLock { // A thread that spins creating and adding to a StringBuffer. StringBuffer is // synchronized, assume object will be scalar replaced and the lock eliminated. + var started = new CountDownLatch(1); var done = new AtomicBoolean(); var ref = new AtomicReference(); Thread thread = factory.newThread(() -> { + started.countDown(); while (!done.get()) { StringBuffer sb = new StringBuffer(); sb.append(System.currentTimeMillis()); @@ -85,6 +88,7 @@ public class DumpThreadsWithEliminatedLock { }); try { thread.start(); + started.await(); if (plain) { testPlainFormat(); } else { From 5ea2b6402114d34465b2ad9e476ab8e36ddeea06 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Wed, 3 Dec 2025 20:03:33 +0000 Subject: [PATCH 038/141] 8372977: unnecessary gthread-2.0 loading Reviewed-by: prr, kizune --- .../native/libawt_xawt/awt/gtk3_interface.c | 21 ------------------- .../native/libawt_xawt/awt/gtk_interface.h | 6 ------ 2 files changed, 27 deletions(-) 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 e5b2dfa6db9..03dba969e8d 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 @@ -42,7 +42,6 @@ #include "debug_assert.h" static void *gtk3_libhandle = NULL; -static void *gthread_libhandle = NULL; static void transform_detail_string (const gchar *detail, GtkStyleContext *context); @@ -79,15 +78,6 @@ static void* dl_symbol(const char* name) return result; } -static void* dl_symbol_gthread(const char* name) -{ - void* result = dlsym(gthread_libhandle, name); - if (!result) - longjmp(j, NO_SYMBOL_EXCEPTION); - - return result; -} - gboolean gtk3_check(const char* lib_name, gboolean load) { if (gtk3_libhandle != NULL) { @@ -264,13 +254,6 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) return FALSE; } - gthread_libhandle = dlopen(GTHREAD_LIB_VERSIONED, RTLD_LAZY | RTLD_LOCAL); - if (gthread_libhandle == NULL) { - gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL); - if (gthread_libhandle == NULL) - return FALSE; - } - if (setjmp(j) == 0) { fp_gtk_check_version = dl_symbol("gtk_check_version"); @@ -634,9 +617,6 @@ GtkApi* gtk3_load(JNIEnv *env, const char* lib_name) dlclose(gtk3_libhandle); gtk3_libhandle = NULL; - dlclose(gthread_libhandle); - gthread_libhandle = NULL; - return NULL; } @@ -735,7 +715,6 @@ static int gtk3_unload() dlerror(); dlclose(gtk3_libhandle); - dlclose(gthread_libhandle); if ((gtk3_error = dlerror()) != NULL) { return FALSE; 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 11ec245ce8b..39be6a735d7 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 @@ -38,9 +38,6 @@ #define TRUE (!FALSE) #endif -#define GTHREAD_LIB_VERSIONED VERSIONED_JNI_LIB_NAME("gthread-2.0", "0") -#define GTHREAD_LIB JNI_LIB_NAME("gthread-2.0") - #define _G_TYPE_CIC(ip, gt, ct) ((ct*) ip) #define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type) \ (_G_TYPE_CIC ((instance), (g_type), c_type)) @@ -850,9 +847,6 @@ typedef struct GtkApi { gboolean gtk_load(JNIEnv *env, GtkVersion version, gboolean verbose); gboolean gtk_check_version(GtkVersion version); -typedef struct _GThreadFunctions GThreadFunctions; -static gboolean (*fp_g_thread_get_initialized)(void); -static void (*fp_g_thread_init)(GThreadFunctions *vtable); static void (*fp_gdk_threads_init)(void); static void (*fp_gdk_threads_enter)(void); static void (*fp_gdk_threads_leave)(void); From 70e2bc876abe35b3d447f8004245bdbf2fead59f Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Wed, 3 Dec 2025 21:32:29 +0000 Subject: [PATCH 039/141] 8372816: New test sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java succeeds in case of error Reviewed-by: azeller, mdoerr --- .../provider/acvp/ML_DSA_Intrinsic_Test.java | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java index ea04b3c7eec..7f057603323 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java @@ -28,13 +28,6 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import java.util.HexFormat; -/* - * @test - * @library /test/lib - * @key randomness - * @modules java.base/sun.security.provider:+open - * @run main/othervm ML_DSA_Intrinsic_Test -XX:+UnlockDiagnosticVMOptions -XX:-UseDilithiumIntrinsics - */ /* * @test * @requires os.simpleArch == "x64" @@ -55,7 +48,7 @@ import java.util.HexFormat; // -XX:+UnlockDiagnosticVMOptions -XX:+UseDilithiumIntrinsics test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java public class ML_DSA_Intrinsic_Test { - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Exception, Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); Class kClazz = sun.security.provider.ML_DSA.class; @@ -114,27 +107,23 @@ public class ML_DSA_Intrinsic_Test { long seed = rnd.nextLong(); rnd.setSeed(seed); //Note: it might be useful to increase this number during development of new intrinsics - final int repeat = 10000000; + final int repeat = 10000; int[] coeffs1 = new int[ML_DSA_N]; int[] coeffs2 = new int[ML_DSA_N]; int[] prod1 = new int[ML_DSA_N]; int[] prod2 = new int[ML_DSA_N]; int[] prod3 = new int[ML_DSA_N]; int[] prod4 = new int[ML_DSA_N]; - try { - for (int i = 0; i < repeat; i++) { - // Hint: if test fails, you can hardcode the seed to make the test more reproducible: - // rnd.setSeed(seed); - testMult(prod1, prod2, coeffs1, coeffs2, mult, multJava, rnd, seed, i); - testMultConst(prod1, prod2, multConst, multConstJava, rnd, seed, i); - testDecompose(prod1, prod2, prod3, prod4, coeffs1, coeffs2, decompose, decomposeJava, rnd, seed, i); - testAlmostNtt(coeffs1, coeffs2, almostNtt, almostNttJava, rnd, seed, i); - testInverseNtt(coeffs1, coeffs2, inverseNtt, inverseNttJava, rnd, seed, i); - } - System.out.println("Fuzz Success"); - } catch (Throwable e) { - System.out.println("Fuzz Failed: " + e); + for (int i = 0; i < repeat; i++) { + // Hint: if test fails, you can hardcode the seed to make the test more reproducible: + // rnd.setSeed(seed); + testMult(prod1, prod2, coeffs1, coeffs2, mult, multJava, rnd, seed, i); + testMultConst(prod1, prod2, multConst, multConstJava, rnd, seed, i); + testDecompose(prod1, prod2, prod3, prod4, coeffs1, coeffs2, decompose, decomposeJava, rnd, seed, i); + testAlmostNtt(coeffs1, coeffs2, almostNtt, almostNttJava, rnd, seed, i); + testInverseNtt(coeffs1, coeffs2, inverseNtt, inverseNttJava, rnd, seed, i); } + System.out.println("Fuzz Success"); } private static final int ML_DSA_N = 256; From 9b386014a01b2bff47856bf9a8e113317db1f081 Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Wed, 3 Dec 2025 21:58:17 +0000 Subject: [PATCH 040/141] 8373049: Update JCStress test suite Reviewed-by: epavlova, lmesnik --- test/hotspot/jtreg/applications/jcstress/JcstressRunner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java b/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java index a0c9488dfe3..eb785b06330 100644 --- a/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java +++ b/test/hotspot/jtreg/applications/jcstress/JcstressRunner.java @@ -45,7 +45,7 @@ import java.util.List; revision = JcstressRunner.VERSION, extension = "jar", unpack = false) public class JcstressRunner { - public static final String VERSION = "0.17-SNAPSHOT-20241217"; + public static final String VERSION = "0.17-SNAPSHOT-20250619"; public static final String MAIN_CLASS = "org.openjdk.jcstress.Main"; public static final String TIME_BUDGET_PROPERTY = "jcstress.time_budget"; From 1294d55b194704dce92c5132d6779e6f4d4850e6 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Wed, 3 Dec 2025 22:42:47 +0000 Subject: [PATCH 041/141] 8372769: Test runtime/handshake/HandshakeDirectTest.java failed - JVMTI ERROR 13 Reviewed-by: lmesnik, pchilanomate, cjplummer, amenkov --- .../jtreg/runtime/handshake/HandshakeDirectTest.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java b/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java index af43c6059d5..600ef6089a6 100644 --- a/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java +++ b/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,7 @@ public class HandshakeDirectTest implements Runnable { static Object[] locks = new Object[WORKING_THREADS]; static AtomicInteger handshakeCount = new AtomicInteger(0); - static void suspendThread(Thread t) { + static boolean suspendThread(Thread t) { try { JVMTIUtils.suspendThread(t); } catch (JVMTIUtils.JvmtiException e) { @@ -56,7 +56,9 @@ public class HandshakeDirectTest implements Runnable { && e.getCode() != JVMTIUtils.JVMTI_ERROR_WRONG_PHASE) { throw e; } + return false; // failed to suspend } + return true; // suspended } static void resumeThread(Thread t) { @@ -115,7 +117,10 @@ public class HandshakeDirectTest implements Runnable { public void run() { while (true) { int i = ThreadLocalRandom.current().nextInt(0, WORKING_THREADS - 1); - suspendThread(workingThreads[i]); + boolean suspended = suspendThread(workingThreads[i]); + if (!suspended) { + continue; // skip resumeThread call if thread was not suspended + } try { Thread.sleep(1); // sleep for 1 ms } catch(InterruptedException ie) { From db2a5420a2e3d0f5f0f066eace37a8fd4f075802 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 3 Dec 2025 22:43:17 +0000 Subject: [PATCH 042/141] 8372861: Genshen: Override parallel_region_stride of ShenandoahResetBitmapClosure to a reasonable value for better parallelism Reviewed-by: kdnilsen, shade, wkemper --- src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp | 3 +++ src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp | 2 +- src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp | 1 + .../share/gc/shenandoah/shenandoahHeapRegionClosures.hpp | 8 ++++++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index ea421365614..123bd792126 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -76,6 +76,9 @@ public: } } + // Bitmap reset task is heavy-weight and benefits from much smaller tasks than the default. + size_t parallel_region_stride() override { return 8; } + bool is_thread_safe() override { return true; } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 5c4d10ca8a5..6d569e9b4ce 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1962,7 +1962,7 @@ void ShenandoahHeap::parallel_heap_region_iterate(ShenandoahHeapRegionClosure* b assert(blk->is_thread_safe(), "Only thread-safe closures here"); const uint active_workers = workers()->active_workers(); const size_t n_regions = num_regions(); - size_t stride = ShenandoahParallelRegionStride; + size_t stride = blk->parallel_region_stride(); if (stride == 0 && active_workers > 1) { // Automatically derive the stride to balance the work between threads // evenly. Do not try to split work if below the reasonable threshold. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index cd388ee7cf3..65e3803627c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -113,6 +113,7 @@ public: class ShenandoahHeapRegionClosure : public StackObj { public: virtual void heap_region_do(ShenandoahHeapRegion* r) = 0; + virtual size_t parallel_region_stride() { return ShenandoahParallelRegionStride; } virtual bool is_thread_safe() { return false; } }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp index 0daf268628c..3f3b57c9bb2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionClosures.hpp @@ -44,6 +44,10 @@ public: } } + size_t parallel_region_stride() override { + return _closure->parallel_region_stride(); + } + bool is_thread_safe() override { return _closure->is_thread_safe(); } @@ -64,6 +68,10 @@ public: } } + size_t parallel_region_stride() override { + return _closure->parallel_region_stride(); + } + bool is_thread_safe() override { return _closure->is_thread_safe(); } From 8f8fda7c80b57e8a36827cc260f0be0e5d61f6a6 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Wed, 3 Dec 2025 22:46:18 +0000 Subject: [PATCH 043/141] 8373048: Genshen: Remove dead code from Shenandoah Reviewed-by: wkemper --- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 115 +----------------- .../gc/shenandoah/shenandoahGeneration.cpp | 2 - .../shenandoah/shenandoahGenerationalHeap.cpp | 13 -- .../shenandoah/shenandoahGenerationalHeap.hpp | 12 -- .../shenandoahHeapRegion.inline.hpp | 2 +- .../shenandoah/shenandoahRegulatorThread.hpp | 1 - .../shenandoah/shenandoahScanRemembered.hpp | 2 - 7 files changed, 2 insertions(+), 145 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index ab7985b3d34..6a6cad68fd9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -175,7 +175,6 @@ ShenandoahRegionPartitions::ShenandoahRegionPartitions(size_t max_regions, Shena void ShenandoahFreeSet::account_for_pip_regions(size_t mutator_regions, size_t mutator_bytes, size_t collector_regions, size_t collector_bytes) { shenandoah_assert_heaplocked(); - size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); // We have removed all of these regions from their respective partition. Each pip region is "in" the NotFree partition. // We want to account for all pip pad memory as if it had been consumed from within the Mutator partition. @@ -1605,18 +1604,13 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah } } - size_t ac = alloc_capacity(r); ShenandoahFreeSetPartitionId orig_partition; - ShenandoahGeneration* request_generation = nullptr; if (req.is_mutator_alloc()) { - request_generation = _heap->mode()->is_generational()? _heap->young_generation(): _heap->global_generation(); orig_partition = ShenandoahFreeSetPartitionId::Mutator; } else if (req.is_old()) { - request_generation = _heap->old_generation(); orig_partition = ShenandoahFreeSetPartitionId::OldCollector; } else { // Not old collector alloc, so this is a young collector gclab or shared allocation - request_generation = _heap->mode()->is_generational()? _heap->young_generation(): _heap->global_generation(); orig_partition = ShenandoahFreeSetPartitionId::Collector; } if (alloc_capacity(r) < PLAB::min_size() * HeapWordSize) { @@ -1688,7 +1682,6 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req, bo idx_t num = ShenandoahHeapRegion::required_regions(words_size * HeapWordSize); assert(req.is_young(), "Humongous regions always allocated in YOUNG"); - ShenandoahGeneration* generation = _heap->generation_for(req.affiliation()); // Check if there are enough regions left to satisfy allocation. if (num > (idx_t) _partitions.count(ShenandoahFreeSetPartitionId::Mutator)) { @@ -1833,107 +1826,7 @@ HeapWord* ShenandoahFreeSet::allocate_contiguous(ShenandoahAllocRequest& req, bo } class ShenandoahRecycleTrashedRegionClosure final : public ShenandoahHeapRegionClosure { -private: - static const ssize_t SentinelUsed = -1; - static const ssize_t SentinelIndex = -1; - static const size_t MaxSavedRegions = 128; - - ShenandoahRegionPartitions* _partitions; - volatile size_t _recycled_region_count; - ssize_t _region_indices[MaxSavedRegions]; - ssize_t _region_used[MaxSavedRegions]; - - void get_lock_and_flush_buffer(size_t region_count, size_t overflow_region_used, size_t overflow_region_index) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); - ShenandoahHeapLocker locker(heap->lock()); - size_t recycled_regions = AtomicAccess::load(&_recycled_region_count); - size_t region_tallies[int(ShenandoahRegionPartitions::NumPartitions)]; - size_t used_byte_tallies[int(ShenandoahRegionPartitions::NumPartitions)]; - for (int p = 0; p < int(ShenandoahRegionPartitions::NumPartitions); p++) { - region_tallies[p] = 0; - used_byte_tallies[p] = 0; - } - ShenandoahFreeSetPartitionId p = _partitions->membership(overflow_region_index); - used_byte_tallies[int(p)] += overflow_region_used; - if (region_count <= recycled_regions) { - // _recycled_region_count has not been decremented after I incremented it to obtain region_count, so I will - // try to flush the buffer. - - // Multiple worker threads may attempt to flush this buffer. The first thread to acquire the lock does the work. - // _recycled_region_count is only decreased while holding the heap lock. - if (region_count > recycled_regions) { - region_count = recycled_regions; - } - for (size_t i = 0; i < region_count; i++) { - ssize_t used; - // wait for other threads to finish updating their entries within the region buffer before processing entry - do { - used = _region_used[i]; - } while (used == SentinelUsed); - ssize_t index; - do { - index = _region_indices[i]; - } while (index == SentinelIndex); - - ShenandoahFreeSetPartitionId p = _partitions->membership(index); - assert(p != ShenandoahFreeSetPartitionId::NotFree, "Trashed regions should be in a free partition"); - used_byte_tallies[int(p)] += used; - region_tallies[int(p)]++; - } - if (region_count > 0) { - for (size_t i = 0; i < MaxSavedRegions; i++) { - _region_indices[i] = SentinelIndex; - _region_used[i] = SentinelUsed; - } - } - - // The almost last thing we do before releasing the lock is to set the _recycled_region_count to 0. What happens next? - // - // 1. Any worker thread that attempted to buffer a new region while we were flushing the buffer will have seen - // that _recycled_region_count > MaxSavedRegions. All such worker threads will first wait for the lock, then - // discover that the _recycled_region_count is zero, then, while holding the lock, they will process the - // region so it doesn't have to be placed into the buffer. This handles the large majority of cases. - // - // 2. However, there's a race that can happen, which will result in someewhat different behavior. Suppose - // this thread resets _recycled_region_count to 0. Then some other worker thread increments _recycled_region_count - // in order to stores its region into the buffer and suppose this happens before all of the other worker threads - // which are waiting to acquire the heap lock have finished their efforts to flush the buffer. If this happens, - // then the workers who are waiting to acquire the heap lock and flush the buffer will find that _recycled_region_count - // has decreased from the value it held when they last tried to increment its value. In this case, these worker - // threads will process their overflow region while holding the lock, but they will not attempt to process regions - // newly placed into the buffer. Otherwise, confusion could result. - // - // Assumption: all worker threads who are attempting to acquire lock and flush buffer will finish their efforts before - // the buffer once again overflows. - // How could we avoid depending on this assumption? - // 1. Let MaxSavedRegions be as large as number of regions, or at least as large as the collection set. - // 2. Keep a count of how many times the buffer has been flushed per instantation of the - // ShenandoahRecycleTrashedRegionClosure object, and only consult/update this value while holding the heap lock. - // Need to think about how this helps resolve the race. - _recycled_region_count = 0; - } else { - // Some other thread has already processed the buffer, resetting _recycled_region_count to zero. Its current value - // may be greater than zero because other workers may have accumulated entries into the buffer. But it is "extremely" - // unlikely that it will overflow again before all waiting workers have had a chance to clear their state. While I've - // got the heap lock, I'll go ahead and update the global state for my overflow region. I'll let other heap regions - // accumulate in the buffer to be processed when the buffer is once again full. - region_count = 0; - } - for (size_t p = 0; p < int(ShenandoahRegionPartitions::NumPartitions); p++) { - _partitions->decrease_used(ShenandoahFreeSetPartitionId(p), used_byte_tallies[p]); - } - } - public: - ShenandoahRecycleTrashedRegionClosure(ShenandoahRegionPartitions* p): ShenandoahHeapRegionClosure() { - _partitions = p; - _recycled_region_count = 0; - for (size_t i = 0; i < MaxSavedRegions; i++) { - _region_indices[i] = SentinelIndex; - _region_used[i] = SentinelUsed; - } - } - void heap_region_do(ShenandoahHeapRegion* r) { r->try_recycle(); } @@ -1950,14 +1843,12 @@ void ShenandoahFreeSet::recycle_trash() { ShenandoahHeap* heap = ShenandoahHeap::heap(); heap->assert_gc_workers(heap->workers()->active_workers()); - ShenandoahRecycleTrashedRegionClosure closure(&_partitions); + ShenandoahRecycleTrashedRegionClosure closure; heap->parallel_heap_region_iterate(&closure); } bool ShenandoahFreeSet::transfer_one_region_from_mutator_to_old_collector(size_t idx, size_t alloc_capacity) { ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); - ShenandoahYoungGeneration* young_gen = gen_heap->young_generation(); - ShenandoahOldGeneration* old_gen = gen_heap->old_generation(); size_t region_size_bytes = ShenandoahHeapRegion::region_size_bytes(); assert(alloc_capacity == region_size_bytes, "Region must be empty"); if (young_unaffiliated_regions() > 0) { @@ -1985,7 +1876,6 @@ bool ShenandoahFreeSet::flip_to_old_gc(ShenandoahHeapRegion* r) { assert(_partitions.partition_id_matches(idx, ShenandoahFreeSetPartitionId::Mutator), "Should be in mutator view"); assert(can_allocate_from(r), "Should not be allocated"); - ShenandoahGenerationalHeap* gen_heap = ShenandoahGenerationalHeap::heap(); const size_t region_alloc_capacity = alloc_capacity(r); if (transfer_one_region_from_mutator_to_old_collector(idx, region_alloc_capacity)) { @@ -2133,7 +2023,6 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r size_t total_mutator_regions = 0; size_t total_old_collector_regions = 0; - bool is_generational = _heap->mode()->is_generational(); size_t num_regions = _heap->num_regions(); for (size_t idx = 0; idx < num_regions; idx++) { ShenandoahHeapRegion* region = _heap->get_region(idx); @@ -2222,7 +2111,6 @@ void ShenandoahFreeSet::find_regions_with_alloc_capacity(size_t &young_trashed_r } } else { assert(_partitions.membership(idx) == ShenandoahFreeSetPartitionId::NotFree, "Region should have been retired"); - size_t ac = alloc_capacity(region); size_t humongous_waste_bytes = 0; if (region->is_humongous_start()) { oop obj = cast_to_oop(region->bottom()); @@ -3120,7 +3008,6 @@ void ShenandoahFreeSet::log_status() { size_t total_used = 0; size_t total_free = 0; size_t total_free_ext = 0; - size_t total_trashed_free = 0; for (idx_t idx = _partitions.leftmost(ShenandoahFreeSetPartitionId::Mutator); idx <= _partitions.rightmost(ShenandoahFreeSetPartitionId::Mutator); idx++) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 123bd792126..55d6033b3bc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -527,7 +527,6 @@ size_t ShenandoahGeneration::select_aged_regions(const size_t old_promotion_rese assert_no_in_place_promotions(); auto const heap = ShenandoahGenerationalHeap::heap(); - ShenandoahYoungGeneration* young_gen = heap->young_generation(); ShenandoahFreeSet* free_set = heap->free_set(); bool* const candidate_regions_for_promotion_by_copy = heap->collection_set()->preselected_regions(); ShenandoahMarkingContext* const ctx = heap->marking_context(); @@ -565,7 +564,6 @@ size_t ShenandoahGeneration::select_aged_regions(const size_t old_promotion_rese size_t pip_mutator_bytes = 0; size_t pip_collector_bytes = 0; - size_t min_remnant_size = PLAB::min_size() * HeapWordSize; for (idx_t i = 0; i < num_regions; i++) { ShenandoahHeapRegion* const r = heap->get_region(i); if (r->is_empty() || !r->has_live() || !r->is_young() || !r->is_regular()) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp index 134ae371bce..f887cc9064e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.cpp @@ -688,19 +688,6 @@ void ShenandoahGenerationalHeap::reset_generation_reserves() { old_generation()->set_promoted_reserve(0); } -void ShenandoahGenerationalHeap::TransferResult::print_on(const char* when, outputStream* ss) const { - auto heap = ShenandoahGenerationalHeap::heap(); - ShenandoahYoungGeneration* const young_gen = heap->young_generation(); - ShenandoahOldGeneration* const old_gen = heap->old_generation(); - const size_t young_available = young_gen->available(); - const size_t old_available = old_gen->available(); - ss->print_cr("After %s, %s %zu regions to %s to prepare for next gc, old available: " - PROPERFMT ", young_available: " PROPERFMT, - when, - success? "successfully transferred": "failed to transfer", region_count, region_destination, - PROPERFMTARGS(old_available), PROPERFMTARGS(young_available)); -} - void ShenandoahGenerationalHeap::coalesce_and_fill_old_regions(bool concurrent) { class ShenandoahGlobalCoalesceAndFill : public WorkerTask { private: diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp index 704c8538397..736026916f7 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalHeap.hpp @@ -132,24 +132,12 @@ public: bool requires_barriers(stackChunkOop obj) const override; - // Used for logging the result of a region transfer outside the heap lock - struct TransferResult { - bool success; - size_t region_count; - const char* region_destination; - - void print_on(const char* when, outputStream* ss) const; - }; - // Zeros out the evacuation and promotion reserves 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); - // Transfers surplus old regions to young, or takes regions from young to satisfy old region deficit - TransferResult balance_generations(); - // Balances generations, coalesces and fills old regions if necessary void complete_degenerated_cycle(); void complete_concurrent_cycle(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp index 636f65e2553..4feeed815da 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp @@ -157,7 +157,7 @@ inline void ShenandoahHeapRegion::increase_live_data_gc_words(size_t s) { } inline void ShenandoahHeapRegion::internal_increase_live_data(size_t s) { - size_t new_live_data = AtomicAccess::add(&_live_data, s, memory_order_relaxed); + AtomicAccess::add(&_live_data, s, memory_order_relaxed); } inline void ShenandoahHeapRegion::clear_live_data() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp index c23690b15d6..2519025b6fb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.hpp @@ -62,7 +62,6 @@ class ShenandoahRegulatorThread: public ConcurrentGCThread { bool start_old_cycle() const; bool start_young_cycle() const; bool start_global_cycle() const; - bool resume_old_cycle(); // The generational mode can only unload classes in a global cycle. The regulator // thread itself will trigger a global cycle if metaspace is out of memory. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index 9a0d28d2cb7..c758873a040 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -233,8 +233,6 @@ public: inline bool is_write_card_dirty(size_t card_index) const; inline void mark_card_as_dirty(size_t card_index); inline void mark_range_as_dirty(size_t card_index, size_t num_cards); - inline void mark_card_as_clean(size_t card_index); - inline void mark_range_as_clean(size_t card_index, size_t num_cards); inline bool is_card_dirty(HeapWord* p) const; inline bool is_write_card_dirty(HeapWord* p) const; inline void mark_card_as_dirty(HeapWord* p); From 4856344668042fcbc4d15966519d27fb0a4f509f Mon Sep 17 00:00:00 2001 From: Chad Rakoczy Date: Thu, 4 Dec 2025 00:21:53 +0000 Subject: [PATCH 044/141] 8371046: Segfault in compiler/whitebox/StressNMethodRelocation.java with -XX:+UseZGC Reviewed-by: kvn, eastigeevich --- src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp | 2 +- src/hotspot/share/asm/codeBuffer.cpp | 2 +- src/hotspot/share/asm/codeBuffer.hpp | 2 +- src/hotspot/share/code/nmethod.cpp | 57 ++++++++++++------- src/hotspot/share/code/nmethod.hpp | 3 + src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + src/hotspot/share/prims/whitebox.cpp | 2 +- 7 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 94694b58d2f..dbec2d76d4f 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -85,7 +85,7 @@ void Relocation::pd_set_call_destination(address x) { } else { MacroAssembler::pd_patch_instruction(addr(), x); } - assert(pd_call_destination(addr()) == x, "fail in reloc"); + guarantee(pd_call_destination(addr()) == x, "fail in reloc"); } void trampoline_stub_Relocation::pd_fix_owner_after_move() { diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 2c6b7d7e96e..7871134e923 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -90,7 +90,7 @@ typedef CodeBuffer::csize_t csize_t; // file-local definition // External buffer, in a predefined CodeBlob. // Important: The code_start must be taken exactly, and not realigned. -CodeBuffer::CodeBuffer(CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(*this))) { +CodeBuffer::CodeBuffer(const CodeBlob* blob) DEBUG_ONLY(: Scrubber(this, sizeof(*this))) { // Provide code buffer with meaningful name initialize_misc(blob->name()); initialize(blob->content_begin(), blob->content_size()); diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 430d4949467..38e151273da 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -672,7 +672,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) { } // (2) CodeBuffer referring to pre-allocated CodeBlob. - CodeBuffer(CodeBlob* blob); + CodeBuffer(const CodeBlob* blob); // (3) code buffer allocating codeBlob memory for code & relocation // info but with lazy initialization. The name must be something diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index c2f8b46f00e..edfca5c98ee 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1498,6 +1498,40 @@ nmethod::nmethod(const nmethod &nm) : CodeBlob(nm._name, nm._kind, nm._size, nm. // - OOP table memcpy(consts_begin(), nm.consts_begin(), nm.data_end() - nm.consts_begin()); + // Fix relocation + RelocIterator iter(this); + CodeBuffer src(&nm); + CodeBuffer dst(this); + while (iter.next()) { +#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER + // After an nmethod is moved, some direct call sites may end up out of range. + // CallRelocation::fix_relocation_after_move() assumes the target is always + // reachable and does not check branch range. Calling it without range checks + // could cause us to write an offset too large for the instruction. + // + // If a call site has a trampoline, we skip the normal call relocation. The + // associated trampoline_stub_Relocation will handle the call and the + // trampoline, including range checks and updating the branch as needed. + // + // If no trampoline exists, we can assume the call target is always + // reachable and therefore within direct branch range, so calling + // CallRelocation::fix_relocation_after_move() is safe. + if (iter.reloc()->is_call()) { + address trampoline = trampoline_stub_Relocation::get_trampoline_for(iter.reloc()->addr(), this); + if (trampoline != nullptr) { + continue; + } + } +#endif + + iter.reloc()->fix_relocation_after_move(&src, &dst); + } + + { + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); + clear_inline_caches(); + } + post_init(); } @@ -1521,25 +1555,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { return nullptr; } - // Fix relocation - RelocIterator iter(nm_copy); - CodeBuffer src(this); - CodeBuffer dst(nm_copy); - while (iter.next()) { -#ifdef USE_TRAMPOLINE_STUB_FIX_OWNER - // Direct calls may no longer be in range and the use of a trampoline may now be required. - // Instead, allow trampoline relocations to update their owners and perform the necessary checks. - if (iter.reloc()->is_call()) { - address trampoline = trampoline_stub_Relocation::get_trampoline_for(iter.reloc()->addr(), nm_copy); - if (trampoline != nullptr) { - continue; - } - } -#endif - - iter.reloc()->fix_relocation_after_move(&src, &dst); - } - // To make dependency checking during class loading fast, record // the nmethod dependencies in the classes it is dependent on. // This allows the dependency checking code to simply walk the @@ -1569,8 +1584,6 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { if (!is_marked_for_deoptimization() && is_in_use()) { assert(method() != nullptr && method()->code() == this, "should be if is in use"); - nm_copy->clear_inline_caches(); - // Attempt to start using the copy if (nm_copy->make_in_use()) { ICache::invalidate_range(nm_copy->code_begin(), nm_copy->code_size()); @@ -1578,7 +1591,7 @@ nmethod* nmethod::relocate(CodeBlobType code_blob_type) { methodHandle mh(Thread::current(), nm_copy->method()); nm_copy->method()->set_code(mh, nm_copy); - make_not_used(); + make_not_entrant(InvalidationReason::RELOCATED); nm_copy->post_compiled_method_load_event(); diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 0fa9d7fda9e..2391bc6d830 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -499,6 +499,7 @@ public: UNCOMMON_TRAP, WHITEBOX_DEOPTIMIZATION, ZOMBIE, + RELOCATED, INVALIDATION_REASONS_COUNT }; @@ -543,6 +544,8 @@ public: return "whitebox deoptimization"; case InvalidationReason::ZOMBIE: return "zombie"; + case InvalidationReason::RELOCATED: + return "relocated"; default: { assert(false, "Unhandled reason"); return "Unknown"; diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 7f009eba5f1..77e98db9156 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -586,6 +586,7 @@ declare_constant(nmethod::InvalidationReason::UNCOMMON_TRAP) \ declare_constant(nmethod::InvalidationReason::WHITEBOX_DEOPTIMIZATION) \ declare_constant(nmethod::InvalidationReason::ZOMBIE) \ + declare_constant(nmethod::InvalidationReason::RELOCATED) \ \ declare_constant(CodeInstaller::VERIFIED_ENTRY) \ declare_constant(CodeInstaller::UNVERIFIED_ENTRY) \ diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 5514f7d3260..bbd7b4bf795 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1678,7 +1678,7 @@ WB_ENTRY(void, WB_RelocateNMethodFromAddr(JNIEnv* env, jobject o, jlong addr, ji CodeBlob* blob = CodeCache::find_blob(address); if (blob != nullptr && blob->is_nmethod()) { nmethod* code = blob->as_nmethod(); - if (code->is_in_use()) { + if (code->is_in_use() && !code->is_unloading()) { CompiledICLocker ic_locker(code); code->relocate(static_cast(blob_type)); } From 04c0f8d359a3f450ac2070c6d41834145d9c75f7 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Thu, 4 Dec 2025 01:36:54 +0000 Subject: [PATCH 045/141] 8372857: Improve debuggability of java/rmi/server/RemoteServer/AddrInUse.java test Reviewed-by: msheppar, smarks, syan --- .../rmi/server/RemoteServer/AddrInUse.java | 96 +++++++------------ 1 file changed, 37 insertions(+), 59 deletions(-) diff --git a/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java b/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java index 34e343b6193..86ac5b0313b 100644 --- a/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java +++ b/test/jdk/java/rmi/server/RemoteServer/AddrInUse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, 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 @@ -24,7 +24,6 @@ /* @test * @bug 4111507 * @summary retryServerSocket should not retry on BindException - * @author Ann Wollrath * * @run main/othervm AddrInUse */ @@ -33,75 +32,54 @@ import java.net.ServerSocket; import java.rmi.registry.LocateRegistry; import java.rmi.server.ExportException; -public class AddrInUse implements Runnable { +public class AddrInUse { - private static int port = -1; - private static final long TIMEOUT = 10000; - - private boolean exportSucceeded = false; - private Throwable exportException = null; - - public void run() { - - /* - * Attempt to create (i.e. export) a registry on the port that - * has already been bound, and record the result. - */ - try { - LocateRegistry.createRegistry(port); - synchronized (this) { - exportSucceeded = true; - notifyAll(); - } - } catch (Throwable t) { - synchronized (this) { - exportException = t; - notifyAll(); - } - } - } + private static volatile Throwable registryExportFailure = null; public static void main(String[] args) throws Exception { - System.err.println("\nRegression test for bug 4111507\n"); - /* * Bind a server socket to a port. */ - ServerSocket server = new ServerSocket(0); - port = server.getLocalPort(); - System.err.println("Created a ServerSocket on port " + port + "..."); - - /* - * Start a thread that creates a registry on the same port, - * and analyze the result. - */ - System.err.println("create a registry on the same port..."); - System.err.println("(should cause an ExportException)"); - AddrInUse obj = new AddrInUse(); - synchronized (obj) { - (new Thread(obj, "AddrInUse")).start(); + try (ServerSocket server = new ServerSocket(0)) { + int port = server.getLocalPort(); + System.err.println("Created a ServerSocket on port " + port + "..."); /* - * Don't wait forever (original bug is that the export - * hangs). + * Start a thread that creates a registry on the same port, + * and analyze the result. */ - obj.wait(TIMEOUT); + System.err.println("create a registry on the same port..."); + System.err.println("(should cause an ExportException)"); - if (obj.exportSucceeded) { - throw new RuntimeException( - "TEST FAILED: export on already-bound port succeeded"); - } else if (obj.exportException != null) { - obj.exportException.printStackTrace(); - if (obj.exportException instanceof ExportException) { - System.err.println("TEST PASSED"); - } else { - throw new RuntimeException( - "TEST FAILED: unexpected exception occurred", - obj.exportException); + Thread exportRegistryThread = new Thread(() -> { + /* + * Attempt to create (i.e. export) a registry on the port that + * has already been bound, and record the result. + */ + try { + LocateRegistry.createRegistry(port); + } catch (Throwable t) { + registryExportFailure = t; } - } else { - throw new RuntimeException("TEST FAILED: export timed out"); + }, "ExportRegistry-Thread"); + + exportRegistryThread.start(); + + /* + * Wait for the LocateRegistry.createRegistry() call to complete or + * if it blocks forever (due to the original bug), then let jtreg fail + * the test with a timeout + */ + exportRegistryThread.join(); + if (registryExportFailure == null) { + throw new RuntimeException( + "TEST FAILED: export on already-bound port succeeded"); } + if (!(registryExportFailure instanceof ExportException)) { + throw new RuntimeException( + "TEST FAILED: unexpected exception occurred", registryExportFailure); + } + System.err.println("TEST PASSED, received expected exception: " + registryExportFailure); } } } From db2cd1a4e0ee7b72339e7ee3c0286dc04fc5adbf Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Thu, 4 Dec 2025 02:15:54 +0000 Subject: [PATCH 046/141] 8372756: Mouse additional buttons and horizontal scrolling are broken on XWayland GNOME >= 47 after JDK-8351907 Reviewed-by: prr --- .../unix/classes/sun/awt/X11/XToolkit.java | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java index eab0817af23..78cd4a7e57d 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java +++ b/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java @@ -138,8 +138,6 @@ import sun.awt.X11GraphicsDevice; import sun.awt.X11GraphicsEnvironment; import sun.awt.XSettings; import sun.awt.datatransfer.DataTransferer; -import sun.awt.screencast.ScreencastHelper; -import sun.awt.screencast.XdgDesktopPortal; import sun.awt.util.PerformanceLogger; import sun.awt.util.ThreadGroupUtils; import sun.font.FontConfigManager; @@ -1523,21 +1521,16 @@ public final class XToolkit extends UNIXToolkit implements Runnable { awtLock(); try { if (numberOfButtons == 0) { - if (XdgDesktopPortal.isRemoteDesktop() - && ScreencastHelper.isAvailable()) { + numberOfButtons = getNumberOfButtonsImpl(); + numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons; + //4th and 5th buttons are for wheel and shouldn't be reported as buttons. + //If we have more than 3 physical buttons and a wheel, we report N-2 buttons. + //If we have 3 physical buttons and a wheel, we report 3 buttons. + //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively. + if (numberOfButtons >= 5) { + numberOfButtons -= 2; + } else if (numberOfButtons == 4 || numberOfButtons == 5) { numberOfButtons = 3; - } else { - numberOfButtons = getNumberOfButtonsImpl(); - numberOfButtons = (numberOfButtons > MAX_BUTTONS_SUPPORTED) ? MAX_BUTTONS_SUPPORTED : numberOfButtons; - //4th and 5th buttons are for wheel and shouldn't be reported as buttons. - //If we have more than 3 physical buttons and a wheel, we report N-2 buttons. - //If we have 3 physical buttons and a wheel, we report 3 buttons. - //If we have 1,2,3 physical buttons, we report it as is i.e. 1,2 or 3 respectively. - if (numberOfButtons >= 5) { - numberOfButtons -= 2; - } else if (numberOfButtons == 4 || numberOfButtons == 5) { - numberOfButtons = 3; - } } } //Assume don't have to re-query the number again and again. From 019df4d89c8a0fe2b27c6ec074499445ae45bc3f Mon Sep 17 00:00:00 2001 From: Dmitry Drobotov Date: Thu, 4 Dec 2025 03:22:42 +0000 Subject: [PATCH 047/141] 8372757: MacOS, Accessibility: Crash in [MenuAccessibility accessibilityChildren] after JDK-8341311 Reviewed-by: azvegint, psadhukhan --- .../macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m index 90a147aa5a2..14b7ee8c6b5 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/MenuAccessibility.m @@ -68,6 +68,11 @@ static jclass sjc_CAccessibility = NULL; sjm_getCurrentAccessiblePopupMenu, fAccessible, fComponent); + CHECK_EXCEPTION(); + if (axComponent == nil) { + return nil; + } + CommonComponentAccessibility *currentElement = [CommonComponentAccessibility createWithAccessible:axComponent withEnv:env withView:self->fView isCurrent:YES]; From dbf0742bf205ec57477373ebd43016383f7e7791 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Thu, 4 Dec 2025 05:03:07 +0000 Subject: [PATCH 048/141] 8373046: Method::get_c2i_unverified_entry() and get_c2i_no_clinit_check_entry() are missing check for abstract method Reviewed-by: kvn, vlivanov --- src/hotspot/share/oops/method.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index cb1c8ea37e8..1a2e5f0bee4 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -168,11 +168,17 @@ address Method::get_c2i_entry() { } address Method::get_c2i_unverified_entry() { + if (is_abstract()) { + return SharedRuntime::get_handle_wrong_method_abstract_stub(); + } assert(adapter() != nullptr, "must have"); return adapter()->get_c2i_unverified_entry(); } address Method::get_c2i_no_clinit_check_entry() { + if (is_abstract()) { + return nullptr; + } assert(VM_Version::supports_fast_class_init_checks(), ""); assert(adapter() != nullptr, "must have"); return adapter()->get_c2i_no_clinit_check_entry(); From 828498c54b3b1089af9e076cb45f3cf3bea58e2f Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Thu, 4 Dec 2025 07:34:43 +0000 Subject: [PATCH 049/141] 8371978: tools/jar/ReproducibleJar.java fails on XFS Reviewed-by: jpai --- test/jdk/tools/jar/ReproducibleJar.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/test/jdk/tools/jar/ReproducibleJar.java b/test/jdk/tools/jar/ReproducibleJar.java index ed5e2ed2ae3..5f59d1cbe41 100644 --- a/test/jdk/tools/jar/ReproducibleJar.java +++ b/test/jdk/tools/jar/ReproducibleJar.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 @@ -66,7 +66,9 @@ public class ReproducibleJar { private static final TimeZone TZ = TimeZone.getDefault(); private static final boolean DST = TZ.inDaylightTime(new Date()); private static final String UNIX_2038_ROLLOVER_TIME = "2038-01-19T03:14:07Z"; + private static final String UNIX_EPOCH_TIME = "1970-01-01T00:00:00Z"; private static final Instant UNIX_2038_ROLLOVER = Instant.parse(UNIX_2038_ROLLOVER_TIME); + private static final Instant UNIX_EPOCH = Instant.parse(UNIX_EPOCH_TIME); private static final File DIR_OUTER = new File("outer"); private static final File DIR_INNER = new File(DIR_OUTER, "inner"); private static final File FILE_INNER = new File(DIR_INNER, "foo.txt"); @@ -231,12 +233,15 @@ public class ReproducibleJar { if (Math.abs(now - original) > PRECISION) { // If original time is after UNIX 2038 32bit rollover - // and the now time is exactly the rollover time, then assume + // and the now time is exactly the rollover time or UNIX epoch time, then assume // running on a file system that only supports to 2038 (e.g.XFS) and pass test - if (FileTime.fromMillis(original).toInstant().isAfter(UNIX_2038_ROLLOVER) && - FileTime.fromMillis(now).toInstant().equals(UNIX_2038_ROLLOVER)) { - System.out.println("Checking file time after Unix 2038 rollover," + - " and extracted file time is " + UNIX_2038_ROLLOVER_TIME + ", " + + Instant originalInstant = FileTime.fromMillis(original).toInstant(); + Instant nowInstant = FileTime.fromMillis(now).toInstant(); + if (originalInstant.isAfter(UNIX_2038_ROLLOVER) && + (nowInstant.equals(UNIX_2038_ROLLOVER) || + nowInstant.equals(UNIX_EPOCH))) { + System.out.println("Checking file time after Unix 2038 rollover," + + " and extracted file time is " + nowInstant + ", " + " Assuming restricted file system, pass file time check."); } else { throw new AssertionError("checkFileTime failed," + From 63a10e0099111d69b167abf99d1a00084c4d6c1e Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Thu, 4 Dec 2025 08:01:17 +0000 Subject: [PATCH 050/141] 8373024: JFR: CPU throttle rate can't handle incorrect values Reviewed-by: mgronlun --- .../share/classes/jdk/jfr/internal/PlatformEventType.java | 3 ++- .../classes/jdk/jfr/internal/settings/CPUThrottleSetting.java | 2 +- src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java index eaba86e6327..1180ebd6ea2 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformEventType.java @@ -34,6 +34,7 @@ import jdk.jfr.internal.periodic.PeriodicEvents; import jdk.jfr.internal.util.ImplicitFields; import jdk.jfr.internal.util.TimespanRate; import jdk.jfr.internal.util.Utils; +import jdk.jfr.internal.settings.CPUThrottleSetting; import jdk.jfr.internal.settings.Throttler; import jdk.jfr.internal.tracing.Modification; @@ -60,7 +61,7 @@ public final class PlatformEventType extends Type { private boolean stackTraceEnabled = true; private long thresholdTicks = 0; private long period = 0; - private TimespanRate cpuRate; + private TimespanRate cpuRate = TimespanRate.of(CPUThrottleSetting.DEFAULT_VALUE); private boolean hasHook; private boolean beginChunk; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java index 944827f6d6f..7ea0ace21bb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/CPUThrottleSetting.java @@ -65,7 +65,7 @@ public final class CPUThrottleSetting extends SettingControl { } } } - return Objects.requireNonNullElse(highestRate.toString(), DEFAULT_VALUE); + return highestRate == null ? DEFAULT_VALUE : highestRate.toString(); } @Override diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java index 2632cd63848..0a7b14965cb 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Rate.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 @@ -34,7 +34,7 @@ public record Rate(long amount, TimespanUnit unit) { String value = splitted[0].strip(); String unit = splitted[1].strip(); TimespanUnit tu = TimespanUnit.fromText(unit); - if (unit == null) { + if (tu == null) { return null; } try { From 771253e285c48329a9b45dfaaa852b64e74b31d4 Mon Sep 17 00:00:00 2001 From: Frederic Thevenet Date: Thu, 4 Dec 2025 08:23:33 +0000 Subject: [PATCH 051/141] 8372802: PrintFlagsFinal should also print locked flags Reviewed-by: dholmes, stuefe, lmesnik --- src/hotspot/share/runtime/flags/jvmFlag.cpp | 2 +- .../runtime/CommandLine/PrintAllFlags.java | 69 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 51517fa49db..405b47e1813 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -711,7 +711,7 @@ void JVMFlag::printFlags(outputStream* out, bool withComments, bool printRanges, for (size_t i = 0; i < length; i++) { const bool skip = (skipDefaults && flagTable[i].is_default()); const bool visited = iteratorMarkers.at(i); - if (!visited && flagTable[i].is_unlocked() && !skip) { + if (!visited && !skip) { if ((bestFlag == nullptr) || (strcmp(bestFlag->name(), flagTable[i].name()) > 0)) { bestFlag = &flagTable[i]; bestFlagIndex = i; diff --git a/test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java b/test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java new file mode 100644 index 00000000000..13b0dd70d4e --- /dev/null +++ b/test/hotspot/jtreg/runtime/CommandLine/PrintAllFlags.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, IBM Corporation. + * 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 8372802 + * @summary Test that +PrintFlagsFinal print the same options when +UnlockExperimentalVMOptions and + * +UnlockDiagnosticVMOptions are set than when they aren't. + * @requires vm.flagless + * @library /test/lib + * @run driver PrintAllFlags + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +import java.io.IOException; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class PrintAllFlags { + private static final Pattern optPattern = Pattern.compile("\\s*\\w+\\s\\w+\\s+="); + + public static void main(String args[]) throws Exception { + var flagsFinal = runAndMakeVMOptionSet("-XX:+PrintFlagsFinal", "-version"); + var flagsFinalUnlocked = runAndMakeVMOptionSet( + "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintFlagsFinal", "-version"); + if (!flagsFinal.equals(flagsFinalUnlocked)) { + throw new RuntimeException("+PrintFlagsFinal should produce the same output" + + " whether or not UnlockExperimentalVMOptions and UnlockDiagnosticVMOptions are set"); + } + } + + private static Set runAndMakeVMOptionSet(String... args) throws IOException { + var output = new OutputAnalyzer(ProcessTools.createLimitedTestJavaProcessBuilder(args).start()); + Set optNameSet = output.asLines().stream() + .map(optPattern::matcher) + .filter(Matcher::find) + .map(Matcher::group) + .collect(Collectors.toSet()); + if (optNameSet.isEmpty()) { + throw new RuntimeException("Sanity test failed: no match for option pattern in process output"); + } + return optNameSet; + } + +} From bb867ed23e2d6394d7e7dab55cf2122889fdf3ac Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Thu, 4 Dec 2025 08:32:00 +0000 Subject: [PATCH 052/141] 8372938: Fix reference to DeferredStatic in HotSpot Style Guide Reviewed-by: stefank, jsjolen --- doc/hotspot-style.html | 4 ++-- doc/hotspot-style.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index a2ffb57e5a3..362245cd00a 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -1037,8 +1037,8 @@ running destructors at exit can lead to problems.

    Some of the approaches used in HotSpot to avoid dynamic initialization include:

      -
    • Use the Deferred<T> class template. Add a call -to its initialization function at an appropriate place during VM +

    • Use the DeferredStatic<T> class template. Add +a call to its initialization function at an appropriate place during VM initialization. The underlying object is never destroyed.

    • For objects of class type, use a variable whose value is a pointer to the class, initialized to nullptr. Provide an diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index c8f0f72b814..26549e3ca02 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -954,7 +954,7 @@ destructors at exit can lead to problems. Some of the approaches used in HotSpot to avoid dynamic initialization include: -* Use the `Deferred` class template. Add a call to its initialization +* Use the `DeferredStatic` class template. Add a call to its initialization function at an appropriate place during VM initialization. The underlying object is never destroyed. From 317daa3c004fbb1738e0af6acfbaf50c403c8230 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 4 Dec 2025 08:36:00 +0000 Subject: [PATCH 053/141] 8372643: Warning message on macos when building the JDK - (arm64) /tmp/lto.o unable to open object file: No such file or directory Reviewed-by: erikj --- make/common/native/Flags.gmk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/make/common/native/Flags.gmk b/make/common/native/Flags.gmk index 843701cb4db..efb4c08e74c 100644 --- a/make/common/native/Flags.gmk +++ b/make/common/native/Flags.gmk @@ -229,6 +229,11 @@ define SetupLinkerFlags # TOOLCHAIN_TYPE plus OPENJDK_TARGET_OS ifeq ($$($1_LINK_TIME_OPTIMIZATION), true) $1_EXTRA_LDFLAGS += $(LDFLAGS_LTO) + # Instruct the ld64 linker not to delete the temporary object file + # generated during Link Time Optimization + ifeq ($(call isTargetOs, macosx), true) + $1_EXTRA_LDFLAGS += -Wl,-object_path_lto,$$($1_OBJECT_DIR)/$$($1_NAME)_lto_helper.o + endif endif $1_EXTRA_LDFLAGS += $$($1_LDFLAGS_$(OPENJDK_TARGET_OS_TYPE)) $$($1_LDFLAGS_$(OPENJDK_TARGET_OS)) \ From 14000a25e6efcbe55171d4cc8c68170a8cf0406f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Thu, 4 Dec 2025 09:37:56 +0000 Subject: [PATCH 054/141] 8373080: Parallel: gc/arguments/TestMinInitialErgonomics.java should not be run with Large Pages Reviewed-by: ayang, aboldtch --- test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java b/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java index 6912499e53f..38eb07139bd 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java +++ b/test/hotspot/jtreg/gc/arguments/TestMinInitialErgonomics.java @@ -28,6 +28,7 @@ package gc.arguments; * @bug 8006088 * @requires vm.gc.Parallel * @requires vm.compMode != "Xcomp" + * @requires !vm.opt.final.UseLargePages * @summary Test Parallel GC ergonomics decisions related to minimum and initial heap size. * @library /test/lib * @library / From 16699a394d4d6c2b8a21e7de3c3d344c5a3309b4 Mon Sep 17 00:00:00 2001 From: Volkan Yazici Date: Thu, 4 Dec 2025 09:40:31 +0000 Subject: [PATCH 055/141] 8208693: HttpClient: Extend the request timeout's scope to cover the response body Reviewed-by: jpai, dfuchs --- .../classes/java/net/http/HttpClient.java | 12 + .../classes/java/net/http/HttpRequest.java | 20 +- .../classes/java/net/http/WebSocket.java | 12 +- .../jdk/internal/net/http/ExchangeImpl.java | 12 + .../jdk/internal/net/http/Http1Exchange.java | 24 +- .../internal/net/http/Http3ExchangeImpl.java | 20 +- .../jdk/internal/net/http/HttpClientImpl.java | 7 + .../jdk/internal/net/http/MultiExchange.java | 17 +- .../classes/jdk/internal/net/http/Stream.java | 25 +- .../common/HttpBodySubscriberWrapper.java | 19 +- .../httpclient/TimeoutResponseBodyTest.java | 285 ++++++++++++ .../httpclient/TimeoutResponseHeaderTest.java | 138 ++++++ .../TimeoutResponseTestSupport.java | 415 ++++++++++++++++++ .../net/http/HttpClientTimerAccess.java | 59 +++ .../httpclient/websocket/WebSocketTest.java | 48 +- 15 files changed, 1088 insertions(+), 25 deletions(-) create mode 100644 test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java create mode 100644 test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java create mode 100644 test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java create mode 100644 test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java diff --git a/src/java.net.http/share/classes/java/net/http/HttpClient.java b/src/java.net.http/share/classes/java/net/http/HttpClient.java index a7a2171857d..9ecb048342b 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpClient.java +++ b/src/java.net.http/share/classes/java/net/http/HttpClient.java @@ -312,10 +312,22 @@ public abstract class HttpClient implements AutoCloseable { * need to be established, for example if a connection can be reused * from a previous request, then this timeout duration has no effect. * + * @implSpec + * A connection timeout applies to the entire connection phase, from the + * moment a connection is requested until it is established. + * Implementations are recommended to ensure that the connection timeout + * covers any SSL/TLS handshakes. + * + * @implNote + * The built-in JDK implementation of the connection timeout covers any + * SSL/TLS handshakes. + * * @param duration the duration to allow the underlying connection to be * established * @return this builder * @throws IllegalArgumentException if the duration is non-positive + * @see HttpRequest.Builder#timeout(Duration) Configuring timeout for + * request execution */ public Builder connectTimeout(Duration duration); diff --git a/src/java.net.http/share/classes/java/net/http/HttpRequest.java b/src/java.net.http/share/classes/java/net/http/HttpRequest.java index c56328ba4b4..741573e06b3 100644 --- a/src/java.net.http/share/classes/java/net/http/HttpRequest.java +++ b/src/java.net.http/share/classes/java/net/http/HttpRequest.java @@ -258,12 +258,28 @@ public abstract class HttpRequest { * {@link HttpClient#sendAsync(java.net.http.HttpRequest, * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync} * completes exceptionally with an {@code HttpTimeoutException}. The effect - * of not setting a timeout is the same as setting an infinite Duration, - * i.e. block forever. + * of not setting a timeout is the same as setting an infinite + * {@code Duration}, i.e., block forever. + * + * @implSpec + * A timeout applies to the duration measured from the instant the + * request execution starts to, at least, the instant an + * {@link HttpResponse} is constructed. The elapsed time includes + * obtaining a connection for transport and retrieving the response + * headers. + * + * @implNote + * The JDK built-in implementation applies timeout over the duration + * measured from the instant the request execution starts to the + * instant the response body is consumed, if present. This is + * implemented by stopping the timer after the response body subscriber + * completion. * * @param duration the timeout duration * @return this builder * @throws IllegalArgumentException if the duration is non-positive + * @see HttpClient.Builder#connectTimeout(Duration) Configuring + * timeout for connection establishment */ public abstract Builder timeout(Duration duration); diff --git a/src/java.net.http/share/classes/java/net/http/WebSocket.java b/src/java.net.http/share/classes/java/net/http/WebSocket.java index 313847cf449..84fc8472eef 100644 --- a/src/java.net.http/share/classes/java/net/http/WebSocket.java +++ b/src/java.net.http/share/classes/java/net/http/WebSocket.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 @@ -144,6 +144,16 @@ public interface WebSocket { * {@link HttpTimeoutException}. If this method is not invoked then the * infinite timeout is assumed. * + * @implSpec + * A connection timeout applies to the entire connection phase, from the + * moment a connection is requested until it is established. + * Implementations are recommended to ensure that the connection timeout + * covers any WebSocket and SSL/TLS handshakes. + * + * @implNote + * The built-in JDK implementation of the connection timeout covers any + * WebSocket and SSL/TLS handshakes. + * * @param timeout * the timeout, non-{@linkplain Duration#isNegative() negative}, * non-{@linkplain Duration#ZERO ZERO} diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java index 74600e78557..c1ed01ff07a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ExchangeImpl.java @@ -581,6 +581,18 @@ abstract class ExchangeImpl { // Needed for HTTP/2 to subscribe a dummy subscriber and close the stream } + /** + * {@return {@code true}, if it is allowed to cancel the request timer on + * response body subscriber termination; {@code false}, otherwise} + * + * @param webSocket indicates if the associated request is a WebSocket handshake + * @param statusCode the status code of the associated response + */ + static boolean cancelTimerOnResponseBodySubscriberTermination( + boolean webSocket, int statusCode) { + return webSocket || statusCode < 100 || statusCode >= 200; + } + /* The following methods have separate HTTP/1.1 and HTTP/2 implementations */ abstract CompletableFuture> sendHeadersAsync(); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java index 02ce63b6314..72a47eca42c 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1Exchange.java @@ -206,8 +206,15 @@ class Http1Exchange extends ExchangeImpl { */ static final class Http1ResponseBodySubscriber extends HttpBodySubscriberWrapper { final Http1Exchange exchange; - Http1ResponseBodySubscriber(BodySubscriber userSubscriber, Http1Exchange exchange) { + + private final boolean cancelTimerOnTermination; + + Http1ResponseBodySubscriber( + BodySubscriber userSubscriber, + boolean cancelTimerOnTermination, + Http1Exchange exchange) { super(userSubscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; this.exchange = exchange; } @@ -220,6 +227,14 @@ class Http1Exchange extends ExchangeImpl { protected void unregister() { exchange.unregisterResponseSubscriber(this); } + + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.exchange.multi.cancelTimer(); + } + } + } @Override @@ -459,9 +474,10 @@ class Http1Exchange extends ExchangeImpl { @Override Http1ResponseBodySubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { BodySubscriber subscriber = handler.apply(response); - Http1ResponseBodySubscriber bs = - new Http1ResponseBodySubscriber(subscriber, this); - return bs; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http1ResponseBodySubscriber<>(subscriber, cancelTimerOnTermination, this); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java index 41a4a84958a..81475a47c4a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http3ExchangeImpl.java @@ -554,8 +554,12 @@ final class Http3ExchangeImpl extends Http3Stream { } final class Http3StreamResponseSubscriber extends HttpBodySubscriberWrapper { - Http3StreamResponseSubscriber(BodySubscriber subscriber) { + + private final boolean cancelTimerOnTermination; + + Http3StreamResponseSubscriber(BodySubscriber subscriber, boolean cancelTimerOnTermination) { super(subscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; } @Override @@ -568,6 +572,13 @@ final class Http3ExchangeImpl extends Http3Stream { registerResponseSubscriber(this); } + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.multi.cancelTimer(); + } + } + @Override protected void logComplete(Throwable error) { if (error == null) { @@ -590,9 +601,10 @@ final class Http3ExchangeImpl extends Http3Stream { Http3StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { if (debug.on()) debug.log("Creating body subscriber"); - Http3StreamResponseSubscriber subscriber = - new Http3StreamResponseSubscriber<>(handler.apply(response)); - return subscriber; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http3StreamResponseSubscriber<>(handler.apply(response), cancelTimerOnTermination); } @Override diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index d02930f4f31..ff130e90358 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -1880,6 +1880,13 @@ final class HttpClientImpl extends HttpClient implements Trackable { } } + // Visible for tests + List timers() { + synchronized (this) { + return new ArrayList<>(timeouts); + } + } + /** * Purges ( handles ) timer events that have passed their deadline, and * returns the amount of time, in milliseconds, until the next earliest diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java index ec621f7f955..60eb55ec0ad 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/MultiExchange.java @@ -25,7 +25,6 @@ package jdk.internal.net.http; -import java.io.IOError; import java.io.IOException; import java.lang.ref.WeakReference; import java.net.ConnectException; @@ -254,7 +253,7 @@ class MultiExchange implements Cancelable { .map(ConnectTimeoutTracker::getRemaining); } - private void cancelTimer() { + void cancelTimer() { if (responseTimerEvent != null) { client.cancelTimer(responseTimerEvent); responseTimerEvent = null; @@ -404,6 +403,8 @@ class MultiExchange implements Cancelable { processAltSvcHeader(r, client(), currentreq); Exchange exch = getExchange(); if (bodyNotPermitted(r)) { + // No response body consumption is expected, we can cancel the timer right away + cancelTimer(); if (bodyIsPresent(r)) { IOException ioe = new IOException( "unexpected content length header with 204 response"); @@ -467,6 +468,8 @@ class MultiExchange implements Cancelable { private CompletableFuture responseAsyncImpl(final boolean applyReqFilters) { if (currentreq.timeout().isPresent()) { + // Retried/Forwarded requests should reset the timer, if present + cancelTimer(); responseTimerEvent = ResponseTimerEvent.of(this); client.registerTimer(responseTimerEvent); } @@ -502,7 +505,6 @@ class MultiExchange implements Cancelable { } return completedFuture(response); } else { - cancelTimer(); setNewResponse(currentreq, response, null, exch); if (currentreq.isWebSocket()) { // need to close the connection and open a new one. @@ -520,11 +522,18 @@ class MultiExchange implements Cancelable { } }) .handle((response, ex) -> { // 5. handle errors and cancel any timer set - cancelTimer(); if (ex == null) { assert response != null; return completedFuture(response); } + + // Cancel the timer. Note that we only do so if the + // response has completed exceptionally. That is, we don't + // cancel the timer if there are no exceptions, since the + // response body might still get consumed, and it is + // still subject to the response timer. + cancelTimer(); + // all exceptions thrown are handled here final RetryContext retryCtx = checkRetryEligible(ex, exch); assert retryCtx != null : "retry context is null"; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java index 9a7ccd8f3a1..bf9170f8f51 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java @@ -390,9 +390,10 @@ class Stream extends ExchangeImpl { @Override Http2StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { - Http2StreamResponseSubscriber subscriber = - new Http2StreamResponseSubscriber<>(handler.apply(response)); - return subscriber; + var cancelTimerOnTermination = + cancelTimerOnResponseBodySubscriberTermination( + exchange.request().isWebSocket(), response.statusCode()); + return new Http2StreamResponseSubscriber<>(handler.apply(response), cancelTimerOnTermination); } // The Http2StreamResponseSubscriber is registered with the HttpClient @@ -1694,6 +1695,11 @@ class Stream extends ExchangeImpl { .whenComplete((v, t) -> pushGroup.pushError(t)); } + @Override + Http2StreamResponseSubscriber createResponseSubscriber(BodyHandler handler, ResponseInfo response) { + return new Http2StreamResponseSubscriber(handler.apply(response), false); + } + @Override void completeResponse(Response r) { Log.logResponse(r::toString); @@ -1924,8 +1930,12 @@ class Stream extends ExchangeImpl { } final class Http2StreamResponseSubscriber extends HttpBodySubscriberWrapper { - Http2StreamResponseSubscriber(BodySubscriber subscriber) { + + private final boolean cancelTimerOnTermination; + + Http2StreamResponseSubscriber(BodySubscriber subscriber, boolean cancelTimerOnTermination) { super(subscriber); + this.cancelTimerOnTermination = cancelTimerOnTermination; } @Override @@ -1938,6 +1948,13 @@ class Stream extends ExchangeImpl { unregisterResponseSubscriber(this); } + @Override + protected void onTermination() { + if (cancelTimerOnTermination) { + exchange.multi.cancelTimer(); + } + } + } private static final VarHandle DEREGISTERED; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java index 1c483ce99f4..f1c1f6f2d2a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/HttpBodySubscriberWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import java.util.Objects; import java.util.concurrent.CompletionStage; import java.util.concurrent.Flow; import java.util.concurrent.Flow.Subscription; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; @@ -51,7 +50,6 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { public static final Comparator> COMPARE_BY_ID = Comparator.comparing(HttpBodySubscriberWrapper::id); - public static final Flow.Subscription NOP = new Flow.Subscription() { @Override public void request(long n) { } @@ -75,7 +73,18 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { this.userSubscriber = userSubscriber; } - private class SubscriptionWrapper implements Subscription { + /** + * A callback to be invoked before termination, whether due to the + * completion or failure of the subscriber, or cancellation of the + * subscription. To be precise, this method is called before + * {@link #onComplete()}, {@link #onError(Throwable) onError()}, or + * {@link #onCancel()}. + */ + protected void onTermination() { + // Do nothing + } + + private final class SubscriptionWrapper implements Subscription { final Subscription subscription; SubscriptionWrapper(Subscription s) { this.subscription = Objects.requireNonNull(s); @@ -92,6 +101,7 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { subscription.cancel(); } finally { if (markCancelled()) { + onTermination(); onCancel(); } } @@ -284,6 +294,7 @@ public class HttpBodySubscriberWrapper implements TrustedSubscriber { */ public final void complete(Throwable t) { if (markCompleted()) { + onTermination(); logComplete(t); tryUnregister(); t = withError = Utils.getCompletionCause(t); diff --git a/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java b/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java new file mode 100644 index 00000000000..093885a6ba0 --- /dev/null +++ b/test/jdk/java/net/httpclient/TimeoutResponseBodyTest.java @@ -0,0 +1,285 @@ +/* + * 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 jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.InputStream; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import static jdk.internal.net.http.HttpClientTimerAccess.assertNoResponseTimerEventRegistrations; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; +import static org.junit.jupiter.api.Assertions.fail; + +/* + * @test id=retriesDisabled + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response body* + * timeouts when all retry mechanisms are disabled. + * + * @library /test/lib + * /test/jdk/java/net/httpclient/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=0 + * -Dtest.requestTimeoutMillis=1000 + * TimeoutResponseBodyTest + */ + +/* + * @test id=retriesEnabledForResponseFailure + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response body* + * timeouts, where some initial responses are intentionally configured + * to fail to trigger retries. + * + * @library /test/lib + * /test/jdk/java/net/httpclient/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=3 + * -Dtest.requestTimeoutMillis=1000 + * -Dtest.responseFailureWaitDurationMillis=600 + * TimeoutResponseBodyTest + */ + +/** + * Verifies {@link HttpRequest#timeout() HttpRequest.timeout()} is effective + * for response body timeouts. + * + * @implNote + * + * Using a response body subscriber (i.e., {@link InputStream}) of type that + * allows gradual consumption of the response body after successfully building + * an {@link HttpResponse} instance to ensure timeouts are propagated even + * after the {@code HttpResponse} construction. + *

      + * Each test is provided a pristine ephemeral client to avoid any unexpected + * effects due to pooling. + */ +class TimeoutResponseBodyTest extends TimeoutResponseTestSupport { + + private static final Logger LOGGER = Utils.getDebugLogger( + TimeoutResponseBodyTest.class.getSimpleName()::toString, Utils.DEBUG); + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server blocking without delivering the response body. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendOnMissingBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.BLOCK_BEFORE_BODY_DELIVERY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request"); + var response = client.send(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyDoesNotArrive(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server blocking without delivering the response body. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsyncOnMissingBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.BLOCK_BEFORE_BODY_DELIVERY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + var responseFuture = client.sendAsync(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Obtaining the response"); + var response = responseFuture.get(); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyDoesNotArrive(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + private static void verifyResponseBodyDoesNotArrive(HttpResponse response) { + assertEquals(200, response.statusCode()); + assertThrowsHttpTimeoutException(() -> { + try (var responseBodyStream = response.body()) { + var readByte = responseBodyStream.read(); + fail("Unexpected read byte: " + readByte); + } + }); + } + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server delivering the response body very slowly. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendOnSlowBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_BODY_SLOWLY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request"); + var response = client.send(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyArrivesSlow(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server delivering the response body very slowly. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsyncOnSlowBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_BODY_SLOWLY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + var responseFuture = client.sendAsync(pair.request(), HttpResponse.BodyHandlers.ofInputStream()); + LOGGER.log("Obtaining the response"); + var response = responseFuture.get(); + LOGGER.log("Consuming the obtained response"); + verifyResponseBodyArrivesSlow(response); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + private static void verifyResponseBodyArrivesSlow(HttpResponse response) { + assertEquals(200, response.statusCode()); + assertThrowsHttpTimeoutException(() -> { + try (var responseBodyStream = response.body()) { + int i = 0; + int l = ServerRequestPair.CONTENT_LENGTH; + for (; i < l; i++) { + LOGGER.log("Reading byte %s/%s", i, l); + var readByte = responseBodyStream.read(); + if (readByte < 0) { + break; + } + assertEquals(i, readByte); + } + fail("Should not have reached here! (i=%s)".formatted(i)); + } + }); + } + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server delivering 204, i.e., no content, which is handled + * through a specialized path served by {@code MultiExchange::handleNoBody}. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendOnNoBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_NO_BODY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request"); + client.send(pair.request(), HttpResponse.BodyHandlers.discarding()); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server delivering 204, i.e., no content, which is handled + * through a specialized path served by {@code MultiExchange::handleNoBody}. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsyncOnNoBody(ServerRequestPair pair) throws Exception { + + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.DELIVER_NO_BODY; + + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + client.sendAsync(pair.request(), HttpResponse.BodyHandlers.discarding()).get(); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + + } + +} diff --git a/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java b/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java new file mode 100644 index 00000000000..ab562f8eab8 --- /dev/null +++ b/test/jdk/java/net/httpclient/TimeoutResponseHeaderTest.java @@ -0,0 +1,138 @@ +/* + * 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 jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +import static jdk.internal.net.http.HttpClientTimerAccess.assertNoResponseTimerEventRegistrations; +import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; + +/* + * @test id=retriesDisabled + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response header* + * timeouts when all retry mechanisms are disabled. + * + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=0 + * -Dtest.requestTimeoutMillis=1000 + * TimeoutResponseHeaderTest + */ + +/* + * @test id=retriesEnabledForResponseFailure + * @bug 8208693 + * @summary Verifies `HttpRequest::timeout` is effective for *response header* + * timeouts, where some initial responses are intentionally configured + * to fail to trigger retries. + * + * @library /test/jdk/java/net/httpclient/lib + * /test/lib + * access + * @build TimeoutResponseTestSupport + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess + * jdk.httpclient.test.lib.common.HttpServerAdapters + * jdk.test.lib.net.SimpleSSLContext + * + * @run junit/othervm + * -Djdk.httpclient.auth.retrylimit=0 + * -Djdk.httpclient.disableRetryConnect + * -Djdk.httpclient.redirects.retrylimit=3 + * -Dtest.requestTimeoutMillis=1000 + * -Dtest.responseFailureWaitDurationMillis=600 + * TimeoutResponseHeaderTest + */ + +/** + * Verifies {@link HttpRequest#timeout() HttpRequest.timeout()} is effective + * for response header timeouts. + */ +class TimeoutResponseHeaderTest extends TimeoutResponseTestSupport { + + private static final Logger LOGGER = Utils.getDebugLogger( + TimeoutResponseHeaderTest.class.getSimpleName()::toString, Utils.DEBUG); + + static { + ServerRequestPair.SERVER_HANDLER_BEHAVIOUR = + ServerRequestPair.ServerHandlerBehaviour.BLOCK_BEFORE_HEADER_DELIVERY; + } + + /** + * Tests timeouts using + * {@link HttpClient#send(HttpRequest, HttpResponse.BodyHandler) HttpClient::send} + * against a server blocking without delivering any response headers. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSend(ServerRequestPair pair) throws Exception { + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively( + REQUEST_TIMEOUT.multipliedBy(2), + () -> assertThrowsHttpTimeoutException(() -> { + LOGGER.log("Sending the request"); + client.send(pair.request(), HttpResponse.BodyHandlers.discarding()); + })); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + } + + /** + * Tests timeouts using + * {@link HttpClient#sendAsync(HttpRequest, HttpResponse.BodyHandler) HttpClient::sendAsync} + * against a server blocking without delivering any response headers. + */ + @ParameterizedTest + @MethodSource("serverRequestPairs") + void testSendAsync(ServerRequestPair pair) throws Exception { + try (var client = pair.createClientWithEstablishedConnection()) { + assertTimeoutPreemptively(REQUEST_TIMEOUT.multipliedBy(2), () -> { + LOGGER.log("Sending the request asynchronously"); + var responseFuture = client.sendAsync(pair.request(), HttpResponse.BodyHandlers.discarding()); + assertThrowsHttpTimeoutException(() -> { + LOGGER.log("Obtaining the response"); + responseFuture.get(); + }); + }); + LOGGER.log("Verifying the registered response timer events"); + assertNoResponseTimerEventRegistrations(client); + } + } + +} diff --git a/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java b/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java new file mode 100644 index 00000000000..4da63a2dff9 --- /dev/null +++ b/test/jdk/java/net/httpclient/TimeoutResponseTestSupport.java @@ -0,0 +1,415 @@ +/* + * 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 jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestExchange; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestHandler; +import jdk.httpclient.test.lib.common.HttpServerAdapters.HttpTestServer; +import jdk.internal.net.http.common.Logger; +import jdk.internal.net.http.common.Utils; +import jdk.internal.net.http.frame.ErrorFrame; +import jdk.internal.net.http.http3.Http3Error; +import jdk.test.lib.net.SimpleSSLContext; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.function.Executable; + +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpClient.Version; +import java.net.http.HttpOption; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpTimeoutException; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +import static java.net.http.HttpClient.Builder.NO_PROXY; +import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; +import static jdk.httpclient.test.lib.common.HttpServerAdapters.createClientBuilderFor; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Utilities for {@code TimeoutResponse*Test}s. + * + * @see TimeoutResponseBodyTest Server response body timeout tests + * @see TimeoutResponseHeaderTest Server response header timeout tests + * @see TimeoutBasic Server connection timeout tests + */ +public class TimeoutResponseTestSupport { + + private static final String CLASS_NAME = TimeoutResponseTestSupport.class.getSimpleName(); + + private static final Logger LOGGER = Utils.getDebugLogger(CLASS_NAME::toString, Utils.DEBUG); + + private static final SSLContext SSL_CONTEXT = createSslContext(); + + protected static final Duration REQUEST_TIMEOUT = + Duration.ofMillis(Long.parseLong(System.getProperty("test.requestTimeoutMillis"))); + + static { + assertTrue( + REQUEST_TIMEOUT.isPositive(), + "was expecting `test.requestTimeoutMillis > 0`, found: " + REQUEST_TIMEOUT); + } + + protected static final int RETRY_LIMIT = + 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")); + + static { + if (RETRY_LIMIT > 0) { + + // Verify that response failure wait duration is provided + if (RESPONSE_FAILURE_WAIT_DURATION_MILLIS <= 0) { + var message = String.format( + "`jdk.httpclient.redirects.retrylimit` (%s) is greater than zero. " + + "`test.responseFailureWaitDurationMillis` (%s) must be greater than zero too.", + RETRY_LIMIT, RESPONSE_FAILURE_WAIT_DURATION_MILLIS); + throw new AssertionError(message); + } + + // Verify that the total response failure waits exceed the request timeout + var totalResponseFailureWaitDuration = Duration + .ofMillis(RESPONSE_FAILURE_WAIT_DURATION_MILLIS) + .multipliedBy(RETRY_LIMIT); + if (totalResponseFailureWaitDuration.compareTo(REQUEST_TIMEOUT) <= 0) { + var message = ("`test.responseFailureWaitDurationMillis * jdk.httpclient.redirects.retrylimit` (%s * %s = %s) " + + "must be greater than `test.requestTimeoutMillis` (%s)") + .formatted( + RESPONSE_FAILURE_WAIT_DURATION_MILLIS, + RETRY_LIMIT, + totalResponseFailureWaitDuration, + REQUEST_TIMEOUT); + throw new AssertionError(message); + } + + } + } + + protected static final ServerRequestPair + HTTP1 = ServerRequestPair.of(Version.HTTP_1_1, false), + HTTPS1 = ServerRequestPair.of(Version.HTTP_1_1, true), + HTTP2 = ServerRequestPair.of(Version.HTTP_2, false), + HTTPS2 = ServerRequestPair.of(Version.HTTP_2, true), + HTTP3 = ServerRequestPair.of(Version.HTTP_3, true); + + private static SSLContext createSslContext() { + try { + return new SimpleSSLContext().get(); + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + } + + protected record ServerRequestPair(HttpTestServer server, HttpRequest request, boolean secure) { + + private static final ExecutorService EXECUTOR = Executors.newVirtualThreadPerTaskExecutor(); + + private static final CountDownLatch SHUT_DOWN_LATCH = new CountDownLatch(1); + + private static final AtomicInteger SERVER_COUNTER = new AtomicInteger(); + + /** + * An arbitrary content length to cause the client wait for it. + * It just needs to be greater than zero, and big enough to trigger a timeout when delivered slowly. + */ + public static final int CONTENT_LENGTH = 1234; + + public enum ServerHandlerBehaviour { + BLOCK_BEFORE_HEADER_DELIVERY, + BLOCK_BEFORE_BODY_DELIVERY, + DELIVER_BODY_SLOWLY, + DELIVER_NO_BODY + } + + public static volatile ServerHandlerBehaviour SERVER_HANDLER_BEHAVIOUR; + + public static volatile int SERVER_HANDLER_PENDING_FAILURE_COUNT = 0; + + private static ServerRequestPair of(Version version, boolean secure) { + + // Create the server and the request URI + var sslContext = secure ? SSL_CONTEXT : null; + var serverId = "" + SERVER_COUNTER.getAndIncrement(); + var server = createServer(version, sslContext); + server.getVersion(); + var handlerPath = "/%s/".formatted(CLASS_NAME); + var requestUriScheme = secure ? "https" : "http"; + var requestUri = URI.create("%s://%s%s-".formatted(requestUriScheme, server.serverAuthority(), handlerPath)); + + // Register the request handler + server.addHandler(createServerHandler(serverId), handlerPath); + + // Create the request + var request = createRequestBuilder(requestUri, version).timeout(REQUEST_TIMEOUT).build(); + + // Create the pair + var pair = new ServerRequestPair(server, request, secure); + pair.server.start(); + LOGGER.log("Server[%s] is started at `%s`", serverId, server.serverAuthority()); + return pair; + + } + + private static HttpTestServer createServer(Version version, SSLContext sslContext) { + try { + return switch (version) { + case HTTP_1_1, HTTP_2 -> HttpTestServer.create(version, sslContext, EXECUTOR); + case HTTP_3 -> HttpTestServer.create(HTTP_3_URI_ONLY, sslContext, EXECUTOR); + }; + } catch (IOException exception) { + throw new UncheckedIOException(exception); + } + } + + private static HttpTestHandler createServerHandler(String serverId) { + return (exchange) -> { + var connectionKey = exchange.getConnectionKey(); + LOGGER.log( + "Server[%s] has received request %s", + serverId, Map.of("connectionKey", connectionKey)); + try (exchange) { + + // Short-circuit on `HEAD` requests. + // They are used for admitting established connections to the pool. + if ("HEAD".equals(exchange.getRequestMethod())) { + LOGGER.log( + "Server[%s] is responding to the `HEAD` request %s", + serverId, Map.of("connectionKey", connectionKey)); + exchange.sendResponseHeaders(200, 0); + return; + } + + // Short-circuit if instructed to fail + synchronized (ServerRequestPair.class) { + if (SERVER_HANDLER_PENDING_FAILURE_COUNT > 0) { + LOGGER.log( + "Server[%s] is prematurely failing as instructed %s", + serverId, + Map.of( + "connectionKey", connectionKey, + "SERVER_HANDLER_PENDING_FAILURE_COUNT", SERVER_HANDLER_PENDING_FAILURE_COUNT)); + // Closing the exchange will trigger an `END_STREAM` without a headers frame. + // This is a protocol violation, hence we must reset the stream first. + // We are doing so using by rejecting the stream, which is known to make the client retry. + if (Version.HTTP_2.equals(exchange.getExchangeVersion())) { + exchange.resetStream(ErrorFrame.REFUSED_STREAM); + } else if (Version.HTTP_3.equals(exchange.getExchangeVersion())) { + exchange.resetStream(Http3Error.H3_REQUEST_REJECTED.code()); + } + SERVER_HANDLER_PENDING_FAILURE_COUNT--; + return; + } + } + + switch (SERVER_HANDLER_BEHAVIOUR) { + + case BLOCK_BEFORE_HEADER_DELIVERY -> sleepIndefinitely(serverId, connectionKey); + + case BLOCK_BEFORE_BODY_DELIVERY -> { + sendResponseHeaders(serverId, exchange, connectionKey); + sleepIndefinitely(serverId, connectionKey); + } + + case DELIVER_BODY_SLOWLY -> { + sendResponseHeaders(serverId, exchange, connectionKey); + sendResponseBodySlowly(serverId, exchange, connectionKey); + } + + case DELIVER_NO_BODY -> sendResponseHeaders(serverId, exchange, connectionKey, 204, 0); + + } + + } catch (Exception exception) { + var message = String.format( + "Server[%s] has failed! %s", + serverId, Map.of("connectionKey", connectionKey)); + LOGGER.log(System.Logger.Level.ERROR, message, exception); + if (exception instanceof InterruptedException) { + // Restore the interrupt + Thread.currentThread().interrupt(); + } + throw new RuntimeException(message, exception); + } + }; + } + + private static void sleepIndefinitely(String serverId, String connectionKey) throws InterruptedException { + LOGGER.log("Server[%s] is sleeping %s", serverId, Map.of("connectionKey", connectionKey)); + SHUT_DOWN_LATCH.await(); + } + + private static void sendResponseHeaders(String serverId, HttpTestExchange exchange, String connectionKey) + throws IOException { + sendResponseHeaders(serverId, exchange, connectionKey, 200, CONTENT_LENGTH); + } + + private static void sendResponseHeaders( + String serverId, + HttpTestExchange exchange, + String connectionKey, + int statusCode, + long contentLength) + throws IOException { + LOGGER.log("Server[%s] is sending headers %s", serverId, Map.of("connectionKey", connectionKey)); + exchange.sendResponseHeaders(statusCode, contentLength); + // Force the headers to be flushed + exchange.getResponseBody().flush(); + } + + private static void sendResponseBodySlowly(String serverId, HttpTestExchange exchange, String connectionKey) + throws Exception { + var perBytePauseDuration = Duration.ofMillis(100); + assertTrue( + perBytePauseDuration.multipliedBy(CONTENT_LENGTH).compareTo(REQUEST_TIMEOUT) > 0, + "Per-byte pause duration (%s) must be long enough to exceed the timeout (%s) when delivering the content (%s bytes)".formatted( + perBytePauseDuration, REQUEST_TIMEOUT, CONTENT_LENGTH)); + try (var responseBody = exchange.getResponseBody()) { + for (int i = 0; i < CONTENT_LENGTH; i++) { + LOGGER.log( + "Server[%s] is sending the body %s/%s %s", + serverId, i, CONTENT_LENGTH, Map.of("connectionKey", connectionKey)); + responseBody.write(i); + responseBody.flush(); + Thread.sleep(perBytePauseDuration); + } + throw new AssertionError("Delivery should never have succeeded due to timeout!"); + } catch (IOException _) { + // Client's timeout mechanism is expected to short-circuit and cut the stream. + // Hence, discard I/O failures. + } + } + + public HttpClient createClientWithEstablishedConnection() throws IOException, InterruptedException { + var version = server.getVersion(); + var client = createClientBuilderFor(version) + .version(version) + .sslContext(SSL_CONTEXT) + .proxy(NO_PROXY) + .build(); + // Ensure an established connection is admitted to the pool. This + // helps to cross out any possibilities of a timeout before a + // request makes it to the server handler. For instance, consider + // HTTP/1.1 to HTTP/2 upgrades, or long-running TLS handshakes. + var headRequest = createRequestBuilder(request.uri(), version).HEAD().build(); + client.send(headRequest, HttpResponse.BodyHandlers.discarding()); + return client; + } + + private static HttpRequest.Builder createRequestBuilder(URI uri, Version version) { + var requestBuilder = HttpRequest.newBuilder(uri).version(version); + if (Version.HTTP_3.equals(version)) { + requestBuilder.setOption(HttpOption.H3_DISCOVERY, HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY); + } + return requestBuilder; + } + + @Override + public String toString() { + var version = server.getVersion(); + var versionString = version.toString(); + return switch (version) { + case HTTP_1_1, HTTP_2 -> secure ? versionString.replaceFirst("_", "S_") : versionString; + case HTTP_3 -> versionString; + }; + } + + } + + @AfterAll + static void closeServers() { + + // Terminate all handlers before shutting down the server, which would block otherwise. + ServerRequestPair.SHUT_DOWN_LATCH.countDown(); + ServerRequestPair.EXECUTOR.shutdown(); + + // Shut down servers + Exception[] exceptionRef = {null}; + serverRequestPairs() + .forEach(pair -> { + try { + pair.server.stop(); + } catch (Exception exception) { + if (exceptionRef[0] == null) { + exceptionRef[0] = exception; + } else { + exceptionRef[0].addSuppressed(exception); + } + } + }); + if (exceptionRef[0] != null) { + throw new RuntimeException("failed closing one or more server resources", exceptionRef[0]); + } + + } + + /** + * Configures how many times the handler should fail. + */ + @BeforeEach + void resetServerHandlerFailureIndex() { + ServerRequestPair.SERVER_HANDLER_PENDING_FAILURE_COUNT = Math.max(0, RETRY_LIMIT - 1); + } + + /** + * Ensures that the handler has failed as many times as instructed. + */ + @AfterEach + void verifyServerHandlerFailureIndex() { + assertEquals(0, ServerRequestPair.SERVER_HANDLER_PENDING_FAILURE_COUNT); + } + + protected static Stream serverRequestPairs() { + return Stream.of(HTTP1, HTTPS1, HTTP2, HTTPS2, HTTP3); + } + + protected static void assertThrowsHttpTimeoutException(Executable executable) { + var rootException = assertThrows(Exception.class, executable); + // Due to intricacies involved in the way exceptions are generated and + // nested, there is no bullet-proof way to determine at which level of + // the causal chain an `HttpTimeoutException` will show up. Hence, we + // scan through the entire causal chain. + Throwable exception = rootException; + while (exception != null) { + if (exception instanceof HttpTimeoutException) { + return; + } + exception = exception.getCause(); + } + throw new AssertionError("was expecting an `HttpTimeoutException` in the causal chain", rootException); + } + +} diff --git a/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java b/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java new file mode 100644 index 00000000000..8bc1fac7b60 --- /dev/null +++ b/test/jdk/java/net/httpclient/access/java.net.http/jdk/internal/net/http/HttpClientTimerAccess.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.net.http; + +import java.net.http.HttpClient; + +public enum HttpClientTimerAccess {; + + public static void assertNoResponseTimerEventRegistrations(HttpClient client) { + assertTimerEventRegistrationCount(client, ResponseTimerEvent.class, 0); + } + + private static void assertTimerEventRegistrationCount( + HttpClient client, + Class clazz, + long expectedCount) { + var facade = assertType(HttpClientFacade.class, client); + var actualCount = facade.impl.timers().stream().filter(clazz::isInstance).count(); + if (actualCount != 0) { + throw new AssertionError( + "Found %s occurrences of `%s` timer event registrations while expecting %s.".formatted( + actualCount, clazz.getCanonicalName(), expectedCount)); + } + } + + private static T assertType(Class expectedType, Object instance) { + if (!expectedType.isInstance(instance)) { + var expectedTypeName = expectedType.getCanonicalName(); + var actualTypeName = instance != null ? instance.getClass().getCanonicalName() : null; + throw new AssertionError( + "Was expecting an instance of type `%s`, found: `%s`".formatted( + expectedTypeName, actualTypeName)); + } + @SuppressWarnings("unchecked") + T typedInstance = (T) instance; + return typedInstance; + } + +} diff --git a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java index 83f8b6eab27..43bcb054b7d 100644 --- a/test/jdk/java/net/httpclient/websocket/WebSocketTest.java +++ b/test/jdk/java/net/httpclient/websocket/WebSocketTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,10 @@ /* * @test - * @bug 8217429 + * @bug 8217429 8208693 + * @library ../access * @build DummyWebSocketServer + * java.net.http/jdk.internal.net.http.HttpClientTimerAccess * @run testng/othervm * WebSocketTest */ @@ -40,6 +42,7 @@ import java.net.http.WebSocket; import java.net.http.WebSocketHandshakeException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -48,6 +51,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionStage; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; @@ -58,6 +62,7 @@ import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.net.http.HttpClient.newBuilder; import static java.net.http.WebSocket.NORMAL_CLOSURE; import static java.nio.charset.StandardCharsets.UTF_8; +import static jdk.internal.net.http.HttpClientTimerAccess.assertNoResponseTimerEventRegistrations; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; import static org.testng.Assert.fail; @@ -143,6 +148,45 @@ public class WebSocketTest { } } + /** + * Verifies that the internally issued request to establish the WebSocket + * connection does not leave any response timers registered at the client + * after the WebSocket handshake. + */ + @Test + public void responseTimerCleanUp() throws Exception { + try (var server = new DummyWebSocketServer()) { + server.open(); + try (var client = newBuilder().proxy(NO_PROXY).build()) { + var connectionEstablished = new CountDownLatch(1); + var webSocketListener = new WebSocket.Listener() { + + @Override + public void onOpen(WebSocket webSocket) { + connectionEstablished.countDown(); + } + + }; + var webSocket = client + .newWebSocketBuilder() + // Explicitly configure a timeout to get a response + // timer event get registered at the client. The query + // should succeed without timing out. + .connectTimeout(Duration.ofMinutes(2)) + .buildAsync(server.getURI(), webSocketListener) + .join(); + try { + connectionEstablished.await(); + // We expect the response timer event to get evicted once + // the WebSocket handshake headers are received. + assertNoResponseTimerEventRegistrations(client); + } finally { + webSocket.abort(); + } + } + } + } + @Test public void partialBinaryThenText() throws IOException { try (var server = new DummyWebSocketServer()) { From df0165bd6933728fdcf1956323401afdc47b3f78 Mon Sep 17 00:00:00 2001 From: Ana-Maria Mihalceanu Date: Thu, 4 Dec 2025 10:09:33 +0000 Subject: [PATCH 056/141] 8321139: jlink's compression plugin doesn't handle -c option correctly Reviewed-by: jpai, alanb --- .../jdk/tools/jlink/internal/TaskHelper.java | 7 ++- .../tools/jlink/resources/plugins.properties | 12 ++--- src/jdk.jlink/share/man/jlink.md | 21 +++++--- test/jdk/tools/jlink/JLinkTest.java | 38 ++++++++++++-- test/jdk/tools/jlink/TaskHelperTest.java | 51 +++++++++++++++++-- test/setup_aot/TestSetupAOT.java | 2 +- 6 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java index d53589dc388..dca4d57f764 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java @@ -362,10 +362,13 @@ public final class TaskHelper { if (plugin instanceof DefaultCompressPlugin) { plugOption - = new PluginOption(false, + = new PluginOption(true, (task, opt, arg) -> { Map m = addArgumentMap(plugin); - m.put(plugin.getName(), DefaultCompressPlugin.LEVEL_2); + String level = (arg != null && !arg.isEmpty()) + ? arg + :"zip-6"; + m.put(plugin.getName(), level); }, false, "--compress", "-c"); mainOptions.add(plugOption); } else if (plugin instanceof DefaultStripDebugPlugin) { diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties index e9be0b4e587..7e3c26fa7b8 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/plugins.properties @@ -61,14 +61,14 @@ Class optimization: convert Class.forName calls to constant loads. class-for-name.usage=\ \ --class-for-name Class optimization: convert Class.forName calls to constant loads. -compress.argument=[:filter=] +compress.argument=[:filter=] compress.description= Compression to use in compressing resources. compress.usage=\ \ --compress Compression to use in compressing resources:\n\ \ Accepted values are:\n\ -\ zip-[0-9], where zip-0 provides no compression,\n\ +\ zip-'{0-9}', where zip-0 provides no compression,\n\ \ and zip-9 provides the best compression.\n\ \ Default is zip-6. @@ -307,15 +307,15 @@ plugin.opt.disable-plugin=\ \ --disable-plugin Disable the plugin mentioned plugin.opt.compress=\ -\ --compress Compression to use in compressing resources:\n\ +\ --compress Compress all resources in the output image:\n\ \ Accepted values are:\n\ -\ zip-[0-9], where zip-0 provides no compression,\n\ +\ zip-'{0-9}', where zip-0 provides no compression,\n\ \ and zip-9 provides the best compression.\n\ \ Default is zip-6.\n\ \ Deprecated values to be removed in a future release:\n\ -\ 0: No compression. Equivalent to zip-0.\n\ +\ 0: No compression. Use zip-0 instead.\n\ \ 1: Constant String Sharing\n\ -\ 2: Equivalent to zip-6. +\ 2: ZIP. Use zip-6 instead. plugin.opt.strip-debug=\ \ -G, --strip-debug Strip debug information diff --git a/src/jdk.jlink/share/man/jlink.md b/src/jdk.jlink/share/man/jlink.md index dc256af43b5..0d16e69c9ef 100644 --- a/src/jdk.jlink/share/man/jlink.md +++ b/src/jdk.jlink/share/man/jlink.md @@ -64,12 +64,15 @@ Developers are responsible for updating their custom runtime images. `--bind-services` : Link service provider modules and their dependencies. -`-c ={0|1|2}` or `--compress={0|1|2}` -: Enable compression of resources: +`-c zip-{0-9}` or `--compress=zip-{0-9}` +: Enable compression of resources. The accepted values are: + zip-{0-9}, where zip-0 provides no compression, + and zip-9 provides the best compression. Default is zip-6. - - `0`: No compression +: Deprecated values to be removed in a future release: + - `0`: No compression. Use zip-0 instead. - `1`: Constant string sharing - - `2`: ZIP + - `2`: ZIP. Use zip-6 instead. `--disable-plugin` *pluginname* : Disables the specified plug-in. See [jlink Plug-ins] for the list of @@ -170,14 +173,18 @@ For a complete list of all available plug-ins, run the command ### Plugin `compress` Options -: `--compress=`{`0`\|`1`\|`2`}\[`:filter=`*pattern-list*\] +: `--compress=zip-`{`0`-`9`}\[`:filter=`*pattern-list*\] Description : Compresses all resources in the output image. + Accepted values are: + zip-{0-9}, where zip-0 provides no compression, + and zip-9 provides the best compression. Default is zip-6. - - Level 0: No compression +: Deprecated values to be removed in a future release: + - Level 0: No compression. Use zip-0 instead. - Level 1: Constant string sharing - - Level 2: ZIP + - Level 2: ZIP. Use zip-6 instead. An optional *pattern-list* filter can be specified to list the pattern of files to include. diff --git a/test/jdk/tools/jlink/JLinkTest.java b/test/jdk/tools/jlink/JLinkTest.java index bc4d2a08800..1d84caaa147 100644 --- a/test/jdk/tools/jlink/JLinkTest.java +++ b/test/jdk/tools/jlink/JLinkTest.java @@ -42,10 +42,7 @@ import tests.JImageGenerator; /* * @test * @summary Test image creation - * @bug 8189777 - * @bug 8194922 - * @bug 8206962 - * @bug 8240349 + * @bug 8189777 8194922 8206962 8240349 8163382 8165735 8166810 8173717 8321139 * @author Jean-Francois Denise * @requires (vm.compMode != "Xcomp" & os.maxMemory >= 2g) * @library ../lib @@ -358,6 +355,39 @@ public class JLinkTest { helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level invalid"); } + // short command without argument + { + String[] userOptions = {"-c"}; + String moduleName = "invalidCompressLevelEmpty"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: no value given for -c"); + } + + // invalid short command + { + String[] userOptions = {"-c", "3", "--output", "image"}; + String moduleName = "invalidCompressLevel3"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level 3"); + } + + + // invalid argument value + { + String[] userOptions = {"--compress", "42", "--output", "image"}; + String moduleName = "invalidCompressLevel42"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level 42"); + } + + // invalid argument value + { + String[] userOptions = {"--compress", "zip-", "--output", "image"}; + String moduleName = "invalidCompressLevelZip"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level zip-"); + } + // orphan argument - JDK-8166810 { String[] userOptions = {"--compress", "2", "foo" }; diff --git a/test/jdk/tools/jlink/TaskHelperTest.java b/test/jdk/tools/jlink/TaskHelperTest.java index 51dea8de24a..26ac376a6ec 100644 --- a/test/jdk/tools/jlink/TaskHelperTest.java +++ b/test/jdk/tools/jlink/TaskHelperTest.java @@ -48,7 +48,7 @@ import jdk.tools.jlink.internal.TaskHelper.BadArgs; /* * @test * @summary Test TaskHelper option parsing - * @bug 8303884 + * @bug 8303884 8321139 * @modules jdk.jlink/jdk.tools.jlink.internal * jdk.jlink/jdk.tools.jlink.plugin * @run junit TaskHelperTest @@ -59,19 +59,22 @@ public class TaskHelperTest { private static final List> OPTIONS = List.of( new Option<>(true, (task, opt, arg) -> { - System.out.println(arg); mainArgValue = arg; }, true, "--main-expecting"), new Option<>(false, (task, opt, arg) -> { mainFlag = true; - }, true, "--main-no-arg") + }, true, "--main-no-arg"), + new Option<>(true, (task, opt, arg) -> { + compressArgValue = (arg != null && !arg.isEmpty()) ? arg : "zip-6"; + }, "--compress", "-c") ); private static String argValue; private static String mainArgValue; private static boolean mainFlag = false; + private static String compressArgValue; - public record ArgTestCase(String cmdLine, String[] tokens, String pluginArgValue, String mainArgValue, boolean mainFlagSet) {}; + public record ArgTestCase(String cmdLine, String[] tokens, String pluginArgValue, String mainArgValue, boolean mainFlagSet) {} public static class TestPluginWithRawOption implements Plugin { @Override @@ -118,6 +121,7 @@ public class TaskHelperTest { argValue = null; mainArgValue = null; mainFlag = false; + compressArgValue= null; } public static Stream gnuStyleUsages() { @@ -217,4 +221,41 @@ public class TaskHelperTest { var remaining = optionsHelper.handleOptions(this, args); assertEquals(2, remaining.size()); } -} \ No newline at end of file + + record CompressTestCase(String[] tokens, String expectedCompressValue) {} + + public static Stream compressUsages() { + return Stream.of( + + new CompressTestCase(new String[] {"-c", "0"}, "0"), + new CompressTestCase(new String[] {"--compress=zip-0"}, "zip-0"), + + new CompressTestCase(new String[] {"-c", "1"}, "1"), + new CompressTestCase(new String[] {"--compress=zip-1"}, "zip-1"), + + new CompressTestCase(new String[] {"-c", "2"}, "2"), + new CompressTestCase(new String[] {"--compress=zip-2"}, "zip-2"), + + new CompressTestCase(new String[] {"--compress=zip-3"}, "zip-3"), + new CompressTestCase(new String[] {"--compress=zip-4"}, "zip-4"), + new CompressTestCase(new String[] {"--compress=zip-5"}, "zip-5"), + new CompressTestCase(new String[] {"--compress=zip-6"}, "zip-6"), + new CompressTestCase(new String[] {"--compress=zip-7"}, "zip-7"), + new CompressTestCase(new String[] {"--compress=zip-8"}, "zip-8"), + new CompressTestCase(new String[] {"--compress=zip-9"}, "zip-9") + ); + } + + @ParameterizedTest + @MethodSource("compressUsages") + public void testCompressOptionArg(CompressTestCase testCase) throws TaskHelper.BadArgs, IOException { + var remaining = optionsHelper.handleOptions(this, testCase.tokens); + + // trigger Plugin::configure + taskHelper.getPluginsConfig(null, null, null); + + assertTrue(remaining.isEmpty()); + assertEquals(testCase.expectedCompressValue, compressArgValue); + } +} + diff --git a/test/setup_aot/TestSetupAOT.java b/test/setup_aot/TestSetupAOT.java index a46bd6e66c7..0ab17d6ca99 100644 --- a/test/setup_aot/TestSetupAOT.java +++ b/test/setup_aot/TestSetupAOT.java @@ -137,7 +137,7 @@ public class TestSetupAOT { String jlinkOutput = tmpDir + File.separator + "jlinkOutput"; execTool("jlink", "--help") - .shouldContain("Compression to use in compressing resources"); + .shouldContain("Compress all resources in the output image"); execTool("jlink", "--list-plugins") .shouldContain("List of available plugins", "--generate-cds-archive "); From 91c5bd550a36e10e8b39d1b322fd433ee8df14f5 Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Thu, 4 Dec 2025 10:17:34 +0000 Subject: [PATCH 057/141] 8337791: VectorAPI jtreg ABSMaskedByteMaxVectorTests crashes with UseAVX=0 -XX:MaxVectorSize=8 Reviewed-by: epeter, sviswanathan, dlunden --- src/hotspot/cpu/x86/x86.ad | 5 ++ .../vectorapi/TestABSMaskedMaxByteVector.java | 54 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 1d393897bca..42d2e815e45 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -3386,6 +3386,11 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { return false; } break; + case Op_VectorBlend: + if (UseAVX == 0 && size_in_bits < 128) { + return false; + } + break; case Op_VectorTest: if (UseSSE < 4) { return false; // Implementation limitation diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java b/test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java new file mode 100644 index 00000000000..356892fadf8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestABSMaskedMaxByteVector.java @@ -0,0 +1,54 @@ +/* + * 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.vectorapi; + +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; + +/* + * @test + * @bug 8337791 + * @summary Test byte vector predicated ABS with UseAVX=0 and MaxVectorSize=8 + * @modules jdk.incubator.vector + * @library /test/lib / + * @run driver compiler.vectorapi.TestABSMaskedMaxByteVector + */ + +public class TestABSMaskedMaxByteVector { + public static final VectorSpecies BSP = ByteVector.SPECIES_MAX; + public static int idx = 0; + + public static void main(String[] args) { + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-ea", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:UseAVX=0", "-XX:MaxVectorSize=8"); + TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", "-ea"); + } + + @Test + @IR(failOn = {IRNode.ABS_VB}, applyIfAnd = {"MaxVectorSize", " <= 8 ", "UseAVX", "0"}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"sse4.1", "true"}) + @IR(counts = {IRNode.ABS_VB, "1"}, applyIf = {"MaxVectorSize", " > 8 "}, applyIfPlatform = {"x64", "true"}, applyIfCPUFeature = {"sse4.1", "true"}) + public void test() { + assert ByteVector.broadcast(BSP, (byte)-4) + .lanewise(VectorOperators.ABS, VectorMask.fromLong(BSP, 0xF)) + .lane(idx++ & 3) == 4; + } +} From b5970c97bdd5b1e079e9ada0fbd469850c0e23b4 Mon Sep 17 00:00:00 2001 From: Volodymyr Paprotski Date: Thu, 4 Dec 2025 10:21:53 +0000 Subject: [PATCH 058/141] 8373063: Test sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java fails on Aarch64 after JDK-8372816 Reviewed-by: dholmes, mdoerr --- .../provider/acvp/ML_DSA_Intrinsic_Test.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java index 7f057603323..1e9faf7fb74 100644 --- a/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java +++ b/test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java @@ -38,6 +38,8 @@ import java.util.HexFormat; */ /* * @test + * @comment This test should be reenabled on aarch64 + * @requires os.simpleArch == "x64" * @library /test/lib * @key randomness * @modules java.base/sun.security.provider:+open @@ -48,7 +50,7 @@ import java.util.HexFormat; // -XX:+UnlockDiagnosticVMOptions -XX:+UseDilithiumIntrinsics test/jdk/sun/security/provider/acvp/ML_DSA_Intrinsic_Test.java public class ML_DSA_Intrinsic_Test { - public static void main(String[] args) throws Exception, Throwable { + public static void main(String[] args) throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); Class kClazz = sun.security.provider.ML_DSA.class; @@ -129,7 +131,7 @@ public class ML_DSA_Intrinsic_Test { private static final int ML_DSA_N = 256; public static void testMult(int[] prod1, int[] prod2, int[] coeffs1, int[] coeffs2, MethodHandle mult, MethodHandle multJava, Random rnd, - long seed, int i) throws Exception, Throwable { + long seed, int i) throws Throwable { for (int j = 0; j Date: Thu, 4 Dec 2025 12:25:02 +0000 Subject: [PATCH 059/141] 8373062: JFR build failure with CDS disabled Reviewed-by: egahlin --- .../share/classfile/systemDictionary.cpp | 22 +++++++++---------- src/hotspot/share/jfr/jfr.cpp | 2 ++ src/hotspot/share/jfr/jfr.hpp | 2 +- .../share/jfr/support/jfrClassDefineEvent.cpp | 2 ++ .../share/jfr/support/jfrClassDefineEvent.hpp | 3 ++- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index ac57293687c..c873347a197 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1146,17 +1146,6 @@ void SystemDictionary::load_shared_class_misc(InstanceKlass* ik, ClassLoaderData } } -#if INCLUDE_JFR -void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { - assert(event != nullptr, "invariant"); - assert(k != nullptr, "invariant"); - event->set_loadedClass(k); - event->set_definingClassLoader(k->class_loader_data()); - event->set_initiatingClassLoader(init_cld); - event->commit(); -} -#endif // INCLUDE_JFR - // This is much more lightweight than SystemDictionary::resolve_or_null // - There's only a single Java thread at this point. No need for placeholder. // - All supertypes of ik have been loaded @@ -1217,6 +1206,17 @@ void SystemDictionary::preload_class(Handle class_loader, InstanceKlass* ik, TRA #endif // INCLUDE_CDS +#if INCLUDE_JFR +void SystemDictionary::post_class_load_event(EventClassLoad* event, const InstanceKlass* k, const ClassLoaderData* init_cld) { + assert(event != nullptr, "invariant"); + assert(k != nullptr, "invariant"); + event->set_loadedClass(k); + event->set_definingClassLoader(k->class_loader_data()); + event->set_initiatingClassLoader(init_cld); + event->commit(); +} +#endif // INCLUDE_JFR + InstanceKlass* SystemDictionary::load_instance_class_impl(Symbol* class_name, Handle class_loader, TRAPS) { if (class_loader.is_null()) { diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 3a2465e211d..b09a89594ad 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -173,6 +173,7 @@ bool Jfr::on_start_flight_recording_option(const JavaVMOption** option, char* de return JfrOptionSet::parse_start_flight_recording_option(option, delimiter); } +#if INCLUDE_CDS void Jfr::on_restoration(const Klass* k, JavaThread* jt) { assert(k != nullptr, "invariant"); JfrTraceId::restore(k); @@ -180,3 +181,4 @@ void Jfr::on_restoration(const Klass* k, JavaThread* jt) { JfrClassDefineEvent::on_restoration(InstanceKlass::cast(k), jt); } } +#endif diff --git a/src/hotspot/share/jfr/jfr.hpp b/src/hotspot/share/jfr/jfr.hpp index 7b86e6c917e..db567cc9a29 100644 --- a/src/hotspot/share/jfr/jfr.hpp +++ b/src/hotspot/share/jfr/jfr.hpp @@ -79,7 +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_restoration(const Klass* k, JavaThread* jt); + CDS_ONLY(static void on_restoration(const Klass* k, JavaThread* jt);) }; #endif // SHARE_JFR_JFR_HPP diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp index 06f361ced8c..5bdc0015a2b 100644 --- a/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.cpp @@ -171,6 +171,7 @@ void JfrClassDefineEvent::on_creation(const InstanceKlass* ik, const ClassFilePa } } +#if INCLUDE_CDS void JfrClassDefineEvent::on_restoration(const InstanceKlass* ik, JavaThread* jt) { assert(ik != nullptr, "invariant"); assert(ik->trace_id() != 0, "invariant"); @@ -186,3 +187,4 @@ void JfrClassDefineEvent::on_restoration(const InstanceKlass* ik, JavaThread* jt send_event(ik, cl->is_modules_image() ? module_path(ik, jt) : get_source(cl, jt)); } } +#endif diff --git a/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp index 4a0926023ca..3e242d8e4f2 100644 --- a/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp +++ b/src/hotspot/share/jfr/support/jfrClassDefineEvent.hpp @@ -26,6 +26,7 @@ #define SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP #include "memory/allStatic.hpp" +#include "utilities/macros.hpp" class ClassFileParser; class InstanceKlass; @@ -34,7 +35,7 @@ class JavaThread; class JfrClassDefineEvent : AllStatic { public: static void on_creation(const InstanceKlass* ik, const ClassFileParser& parser, JavaThread* jt); - static void on_restoration(const InstanceKlass* ik, JavaThread* jt); + CDS_ONLY(static void on_restoration(const InstanceKlass* ik, JavaThread* jt);) }; #endif // SHARE_JFR_SUPPORT_JFRCLASSDEFINEEVENT_HPP From c4ec983da57ee8aea71e88d5de2570c5d65a69df Mon Sep 17 00:00:00 2001 From: Robert Toyonaga Date: Thu, 4 Dec 2025 13:56:17 +0000 Subject: [PATCH 060/141] 8370715: JFR: Races are possible when dumping recordings Reviewed-by: egahlin, stuefe --- .../jdk/jfr/internal/PlatformRecording.java | 10 ++- .../api/recording/dump/TestDumpOverwrite.java | 79 +++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java index b07a71dd4d5..64454fc3cb4 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java @@ -34,6 +34,7 @@ import static jdk.jfr.internal.LogTag.JFR; import java.io.IOException; import java.io.InputStream; import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.nio.file.StandardOpenOption; @@ -744,7 +745,14 @@ public final class PlatformRecording implements AutoCloseable { } private void transferChunks(WriteablePath path) throws IOException { - try (ChunksChannel cc = new ChunksChannel(chunks); FileChannel fc = FileChannel.open(path.getReal(), StandardOpenOption.WRITE, StandardOpenOption.APPEND)) { + // Before writing, wipe the file if it already exists. + try (ChunksChannel cc = new ChunksChannel(chunks); FileChannel fc = FileChannel.open(path.getReal(), StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE)) { + // Mitigate races against other processes + FileLock l = fc.tryLock(); + if (l == null) { + Logger.log(LogTag.JFR, LogLevel.INFO, "Dump operation skipped for recording \"" + name + "\" (" + id + "). File " + path.getRealPathText() + " is locked by other dump operation or activity."); + return; + } long bytes = cc.transferTo(fc); Logger.log(LogTag.JFR, LogLevel.INFO, "Transferred " + bytes + " bytes from the disk repository"); // No need to force if no data was transferred, which avoids IOException when device is /dev/null diff --git a/test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java b/test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java new file mode 100644 index 00000000000..050b68eb538 --- /dev/null +++ b/test/jdk/jdk/jfr/api/recording/dump/TestDumpOverwrite.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.api.recording.dump; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.SimpleEventHelper; +import jdk.test.lib.jfr.Events; + +/** + * @test + * @summary Test that multiple dumps to the same file by ongoing recordings do not mangle data. + * @requires vm.flagless + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.api.recording.dump.TestDumpOverwrite + */ +public class TestDumpOverwrite { + private static Path DUMP_PATH = Paths.get(".", "rec_TestDumpOverwrite.jfr"); + public static void main(String[] args) throws Exception { + Recording recording1 = new Recording(); + Recording recording2 = new Recording(); + SimpleEventHelper.enable(recording1, true); + SimpleEventHelper.enable(recording2, true); + recording1.setDestination(DUMP_PATH); + recording2.setDestination(DUMP_PATH); + + int actualId = 0; + recording1.start(); + SimpleEventHelper.createEvent(actualId++); + recording2.start(); + SimpleEventHelper.createEvent(actualId++); + // This is results in the initial write to the dump destination + recording2.stop(); + SimpleEventHelper.createEvent(actualId++); + recording2.close(); + SimpleEventHelper.createEvent(actualId++); + // This should first wipe the data previously written by recording2. + recording1.stop(); + recording1.close(); + + Asserts.assertTrue(Files.exists(DUMP_PATH), "Recording file does not exist: " + DUMP_PATH); + + // Verify events are read in order without duplicates (otherwise chunks may be out of order). + // If the dump file is not being overwritten correctly, we will see event ids: 1, 0, 1, 2, 3. + int expectedId = 0; + for (RecordedEvent event : RecordingFile.readAllEvents(DUMP_PATH)) { + Events.assertField(event, "id").equal(expectedId++); + } + Asserts.assertTrue(expectedId == actualId, "incorrect number of events found"); + } +} From 6f03c7808de2b07b1e501d05b1bb7d5bfde5e393 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Thu, 4 Dec 2025 15:00:09 +0000 Subject: [PATCH 061/141] 8360702: runtime/Thread/AsyncExceptionTest.java timed out Reviewed-by: dholmes, fbredberg --- .../Thread/AsyncExceptionOnMonitorEnter.java | 42 ++++++++++--------- .../runtime/Thread/AsyncExceptionTest.java | 23 +++++----- 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java index a4aa0fe3797..409313b9626 100644 --- a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java +++ b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionOnMonitorEnter.java @@ -25,7 +25,6 @@ * @test * @bug 8283044 * @summary Stress delivery of asynchronous exceptions while target is at monitorenter - * @requires test.thread.factory == null * @library /test/hotspot/jtreg/testlibrary * @run main/othervm/native AsyncExceptionOnMonitorEnter 0 * @run main/othervm/native -agentlib:AsyncExceptionOnMonitorEnter AsyncExceptionOnMonitorEnter 1 @@ -45,9 +44,13 @@ public class AsyncExceptionOnMonitorEnter extends Thread { public static native int exitRawMonitor(); public static native void destroyRawMonitor(); + // Avoid using CountDownLatch or similar objects that require unparking the + // main thread. Otherwise, if the main thread is run as a virtual thread, the + // async exception could be sent while the target is still executing FJP logic. + public volatile boolean started = false; + public volatile boolean gotMonitor = false; + private static Object o1 = new Object(); - private static boolean firstWorker = true; - private static Semaphore sem = new Semaphore(0); @Override public void run() { @@ -60,11 +63,9 @@ public class AsyncExceptionOnMonitorEnter extends Thread { public void testWithJavaMonitor() { try { + started = true; synchronized (o1) { - if (firstWorker) { - firstWorker = false; - sem.release(); - } + gotMonitor = true; Thread.sleep(1000); } } catch (ThreadDeath td) { @@ -75,20 +76,16 @@ public class AsyncExceptionOnMonitorEnter extends Thread { public void testWithJVMTIRawMonitor() { - boolean savedFirst = false; try { + started = true; int retCode = enterRawMonitor(); - if (retCode != 0 && firstWorker) { + if (retCode != 0) { throw new RuntimeException("error in JVMTI RawMonitorEnter: retCode=" + retCode); } - if (firstWorker) { - firstWorker = false; - savedFirst = true; - sem.release(); - } - Thread.sleep(1000); + gotMonitor = true; + Thread.sleep(500); retCode = exitRawMonitor(); - if (retCode != 0 && savedFirst) { + if (retCode != 0) { throw new RuntimeException("error in JVMTI RawMonitorExit: retCode=" + retCode); } } catch (ThreadDeath td) { @@ -134,15 +131,18 @@ public class AsyncExceptionOnMonitorEnter extends Thread { AsyncExceptionOnMonitorEnter worker2 = new AsyncExceptionOnMonitorEnter(); try { - // Start firstWorker worker and wait until monitor is acquired - firstWorker = true; + // Start first worker and wait until monitor is acquired worker1.start(); - sem.acquire(); + while (!worker1.gotMonitor) { + Thread.sleep(1); + } // Start second worker and allow some time for target to block on monitorenter // before executing Thread.stop() worker2.start(); - Thread.sleep(300); + while (!worker2.started) { + Thread.sleep(10); + } while (true) { JVMTIUtils.stopThread(worker2); @@ -151,6 +151,8 @@ public class AsyncExceptionOnMonitorEnter extends Thread { // not released worker2 will deadlock on enter JVMTIUtils.stopThread(worker1); } + // Give time to throw exception + Thread.sleep(10); if (!worker1.isAlive() && !worker2.isAlive()) { // Done with Thread.stop() calls since diff --git a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java index 52fc4ca1d56..e15022a9fed 100644 --- a/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java +++ b/test/hotspot/jtreg/runtime/Thread/AsyncExceptionTest.java @@ -49,9 +49,11 @@ public class AsyncExceptionTest extends Thread { private final static int DEF_TIME_MAX = 30; // default max # secs to test private final static String PROG_NAME = "AsyncExceptionTest"; - public CountDownLatch startSyncObj = new CountDownLatch(1); + // Avoid using CountDownLatch or similar objects that require unparking the + // main thread. Otherwise, if the main thread is run as a virtual thread, the + // async exception could be sent while the target is still executing FJP logic. + public volatile boolean started = false; - private boolean firstEntry = true; private boolean receivedThreadDeathinInternal1 = false; private boolean receivedThreadDeathinInternal2 = false; private volatile RuntimeException error = null; @@ -77,6 +79,7 @@ public class AsyncExceptionTest extends Thread { public void internalRun1() { try { + started = true; while (!receivedThreadDeathinInternal2) { internalRun2(); } @@ -87,16 +90,10 @@ public class AsyncExceptionTest extends Thread { public void internalRun2() { try { - Integer myLocalCount = 1; - Integer myLocalCount2 = 1; + int myLocalCount = 1; + int myLocalCount2 = 1; - if (firstEntry) { - // Tell main thread we have started. - startSyncObj.countDown(); - firstEntry = false; - } - - while(myLocalCount > 0) { + while (myLocalCount > 0) { myLocalCount2 = (myLocalCount % 3) / 2; myLocalCount -= 1; } @@ -128,7 +125,9 @@ public class AsyncExceptionTest extends Thread { thread.start(); try { // Wait for the worker thread to get going. - thread.startSyncObj.await(); + while (!thread.started) { + Thread.sleep(1); + } // Send async exception and wait until it is thrown JVMTIUtils.stopThread(thread); thread.join(); From 33dda887d99d39b2d003fd6521db97d45da474f0 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Thu, 4 Dec 2025 15:03:33 +0000 Subject: [PATCH 062/141] 8351842: Windows specific issues in combination of JEP 493 and --with-external-symbols-in-bundles=public Reviewed-by: erikj, mbaesken --- make/Bundles.gmk | 28 +------------------ make/Images.gmk | 22 +++++++++------ make/hotspot/lib/CompileJvm.gmk | 12 ++++---- src/hotspot/share/prims/whitebox.cpp | 15 ++++++++-- .../NMT/CheckForProperDetailStackTrace.java | 13 +++------ .../jdk/modules/etc/JmodExcludedFiles.java | 24 ++++++++-------- test/lib/jdk/test/whitebox/WhiteBox.java | 9 ++++-- 7 files changed, 56 insertions(+), 67 deletions(-) diff --git a/make/Bundles.gmk b/make/Bundles.gmk index cf3b77e4e52..8161b3b0362 100644 --- a/make/Bundles.gmk +++ b/make/Bundles.gmk @@ -125,13 +125,6 @@ define SetupBundleFileBody && $(TAR) cf - -$(TAR_INCLUDE_PARAM) $$($1_$$d_LIST_FILE) \ $(TAR_IGNORE_EXIT_VALUE) ) \ | ( $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) && $(TAR) xf - )$$(NEWLINE) ) - # Rename stripped pdb files - ifeq ($(call isTargetOs, windows)+$(SHIP_DEBUG_SYMBOLS), true+public) - for f in `$(FIND) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) -name "*.stripped.pdb"`; do \ - $(ECHO) Renaming $$$${f} to $$$${f%stripped.pdb}pdb $(LOG_INFO); \ - $(MV) $$$${f} $$$${f%stripped.pdb}pdb; \ - done - endif # Unzip any zipped debuginfo files ifeq ($$($1_UNZIP_DEBUGINFO), true) for f in `$(FIND) $(SUPPORT_OUTPUTDIR)/bundles/$1/$$($1_SUBDIR) -name "*.diz"`; do \ @@ -222,14 +215,6 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) ifeq ($(call isTargetOs, windows), true) ifeq ($(SHIP_DEBUG_SYMBOLS), ) JDK_SYMBOLS_EXCLUDE_PATTERN := %.pdb - else - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - JDK_SYMBOLS_EXCLUDE_PATTERN := \ - $(filter-out \ - %.stripped.pdb, \ - $(filter %.pdb, $(ALL_JDK_FILES)) \ - ) - endif endif endif @@ -244,10 +229,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) ) JDK_SYMBOLS_BUNDLE_FILES := \ - $(filter-out \ - %.stripped.pdb, \ - $(call FindFiles, $(SYMBOLS_IMAGE_DIR)) \ - ) + $(call FindFiles, $(SYMBOLS_IMAGE_DIR)) TEST_DEMOS_BUNDLE_FILES := $(filter $(JDK_DEMOS_IMAGE_HOMEDIR)/demo/%, \ $(ALL_JDK_DEMOS_FILES)) @@ -267,14 +249,6 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), ) ifeq ($(call isTargetOs, windows), true) ifeq ($(SHIP_DEBUG_SYMBOLS), ) JRE_SYMBOLS_EXCLUDE_PATTERN := %.pdb - else - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - JRE_SYMBOLS_EXCLUDE_PATTERN := \ - $(filter-out \ - %.stripped.pdb, \ - $(filter %.pdb, $(ALL_JRE_FILES)) \ - ) - endif endif endif diff --git a/make/Images.gmk b/make/Images.gmk index c5877e44c22..89c0a834477 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -282,29 +282,33 @@ else endif CMDS_TARGET_SUBDIR := bin -# Param 1 - either JDK or JRE +# Copy debug info files into symbols bundle. +# In case of Windows and --with-external-symbols-in-bundles=public, take care to remove *.stripped.pdb files SetupCopyDebuginfo = \ $(foreach m, $(ALL_$1_MODULES), \ + $(eval dbgfiles := $(call FindDebuginfoFiles, $(SUPPORT_OUTPUTDIR)/modules_libs/$m)) \ + $(eval dbgfiles := $(if $(filter true+public,$(call isTargetOs,windows)+$(SHIP_DEBUG_SYMBOLS)), \ + $(filter-out %.stripped.pdb,$(dbgfiles)),$(dbgfiles)) \ + ) \ $(eval $(call SetupCopyFiles, COPY_$1_LIBS_DEBUGINFO_$m, \ SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/$m, \ DEST := $($1_IMAGE_DIR)/$(LIBS_TARGET_SUBDIR), \ - FILES := $(call FindDebuginfoFiles, \ - $(SUPPORT_OUTPUTDIR)/modules_libs/$m), \ + FILES := $(dbgfiles), \ )) \ $(eval $1_TARGETS += $$(COPY_$1_LIBS_DEBUGINFO_$m)) \ + $(eval dbgfiles := $(call FindDebuginfoFiles, $(SUPPORT_OUTPUTDIR)/modules_cmds/$m)) \ + $(eval dbgfiles := $(if $(filter true+public,$(call isTargetOs,windows)+$(SHIP_DEBUG_SYMBOLS)), \ + $(filter-out %.stripped.pdb,$(dbgfiles)),$(dbgfiles)) \ + ) \ $(eval $(call SetupCopyFiles, COPY_$1_CMDS_DEBUGINFO_$m, \ SRC := $(SUPPORT_OUTPUTDIR)/modules_cmds/$m, \ DEST := $($1_IMAGE_DIR)/$(CMDS_TARGET_SUBDIR), \ - FILES := $(call FindDebuginfoFiles, \ - $(SUPPORT_OUTPUTDIR)/modules_cmds/$m), \ + FILES := $(dbgfiles), \ )) \ $(eval $1_TARGETS += $$(COPY_$1_CMDS_DEBUGINFO_$m)) \ ) -# No space before argument to avoid having to put $(strip ) everywhere in -# implementation above. -$(call SetupCopyDebuginfo,JDK) -$(call SetupCopyDebuginfo,JRE) +# No space before argument to avoid having to put $(strip ) everywhere in implementation above. $(call SetupCopyDebuginfo,SYMBOLS) ################################################################################ diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index b0ea27e5081..39a549b7db0 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -151,6 +151,12 @@ JVM_STRIPFLAGS ?= $(STRIPFLAGS) # This source set is reused so save in cache. $(call FillFindCache, $(JVM_SRC_DIRS)) +ifeq ($(SHIP_DEBUG_SYMBOLS), full) + CFLAGS_SHIP_DEBUGINFO := -DSHIP_DEBUGINFO_FULL +else ifeq ($(SHIP_DEBUG_SYMBOLS), public) + CFLAGS_SHIP_DEBUGINFO := -DSHIP_DEBUGINFO_PUBLIC +endif + ifeq ($(call isTargetOs, windows), true) ifeq ($(STATIC_LIBS), true) WIN_EXPORT_FILE := $(JVM_OUTPUTDIR)/static-win-exports.def @@ -158,10 +164,6 @@ ifeq ($(call isTargetOs, windows), true) WIN_EXPORT_FILE := $(JVM_OUTPUTDIR)/win-exports.def endif - ifeq ($(SHIP_DEBUG_SYMBOLS), public) - CFLAGS_STRIPPED_DEBUGINFO := -DHAS_STRIPPED_DEBUGINFO - endif - JVM_LDFLAGS += -def:$(WIN_EXPORT_FILE) endif @@ -187,7 +189,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \ CFLAGS := $(JVM_CFLAGS), \ abstract_vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ arguments.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ - whitebox.cpp_CXXFLAGS := $(CFLAGS_STRIPPED_DEBUGINFO), \ + whitebox.cpp_CXXFLAGS := $(CFLAGS_SHIP_DEBUGINFO), \ DISABLED_WARNINGS_gcc := $(DISABLED_WARNINGS_gcc), \ DISABLED_WARNINGS_gcc_ad_$(HOTSPOT_TARGET_CPU_ARCH).cpp := nonnull, \ DISABLED_WARNINGS_gcc_bytecodeInterpreter.cpp := unused-label, \ diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index bbd7b4bf795..a6ce092e40d 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -508,8 +508,16 @@ WB_ENTRY(jboolean, WB_ConcurrentGCRunTo(JNIEnv* env, jobject o, jobject at)) return ConcurrentGCBreakpoints::run_to(c_name); WB_END -WB_ENTRY(jboolean, WB_HasExternalSymbolsStripped(JNIEnv* env, jobject o)) -#if defined(HAS_STRIPPED_DEBUGINFO) +WB_ENTRY(jboolean, WB_ShipDebugInfoFull(JNIEnv* env, jobject o)) +#if defined(SHIP_DEBUGINFO_FULL) + return true; +#else + return false; +#endif +WB_END + +WB_ENTRY(jboolean, WB_ShipDebugInfoPublic(JNIEnv* env, jobject o)) +#if defined(SHIP_DEBUGINFO_PUBLIC) return true; #else return false; @@ -2840,7 +2848,8 @@ static JNINativeMethod methods[] = { {CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize}, {CC"getHeapSpaceAlignment", CC"()J", (void*)&WB_GetHeapSpaceAlignment}, {CC"getHeapAlignment", CC"()J", (void*)&WB_GetHeapAlignment}, - {CC"hasExternalSymbolsStripped", CC"()Z", (void*)&WB_HasExternalSymbolsStripped}, + {CC"shipsFullDebugInfo", CC"()Z", (void*)&WB_ShipDebugInfoFull}, + {CC"shipsPublicDebugInfo", CC"()Z", (void*)&WB_ShipDebugInfoPublic}, {CC"countAliveClasses0", CC"(Ljava/lang/String;)I", (void*)&WB_CountAliveClasses }, {CC"getSymbolRefcount", CC"(Ljava/lang/String;)I", (void*)&WB_GetSymbolRefcount }, {CC"parseCommandLine0", diff --git a/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java b/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java index 28af0692721..66c256be3cc 100644 --- a/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java +++ b/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java @@ -63,10 +63,9 @@ public class CheckForProperDetailStackTrace { private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); private static final Path MODS_DIR = Paths.get(TEST_CLASSES, "mods"); - // Windows has source information only in full pdbs, not in stripped pdbs - private static boolean expectSourceInformation = Platform.isLinux() || Platform.isWindows(); - - static WhiteBox wb = WhiteBox.getWhiteBox(); + // In some configurations on Windows, we could have stripped pdbs which do not have source information. + private static boolean expectSourceInformation = (Platform.isLinux() || Platform.isWindows()) && + WhiteBox.getWhiteBox().shipsFullDebugInfo(); /* The stack trace we look for by default. Note that :: has been replaced by .* to make sure it matches even if the symbol is not unmangled. @@ -145,12 +144,8 @@ public class CheckForProperDetailStackTrace { throw new RuntimeException("Expected stack trace missing from output"); } - if (wb.hasExternalSymbolsStripped()) { - expectSourceInformation = false; - } - - System.out.println("Looking for source information:"); if (expectSourceInformation) { + System.out.println("Looking for source information:"); if (!stackTraceMatches(".*moduleEntry.cpp.*", output)) { output.reportDiagnosticSummary(); throw new RuntimeException("Expected source information missing from output"); diff --git a/test/jdk/jdk/modules/etc/JmodExcludedFiles.java b/test/jdk/jdk/modules/etc/JmodExcludedFiles.java index 90ca6840d52..3929419a080 100644 --- a/test/jdk/jdk/modules/etc/JmodExcludedFiles.java +++ b/test/jdk/jdk/modules/etc/JmodExcludedFiles.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 @@ -25,9 +25,12 @@ * @test * @bug 8159927 * @modules java.base/jdk.internal.util + * @library /test/lib * @requires jlink.packagedModules - * @run main JmodExcludedFiles - * @summary Test that JDK JMOD files do not include native debug symbols + * @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 JmodExcludedFiles + * @summary Test that JDK JMOD files do not include native debug symbols when it is not configured */ import java.nio.file.DirectoryStream; @@ -37,9 +40,11 @@ import java.nio.file.Paths; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import jdk.internal.util.OperatingSystem; +import jdk.test.whitebox.WhiteBox; public class JmodExcludedFiles { private static String javaHome = System.getProperty("java.home"); + private static final boolean expectSymbols = WhiteBox.getWhiteBox().shipsDebugInfo(); public static void main(String[] args) throws Exception { Path jmods = Path.of(javaHome, "jmods"); @@ -76,24 +81,19 @@ public class JmodExcludedFiles { if (i != -1) { if (n.substring(0, i).endsWith(".dSYM")) { System.err.println("Found symbols in " + jmod + ": " + name); - return true; + return expectSymbols ? false: true; } } } if (OperatingSystem.isWindows() && name.endsWith(".pdb")) { - // on Windows we check if we should have public symbols through --with-external-symbols-in-bundles=public (JDK-8237192) - String strippedpdb = javaHome + "/bin/" + name.substring(index + 1, name.length() - 4) + ".stripped.pdb"; - if (!Files.exists(Paths.get(strippedpdb))) { - System.err.println("Found symbols in " + jmod + ": " + name + - ". No stripped pdb file " + strippedpdb + " exists."); - return true; - } + System.err.println("Found symbols in " + jmod + ": " + name); + return expectSymbols ? false: true; } if (name.endsWith(".diz") || name.endsWith(".debuginfo") || name.endsWith(".map")) { System.err.println("Found symbols in " + jmod + ": " + name); - return true; + return expectSymbols ? false: true; } } return false; diff --git a/test/lib/jdk/test/whitebox/WhiteBox.java b/test/lib/jdk/test/whitebox/WhiteBox.java index 5741745e064..8e30c089bcb 100644 --- a/test/lib/jdk/test/whitebox/WhiteBox.java +++ b/test/lib/jdk/test/whitebox/WhiteBox.java @@ -66,7 +66,7 @@ public class WhiteBox { // Memory private native long getObjectAddress0(Object o); - public long getObjectAddress(Object o) { + public long getObjectAddress(Object o) { Objects.requireNonNull(o); return getObjectAddress0(o); } @@ -78,7 +78,12 @@ public class WhiteBox { public native long getHeapSpaceAlignment(); public native long getHeapAlignment(); - public native boolean hasExternalSymbolsStripped(); + public native boolean shipsFullDebugInfo(); + public native boolean shipsPublicDebugInfo(); + + public boolean shipsDebugInfo() { + return shipsFullDebugInfo() || shipsPublicDebugInfo(); + } private native boolean isObjectInOldGen0(Object o); public boolean isObjectInOldGen(Object o) { From 2735140147b159d3a3238804f221db4f835ef744 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 4 Dec 2025 15:25:37 +0000 Subject: [PATCH 063/141] 8370939: C2: SIGSEGV in SafePointNode::verify_input when processing MH call from Compile::process_late_inline_calls_no_inline() Reviewed-by: thartmann, vlivanov --- src/hotspot/share/opto/callGenerator.cpp | 3 +- src/hotspot/share/opto/callnode.cpp | 1 - src/hotspot/share/opto/callnode.hpp | 7 +- src/hotspot/share/opto/compile.cpp | 4 +- src/hotspot/share/opto/compile.hpp | 9 +- .../inlining/TestLateMHClonedCallNode.java | 110 ++++++++++++++++++ 6 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index 483cb731103..db03dd9d80c 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -420,7 +420,6 @@ bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms) } assert(!cg->is_late_inline() || cg->is_mh_late_inline() || AlwaysIncrementalInline || StressIncrementalInlining, "we're doing late inlining"); _inline_cg = cg; - C->dec_number_of_mh_late_inlines(); return true; } else { // Method handle call which has a constant appendix argument should be either inlined or replaced with a direct call @@ -432,7 +431,7 @@ bool LateInlineMHCallGenerator::do_late_inline_check(Compile* C, JVMState* jvms) CallGenerator* CallGenerator::for_mh_late_inline(ciMethod* caller, ciMethod* callee, bool input_not_const) { assert(IncrementalInlineMH, "required"); - Compile::current()->inc_number_of_mh_late_inlines(); + Compile::current()->mark_has_mh_late_inlines(); CallGenerator* cg = new LateInlineMHCallGenerator(caller, callee, input_not_const); return cg; } diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index ad6548a649e..4cf72fbde4b 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1145,7 +1145,6 @@ Node* CallStaticJavaNode::Ideal(PhaseGVN* phase, bool can_reshape) { assert(callee->has_member_arg(), "wrong type of call?"); if (in(TypeFunc::Parms + callee->arg_size() - 1)->Opcode() == Op_ConP) { register_for_late_inline(); - phase->C->inc_number_of_mh_late_inlines(); } } } else { diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 9029a009989..90a86d76679 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -730,9 +730,10 @@ public: // for some macro nodes whose expansion does not have a safepoint on the fast path. virtual bool guaranteed_safepoint() { return true; } // For macro nodes, the JVMState gets modified during expansion. If calls - // use MachConstantBase, it gets modified during matching. So when cloning - // the node the JVMState must be deep cloned. Default is to shallow clone. - virtual bool needs_deep_clone_jvms(Compile* C) { return C->needs_deep_clone_jvms(); } + // use MachConstantBase, it gets modified during matching. If the call is + // late inlined, it also needs the full JVMState. So when cloning the + // node the JVMState must be deep cloned. Default is to shallow clone. + virtual bool needs_deep_clone_jvms(Compile* C) { return _generator != nullptr || C->needs_deep_clone_jvms(); } // Returns true if the call may modify n virtual bool may_modify(const TypeOopPtr* t_oop, PhaseValues* phase); diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 89b5e36b120..a89b5b00a25 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -686,7 +686,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci, _boxing_late_inlines(comp_arena(), 2, 0, nullptr), _vector_reboxing_late_inlines(comp_arena(), 2, 0, nullptr), _late_inlines_pos(0), - _number_of_mh_late_inlines(0), + _has_mh_late_inlines(false), _oom(false), _replay_inline_data(nullptr), _inline_printer(this), @@ -948,7 +948,7 @@ Compile::Compile(ciEnv* ci_env, _igvn_worklist(nullptr), _types(nullptr), _node_hash(nullptr), - _number_of_mh_late_inlines(0), + _has_mh_late_inlines(false), _oom(false), _replay_inline_data(nullptr), _inline_printer(this), diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 845dcf07512..f5611062f2c 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -478,7 +478,9 @@ private: GrowableArray _vector_reboxing_late_inlines; // same but for vector reboxing operations int _late_inlines_pos; // Where in the queue should the next late inlining candidate go (emulate depth first inlining) - uint _number_of_mh_late_inlines; // number of method handle late inlining still pending + bool _has_mh_late_inlines; // Can there still be a method handle late inlining pending? + // false: there can't be one + // true: we've enqueued one at some point so there may still be one // "MemLimit" directive was specified and the memory limit was hit during compilation bool _oom; @@ -1096,9 +1098,8 @@ public: } } - void inc_number_of_mh_late_inlines() { _number_of_mh_late_inlines++; } - void dec_number_of_mh_late_inlines() { assert(_number_of_mh_late_inlines > 0, "_number_of_mh_late_inlines < 0 !"); _number_of_mh_late_inlines--; } - bool has_mh_late_inlines() const { return _number_of_mh_late_inlines > 0; } + void mark_has_mh_late_inlines() { _has_mh_late_inlines = true; } + bool has_mh_late_inlines() const { return _has_mh_late_inlines; } bool inline_incrementally_one(); void inline_incrementally_cleanup(PhaseIterGVN& igvn); diff --git a/test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java b/test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java new file mode 100644 index 00000000000..417fe60ebae --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/TestLateMHClonedCallNode.java @@ -0,0 +1,110 @@ +/* + * 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 8370939 + * @summary C2: SIGSEGV in SafePointNode::verify_input when processing MH call from Compile::process_late_inline_calls_no_inline() + * @run main/othervm -XX:-BackgroundCompilation -XX:CompileOnly=TestLateMHClonedCallNode::test1 + * -XX:CompileOnly=TestLateMHClonedCallNode::test2 TestLateMHClonedCallNode + * @run main TestLateMHClonedCallNode + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +public class TestLateMHClonedCallNode { + private static int field; + + public static void main(String[] args) throws Throwable { + for (int i = 0; i < 20_000; i++) { + test1(true); + test1(false); + test2(true); + test2(false); + } + } + + private static int test1(boolean flag) throws Throwable { + return inlined1(flag); + } + + private static int inlined1(boolean flag) throws Throwable { + MethodHandle mh = mh1; + for (int i = 0; i < 3; ++i) { + if (i > 1) { + mh = mh2; + } + } + int res = 0; + for (int i = 0; i < 2; i++) { + if (!flag) { + field = 42; + } + res += (int) mh.invokeExact(); + } + return res; + } + + private static int test2(boolean flag) throws Throwable { + int res = (int)unknownMh.invokeExact(); + return inlined2(flag); + } + + private static int inlined2(boolean flag) throws Throwable { + MethodHandle mh = mh1; + for (int i = 0; i < 3; ++i) { + if (i > 1) { + mh = mh2; + } + } + int res = 0; + for (int i = 0; i < 2; i++) { + if (!flag) { + field = 42; + } + res += (int) mh.invokeExact(); + } + return res; + } + + static final MethodHandle mh1; + static final MethodHandle mh2; + static MethodHandle unknownMh; + + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + mh1 = lookup.findStatic(TestLateMHClonedCallNode.class, "method1", MethodType.methodType(int.class)); + mh2 = lookup.findStatic(TestLateMHClonedCallNode.class, "method2", MethodType.methodType(int.class)); + unknownMh = mh1; + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + throw new RuntimeException("Method handle lookup failed"); + } + } + + static int method1() { return 0; } + static int method2() { return 42; } +} From 45dcc0e7e26b8130236c5ba80edb54fa530dab57 Mon Sep 17 00:00:00 2001 From: Kurt Miller Date: Thu, 4 Dec 2025 16:59:03 +0000 Subject: [PATCH 064/141] 8371914: PNG defines in CFLAGS can cause compilation errors with external libpng Reviewed-by: erikj, jdv --- .../java.desktop/lib/ClientLibraries.gmk | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index 4cd7f5bac90..f273065a6df 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -164,6 +164,24 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) ifeq ($(USE_EXTERNAL_LIBPNG), false) LIBSPLASHSCREEN_HEADER_DIRS += libsplashscreen/libpng + LIBSPLASHSCREEN_CFLAGS += -DPNG_NO_MMX_CODE -DPNG_ARM_NEON_OPT=0 + -DPNG_ARM_NEON_IMPLEMENTATION=0 -DPNG_LOONGARCH_LSX_OPT=0 + + ifeq ($(call isTargetOs, linux)+$(call isTargetCpuArch, ppc), true+true) + LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 + endif + + # The libpng bundled with jdk is a reduced version which does not + # contain .png_init_filter_functions_vsx. + # Therefore we need to disable PNG_POWERPC_VSX_OPT explicitly by setting + # it to 0. If this define is not set, it would be automatically set to 2, + # because + # "#if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)" + # expands to true. This would results in the fact that + # .png_init_filter_functions_vsx is needed in libpng. + ifeq ($(call isTargetOs, aix), true) + LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 + endif else LIBSPLASHSCREEN_EXCLUDES += libpng endif @@ -176,25 +194,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) LIBSPLASHSCREEN_STATIC_LIB_EXCLUDE_OBJS += $(LIBZIP_OBJS) endif - LIBSPLASHSCREEN_CFLAGS += -DSPLASHSCREEN -DPNG_NO_MMX_CODE \ - -DPNG_ARM_NEON_OPT=0 -DPNG_ARM_NEON_IMPLEMENTATION=0 \ - -DPNG_LOONGARCH_LSX_OPT=0 - - ifeq ($(call isTargetOs, linux)+$(call isTargetCpuArch, ppc), true+true) - LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 - endif - - # The external libpng submitted in the jdk is a reduced version - # which does not contain .png_init_filter_functions_vsx. - # Therefore we need to disable PNG_POWERPC_VSX_OPT explicitly by setting - # it to 0. If this define is not set, it would be automatically set to 2, - # because - # "#if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__)" - # expands to true. This would results in the fact that - # .png_init_filter_functions_vsx is needed in libpng. - ifeq ($(call isTargetOs, aix), true) - LIBSPLASHSCREEN_CFLAGS += -DPNG_POWERPC_VSX_OPT=0 - endif + LIBSPLASHSCREEN_CFLAGS += -DSPLASHSCREEN ifeq ($(call isTargetOs, macosx), true) # libsplashscreen on macosx does not use the unix code From c55287d197ef024033f8dfbb5a365cb091bc67fb Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 4 Dec 2025 17:01:41 +0000 Subject: [PATCH 065/141] 8370890: Start of release updates for JDK 27 8370893: Add SourceVersion.RELEASE_27 8370894: Add source 27 and target 27 to javac Reviewed-by: darcy, iris, liach, erikj, dholmes --- .jcheck/conf | 2 +- make/conf/version-numbers.conf | 10 +- .../share/classfile/classFileParser.cpp | 2 + .../java/lang/classfile/ClassFile.java | 10 +- .../lang/reflect/ClassFileFormatVersion.java | 14 +- .../javax/lang/model/SourceVersion.java | 19 +- .../AbstractAnnotationValueVisitor14.java | 2 +- ...AbstractAnnotationValueVisitorPreview.java | 2 +- .../model/util/AbstractElementVisitor14.java | 2 +- .../util/AbstractElementVisitorPreview.java | 2 +- .../model/util/AbstractTypeVisitor14.java | 2 +- .../util/AbstractTypeVisitorPreview.java | 2 +- .../lang/model/util/ElementKindVisitor14.java | 2 +- .../model/util/ElementKindVisitorPreview.java | 2 +- .../lang/model/util/ElementScanner14.java | 2 +- .../model/util/ElementScannerPreview.java | 2 +- .../util/SimpleAnnotationValueVisitor14.java | 2 +- .../SimpleAnnotationValueVisitorPreview.java | 2 +- .../model/util/SimpleElementVisitor14.java | 2 +- .../util/SimpleElementVisitorPreview.java | 2 +- .../lang/model/util/SimpleTypeVisitor14.java | 2 +- .../model/util/SimpleTypeVisitorPreview.java | 2 +- .../lang/model/util/TypeKindVisitor14.java | 2 +- .../model/util/TypeKindVisitorPreview.java | 2 +- .../com/sun/tools/javac/code/Source.java | 7 + .../com/sun/tools/javac/jvm/ClassFile.java | 1 + .../com/sun/tools/javac/jvm/Target.java | 3 + .../javac/processing/PrintingProcessor.java | 2 +- .../share/data/symbols/java.base-Q.sym.txt | 558 ++++++++++++++++++ .../data/symbols/java.compiler-Q.sym.txt | 85 +++ .../share/data/symbols/java.desktop-Q.sym.txt | 90 +++ .../data/symbols/java.management-Q.sym.txt | 37 ++ .../data/symbols/java.net.http-Q.sym.txt | 125 ++++ .../data/symbols/jdk.httpserver-Q.sym.txt | 32 + .../symbols/jdk.incubator.vector-Q.sym.txt | 32 + .../share/data/symbols/jdk.jartool-Q.sym.txt | 31 + .../share/data/symbols/jdk.jdeps-Q.sym.txt | 31 + .../share/data/symbols/jdk.jfr-Q.sym.txt | 31 + .../share/data/symbols/jdk.jlink-Q.sym.txt | 31 + .../share/data/symbols/jdk.jshell-Q.sym.txt | 169 ++++++ .../share/data/symbols/jdk.jsobject-Q.sym.txt | 34 ++ .../data/symbols/jdk.localedata-Q.sym.txt | 31 + src/jdk.compiler/share/data/symbols/symbols | 3 +- test/jdk/ProblemList.txt | 1 + .../javac/api/TestGetSourceVersions.java | 4 +- .../javac/classfiles/ClassVersionChecker.java | 3 +- .../lib/JavacTestingAbstractProcessor.java | 18 +- .../classReaderTest/Client.nopreview.out | 2 +- .../classReaderTest/Client.preview.out | 2 +- .../tools/javac/versions/Versions.java | 7 +- 50 files changed, 1415 insertions(+), 48 deletions(-) create mode 100644 src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt create mode 100644 src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt diff --git a/.jcheck/conf b/.jcheck/conf index 60881e74d2a..25af49f8ef8 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,7 +1,7 @@ [general] project=jdk jbs=JDK -version=26 +version=27 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists,copyright diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 977809535ba..4392d86ac33 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -26,17 +26,17 @@ # Default version, product, and vendor information to use, # unless overridden by configure -DEFAULT_VERSION_FEATURE=26 +DEFAULT_VERSION_FEATURE=27 DEFAULT_VERSION_INTERIM=0 DEFAULT_VERSION_UPDATE=0 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2026-03-17 -DEFAULT_VERSION_CLASSFILE_MAJOR=70 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" +DEFAULT_VERSION_DATE=2026-09-15 +DEFAULT_VERSION_CLASSFILE_MAJOR=71 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 -DEFAULT_ACCEPTABLE_BOOT_VERSIONS="25 26" -DEFAULT_JDK_SOURCE_TARGET_VERSION=26 +DEFAULT_ACCEPTABLE_BOOT_VERSIONS="25 26 27" +DEFAULT_JDK_SOURCE_TARGET_VERSION=27 DEFAULT_PROMOTED_VERSION_PRE=ea diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 312accb1df9..c9d9d3632b5 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -154,6 +154,8 @@ #define JAVA_26_VERSION 70 +#define JAVA_27_VERSION 71 + void ClassFileParser::set_class_bad_constant_seen(short bad_constant) { assert((bad_constant == JVM_CONSTANT_Module || bad_constant == JVM_CONSTANT_Package) && _major_version >= JAVA_9_VERSION, diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFile.java b/src/java.base/share/classes/java/lang/classfile/ClassFile.java index 216facbdddf..5a2b7e6297e 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -1038,6 +1038,14 @@ public sealed interface ClassFile */ int JAVA_26_VERSION = 70; + /** + * The class major version introduced by Java SE 27, {@value}. + * + * @see ClassFileFormatVersion#RELEASE_27 + * @since 27 + */ + int JAVA_27_VERSION = 71; + /** * A minor version number {@value} indicating a class uses preview features * of a Java SE release since 12, for major versions {@value @@ -1049,7 +1057,7 @@ public sealed interface ClassFile * {@return the latest class major version supported by the current runtime} */ static int latestMajorVersion() { - return JAVA_26_VERSION; + return JAVA_27_VERSION; } /** diff --git a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java index a4009915922..1990a467b60 100644 --- a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java +++ b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java @@ -383,6 +383,18 @@ public enum ClassFileFormatVersion { * The Java Virtual Machine Specification, Java SE 26 Edition */ RELEASE_26(70), + + /** + * The version introduced by the Java Platform, Standard Edition + * 27. + * + * @since 27 + * + * @see + * The Java Virtual Machine Specification, Java SE 27 Edition + */ + RELEASE_27(71), ; // Reduce code churn when appending new constants // Note to maintainers: when adding constants for newer releases, @@ -398,7 +410,7 @@ public enum ClassFileFormatVersion { * {@return the latest class file format version} */ public static ClassFileFormatVersion latest() { - return RELEASE_26; + return RELEASE_27; } /** diff --git a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java index e21e9e1db9a..2835143dc4e 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -86,7 +86,8 @@ public enum SourceVersion { * (primitive Types in Patterns, instanceof, and switch in * third preview) * 26: no changes (primitive Types in Patterns, instanceof, and - * switch in in fourth preview) + * switch in fourth preview) + * 27: tbd */ /** @@ -484,6 +485,18 @@ public enum SourceVersion { * The Java Language Specification, Java SE 26 Edition */ RELEASE_26, + + /** + * The version introduced by the Java Platform, Standard Edition + * 27. + * + * @since 27 + * + * @see + * The Java Language Specification, Java SE 27 Edition + */ + RELEASE_27, ; // Reduce code churn when appending new constants // Note that when adding constants for newer releases, the @@ -493,7 +506,7 @@ public enum SourceVersion { * {@return the latest source version that can be modeled} */ public static SourceVersion latest() { - return RELEASE_26; + return RELEASE_27; } private static final SourceVersion latestSupported = getLatestSupported(); @@ -508,7 +521,7 @@ public enum SourceVersion { private static SourceVersion getLatestSupported() { int intVersion = Runtime.version().feature(); return (intVersion >= 11) ? - valueOf("RELEASE_" + Math.min(26, intVersion)): + valueOf("RELEASE_" + Math.min(27, intVersion)): RELEASE_10; } diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java index 2b2f80358b0..bfd3b64a757 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor14.java @@ -44,7 +44,7 @@ import javax.annotation.processing.SupportedSourceVersion; * @see AbstractAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractAnnotationValueVisitor14 extends AbstractAnnotationValueVisitor9 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java index 59d1eb28282..31d0545744a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java @@ -50,7 +50,7 @@ import javax.annotation.processing.ProcessingEnvironment; * @see AbstractAnnotationValueVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractAnnotationValueVisitorPreview extends AbstractAnnotationValueVisitor14 { diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java index b624bb9f999..72b796a2cb7 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java @@ -50,7 +50,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractElementVisitor14 extends AbstractElementVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java index 761916a1434..009cf06a8ce 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java @@ -53,7 +53,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractElementVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractElementVisitorPreview extends AbstractElementVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java index 1860cd09ac5..95dfc473da1 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor14.java @@ -47,7 +47,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public abstract class AbstractTypeVisitor14 extends AbstractTypeVisitor9 { /** * Constructor for concrete subclasses to call. diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java index 6b701262a4f..257d7f5aa17 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java @@ -53,7 +53,7 @@ import static javax.lang.model.SourceVersion.*; * @see AbstractTypeVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public abstract class AbstractTypeVisitorPreview extends AbstractTypeVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java index cb0e1cfbc9f..58b1d81bcf9 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java @@ -61,7 +61,7 @@ import javax.lang.model.SourceVersion; * @see ElementKindVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class ElementKindVisitor14 extends ElementKindVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java index 0f436e6d1e5..e2183185b80 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java @@ -67,7 +67,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementKindVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class ElementKindVisitorPreview extends ElementKindVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java index 946cf97b092..6f7d8bc5fed 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java @@ -77,7 +77,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementScanner9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class ElementScanner14 extends ElementScanner9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java index a9d8e7c1f3f..27080c7abc5 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java @@ -81,7 +81,7 @@ import static javax.lang.model.SourceVersion.*; * @see ElementScanner14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class ElementScannerPreview extends ElementScanner14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java index 9320e18d5dd..a5e32c936e4 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitor14.java @@ -52,7 +52,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleAnnotationValueVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleAnnotationValueVisitor14 extends SimpleAnnotationValueVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java index 01509c0c4a5..a98161812fe 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java @@ -58,7 +58,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleAnnotationValueVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleAnnotationValueVisitorPreview extends SimpleAnnotationValueVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java index dff1731d3c9..da9797b2750 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java @@ -58,7 +58,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleElementVisitor9 * @since 16 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleElementVisitor14 extends SimpleElementVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java index c3896a794c0..158dd24450f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java @@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleElementVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleElementVisitorPreview extends SimpleElementVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java index d06f5d673d3..07b6b2bedbe 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor14.java @@ -56,7 +56,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleTypeVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class SimpleTypeVisitor14 extends SimpleTypeVisitor9 { /** * Constructor for concrete subclasses; uses {@code null} for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java index 11e2e8a50d5..ff9a3050e12 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java @@ -62,7 +62,7 @@ import static javax.lang.model.SourceVersion.*; * @see SimpleTypeVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class SimpleTypeVisitorPreview extends SimpleTypeVisitor14 { /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java index 295ceb200b8..8c80f4ad79a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitor14.java @@ -61,7 +61,7 @@ import static javax.lang.model.SourceVersion.*; * @see TypeKindVisitor9 * @since 14 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) public class TypeKindVisitor14 extends TypeKindVisitor9 { /** * Constructor for concrete subclasses to call; uses {@code null} diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java index c0ca3a0450a..62c059c605f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java @@ -66,7 +66,7 @@ import static javax.lang.model.SourceVersion.*; * @see TypeKindVisitor14 * @since 23 */ -@SupportedSourceVersion(RELEASE_26) +@SupportedSourceVersion(RELEASE_27) @PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) public class TypeKindVisitorPreview extends TypeKindVisitor14 { /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java index d0cb45ebc09..84a823f785f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java @@ -158,6 +158,11 @@ public enum Source { * 26, tbd */ JDK26("26"), + + /** + * 27, tbd + */ + JDK27("27"), ; // Reduce code churn when appending new constants private static final Context.Key sourceKey = new Context.Key<>(); @@ -210,6 +215,7 @@ public enum Source { public Target requiredTarget() { return switch(this) { + case JDK27 -> Target.JDK1_27; case JDK26 -> Target.JDK1_26; case JDK25 -> Target.JDK1_25; case JDK24 -> Target.JDK1_24; @@ -366,6 +372,7 @@ public enum Source { case JDK24 -> RELEASE_24; case JDK25 -> RELEASE_25; case JDK26 -> RELEASE_26; + case JDK27 -> RELEASE_27; default -> null; }; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java index e5adecdb107..ae1aab1cefd 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java @@ -130,6 +130,7 @@ public class ClassFile { V68(68, 0), // JDK 24 V69(69, 0), // JDK 25 V70(70, 0), // JDK 26 + V71(71, 0), // JDK 27 ; // Reduce code churn when appending new constants Version(int major, int minor) { this.major = major; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java index f60adcb3b80..b0a298fc845 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java @@ -113,6 +113,9 @@ public enum Target { /** JDK 26. */ JDK1_26("26", 70, 0), + + /** JDK 27. */ + JDK1_27("27", 71, 0), ; // Reduce code churn when appending new constants private static final Context.Key targetKey = new Context.Key<>(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java index 7aaf035fd36..bcc9ccd0113 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/PrintingProcessor.java @@ -55,7 +55,7 @@ import com.sun.tools.javac.util.StringUtils; * deletion without notice. */ @SupportedAnnotationTypes("*") -@SupportedSourceVersion(SourceVersion.RELEASE_26) +@SupportedSourceVersion(SourceVersion.RELEASE_27) public class PrintingProcessor extends AbstractProcessor { PrintWriter writer; 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 new file mode 100644 index 00000000000..fb1ec6ec7bb --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.base-Q.sym.txt @@ -0,0 +1,558 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name java.base +header exports java/io,java/lang,java/lang/annotation,java/lang/classfile,java/lang/classfile/attribute,java/lang/classfile/constantpool,java/lang/classfile/instruction,java/lang/constant,java/lang/foreign,java/lang/invoke,java/lang/module,java/lang/ref,java/lang/reflect,java/lang/runtime,java/math,java/net,java/net/spi,java/nio,java/nio/channels,java/nio/channels/spi,java/nio/charset,java/nio/charset/spi,java/nio/file,java/nio/file/attribute,java/nio/file/spi,java/security,java/security/cert,java/security/interfaces,java/security/spec,java/text,java/text/spi,java/time,java/time/chrono,java/time/format,java/time/temporal,java/time/zone,java/util,java/util/concurrent,java/util/concurrent/atomic,java/util/concurrent/locks,java/util/function,java/util/jar,java/util/random,java/util/regex,java/util/spi,java/util/stream,java/util/zip,javax/crypto,javax/crypto/interfaces,javax/crypto/spec,javax/net,javax/net/ssl,javax/security/auth,javax/security/auth/callback,javax/security/auth/login,javax/security/auth/spi,javax/security/auth/x500,javax/security/cert,jdk/internal/event[jdk.jfr],jdk/internal/javac[java.compiler\u005C;u002C;jdk.compiler],jdk/internal/vm/vector[jdk.incubator.vector] extraModulePackages jdk/internal/access/foreign,jdk/internal/classfile/impl,jdk/internal/constant,jdk/internal/foreign/abi,jdk/internal/foreign/abi/aarch64/linux,jdk/internal/foreign/abi/aarch64/macos,jdk/internal/foreign/abi/aarch64/windows,jdk/internal/foreign/abi/fallback,jdk/internal/foreign/abi/ppc64/aix,jdk/internal/foreign/abi/ppc64/linux,jdk/internal/foreign/abi/riscv64/linux,jdk/internal/foreign/abi/s390/linux,jdk/internal/foreign/abi/x64/sysv,jdk/internal/foreign/abi/x64/windows,jdk/internal/foreign/layout,jdk/internal/lang,sun/nio,sun/nio/ch,sun/net,jdk/internal/foreign,jdk/internal/foreign,sun/net,sun/nio/ch uses java/lang/System$LoggerFinder,java/net/ContentHandlerFactory,java/net/spi/InetAddressResolverProvider,java/net/spi/URLStreamHandlerProvider,java/nio/channels/spi/AsynchronousChannelProvider,java/nio/channels/spi/SelectorProvider,java/nio/charset/spi/CharsetProvider,java/nio/file/spi/FileSystemProvider,java/nio/file/spi/FileTypeDetector,java/security/Provider,java/text/spi/BreakIteratorProvider,java/text/spi/CollatorProvider,java/text/spi/DateFormatProvider,java/text/spi/DateFormatSymbolsProvider,java/text/spi/DecimalFormatSymbolsProvider,java/text/spi/NumberFormatProvider,java/time/chrono/AbstractChronology,java/time/chrono/Chronology,java/time/zone/ZoneRulesProvider,java/util/spi/CalendarDataProvider,java/util/spi/CalendarNameProvider,java/util/spi/CurrencyNameProvider,java/util/spi/LocaleNameProvider,java/util/spi/ResourceBundleControlProvider,java/util/spi/ResourceBundleProvider,java/util/spi/TimeZoneNameProvider,java/util/spi/ToolProvider,javax/security/auth/spi/LoginModule,jdk/internal/io/JdkConsoleProvider,jdk/internal/logger/DefaultLoggerFinder,sun/text/spi/JavaTimeDateTimePatternProvider,sun/util/locale/provider/LocaleDataMetaInfo,sun/util/resources/LocaleData$LocaleDataResourceBundleProvider,sun/util/spi/CalendarProvider provides interface\u0020;java/nio/file/spi/FileSystemProvider\u0020;impls\u0020;jdk/internal/jrtfs/JrtFileSystemProvider target macos-aarch64 flags 8000 + +class name java/lang/Character$UnicodeBlock +field name SIDETIC descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name SHARADA_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TOLONG_SIKI descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name BERIA_ERFE descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TANGUT_COMPONENTS_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name MISCELLANEOUS_SYMBOLS_SUPPLEMENT descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name TAI_YO descriptor Ljava/lang/Character$UnicodeBlock; flags 19 +field name CJK_UNIFIED_IDEOGRAPHS_EXTENSION_J descriptor Ljava/lang/Character$UnicodeBlock; flags 19 + +class name java/lang/Character$UnicodeScript +field name SIDETIC descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name TOLONG_SIKI descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name BERIA_ERFE descriptor Ljava/lang/Character$UnicodeScript; flags 4019 +field name TAI_YO descriptor Ljava/lang/Character$UnicodeScript; flags 4019 + +class name java/lang/Class +header extends java/lang/Object implements java/io/Serializable,java/lang/reflect/GenericDeclaration,java/lang/reflect/Type,java/lang/reflect/AnnotatedElement,java/lang/invoke/TypeDescriptor$OfField,java/lang/constant/Constable flags 31 signature Ljava/lang/Object;Ljava/io/Serializable;Ljava/lang/reflect/GenericDeclaration;Ljava/lang/reflect/Type;Ljava/lang/reflect/AnnotatedElement;Ljava/lang/invoke/TypeDescriptor$OfField;>;Ljava/lang/constant/Constable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/TypeDescriptor$OfField outerClass java/lang/invoke/TypeDescriptor innerClassName OfField flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/ClassLoader +header extends java/lang/Object flags 421 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/LazyConstant +header extends java/lang/Object implements java/util/function/Supplier sealed true permittedSubclasses jdk/internal/lang/LazyConstantImpl flags 601 signature Ljava/lang/Object;Ljava/util/function/Supplier; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) +method name orElse descriptor (Ljava/lang/Object;)Ljava/lang/Object; flags 401 signature (TT;)TT; +method name get descriptor ()Ljava/lang/Object; flags 401 signature ()TT; +method name isInitialized descriptor ()Z flags 401 +method name equals descriptor (Ljava/lang/Object;)Z flags 401 +method name hashCode descriptor ()I flags 401 +method name toString descriptor ()Ljava/lang/String; flags 401 +method name of descriptor (Ljava/util/function/Supplier;)Ljava/lang/LazyConstant; flags 9 signature (Ljava/util/function/Supplier<+TT;>;)Ljava/lang/LazyConstant; + +class name java/lang/Math +-method name sinh descriptor (D)D +method name sinh descriptor (D)D flags 9 runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; + +class name java/lang/Object +header flags 21 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/Process +header extends java/lang/Object implements java/io/Closeable flags 421 +innerclass innerClass java/util/concurrent/ForkJoinPool$ManagedBlocker outerClass java/util/concurrent/ForkJoinPool innerClassName ManagedBlocker flags 609 +innerclass innerClass java/lang/ProcessHandle$Info outerClass java/lang/ProcessHandle innerClassName Info flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name close descriptor ()V thrownTypes java/io/IOException flags 1 + +-class name java/lang/StableValue + +class name java/lang/Thread +-method name stop descriptor ()V + +class name java/lang/classfile/ClassFile +field name JAVA_26_VERSION descriptor I constantValue 70 flags 19 + +class name java/lang/classfile/Signature$ClassTypeSig +-method name of descriptor (Ljava/lang/classfile/Signature$ClassTypeSig;Ljava/lang/constant/ClassDesc;[Ljava/lang/classfile/Signature$TypeArg;)Ljava/lang/classfile/Signature$ClassTypeSig; +method name of descriptor (Ljava/lang/classfile/Signature$ClassTypeSig;Ljava/lang/constant/ClassDesc;[Ljava/lang/classfile/Signature$TypeArg;)Ljava/lang/classfile/Signature$ClassTypeSig; flags 89 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +-class name java/lang/constant/AsTypeMethodHandleDesc + +class name java/lang/constant/ConstantDescs +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 + +class name java/lang/constant/DynamicConstantDesc +header extends java/lang/Object implements java/lang/constant/ConstantDesc flags 421 signature Ljava/lang/Object;Ljava/lang/constant/ConstantDesc; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/Enum$EnumDesc outerClass java/lang/Enum innerClassName EnumDesc flags 19 +innerclass innerClass java/lang/invoke/VarHandle$VarHandleDesc outerClass java/lang/invoke/VarHandle innerClassName VarHandleDesc flags 19 + +class name java/lang/constant/MethodHandleDesc +header extends java/lang/Object implements java/lang/constant/ConstantDesc sealed true permittedSubclasses jdk/internal/constant/AsTypeMethodHandleDesc,java/lang/constant/DirectMethodHandleDesc flags 601 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/BoundMethodHandle +header extends java/lang/invoke/MethodHandle flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/invoke/DelegatingMethodHandle +header extends java/lang/invoke/MethodHandle sealed true permittedSubclasses java/lang/invoke/MethodHandleImpl$AsVarargsCollector,java/lang/invoke/MethodHandleImpl$WrappedMember,java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle,java/lang/invoke/MethodHandleImpl$CountingWrapper flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 + +class name java/lang/invoke/DirectMethodHandle +header extends java/lang/invoke/MethodHandle nestMembers java/lang/invoke/DirectMethodHandle$StaticAccessor,java/lang/invoke/DirectMethodHandle$Accessor,java/lang/invoke/DirectMethodHandle$Constructor,java/lang/invoke/DirectMethodHandle$Interface,java/lang/invoke/DirectMethodHandle$Special sealed true permittedSubclasses java/lang/invoke/DirectMethodHandle$Special,java/lang/invoke/DirectMethodHandle$Interface,java/lang/invoke/DirectMethodHandle$Constructor,java/lang/invoke/DirectMethodHandle$Accessor,java/lang/invoke/DirectMethodHandle$StaticAccessor flags 20 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/DirectMethodHandle$Special outerClass java/lang/invoke/DirectMethodHandle innerClassName Special flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Interface outerClass java/lang/invoke/DirectMethodHandle innerClassName Interface flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$StaticAccessor outerClass java/lang/invoke/DirectMethodHandle innerClassName StaticAccessor flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Accessor outerClass java/lang/invoke/DirectMethodHandle innerClassName Accessor flags 18 +innerclass innerClass java/lang/invoke/DirectMethodHandle$Constructor outerClass java/lang/invoke/DirectMethodHandle innerClassName Constructor flags 18 + +class name java/lang/invoke/DirectMethodHandle$Constructor +header extends java/lang/invoke/DirectMethodHandle nestHost java/lang/invoke/DirectMethodHandle flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/DirectMethodHandle$Constructor outerClass java/lang/invoke/DirectMethodHandle innerClassName Constructor flags 18 + +class name java/lang/invoke/LambdaForm +header extends java/lang/Object flags 20 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/lang/invoke/LambdaMetafactory +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/MethodHandle +header extends java/lang/Object implements java/lang/constant/Constable sealed true permittedSubclasses java/lang/invoke/NativeMethodHandle,java/lang/invoke/DirectMethodHandle,java/lang/invoke/DelegatingMethodHandle,java/lang/invoke/BoundMethodHandle flags 421 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 + +class name java/lang/invoke/MethodHandleImpl +header extends java/lang/Object nestMembers java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle,java/lang/invoke/MethodHandleImpl$WrappedMember,java/lang/invoke/MethodHandleImpl$CountingWrapper,java/lang/invoke/MethodHandleImpl$AsVarargsCollector flags 420 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/invoke/MethodHandleImpl$AsVarargsCollector +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$AsVarargsCollector outerClass java/lang/invoke/MethodHandleImpl innerClassName AsVarargsCollector flags 18 + +class name java/lang/invoke/MethodHandleImpl$CountingWrapper +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$CountingWrapper outerClass java/lang/invoke/MethodHandleImpl innerClassName CountingWrapper flags 18 + +class name java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$IntrinsicMethodHandle outerClass java/lang/invoke/MethodHandleImpl innerClassName IntrinsicMethodHandle flags 18 + +class name java/lang/invoke/MethodHandleImpl$WrappedMember +header extends java/lang/invoke/DelegatingMethodHandle nestHost java/lang/invoke/MethodHandleImpl flags 30 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandleImpl$WrappedMember outerClass java/lang/invoke/MethodHandleImpl innerClassName WrappedMember flags 18 + +class name java/lang/invoke/MethodHandles +header extends java/lang/Object nestMembers java/lang/invoke/MethodHandles$Lookup,java/lang/invoke/MethodHandles$Lookup$ClassOption flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/invoke/VarHandle$AccessMode outerClass java/lang/invoke/VarHandle innerClassName AccessMode flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup$ClassOption outerClass java/lang/invoke/MethodHandles$Lookup innerClassName ClassOption flags 4019 + +class name java/lang/invoke/StringConcatFactory +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/module/ModuleDescriptor +header extends java/lang/Object implements java/lang/Comparable nestMembers java/lang/module/ModuleDescriptor$Builder,java/lang/module/ModuleDescriptor$Version,java/lang/module/ModuleDescriptor$Provides,java/lang/module/ModuleDescriptor$Opens,java/lang/module/ModuleDescriptor$Opens$Modifier,java/lang/module/ModuleDescriptor$Exports,java/lang/module/ModuleDescriptor$Exports$Modifier,java/lang/module/ModuleDescriptor$Requires,java/lang/module/ModuleDescriptor$Requires$Modifier,java/lang/module/ModuleDescriptor$Modifier flags 31 signature Ljava/lang/Object;Ljava/lang/Comparable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/module/ModuleDescriptor$Version outerClass java/lang/module/ModuleDescriptor innerClassName Version flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Modifier outerClass java/lang/module/ModuleDescriptor innerClassName Modifier flags 4019 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Builder outerClass java/lang/module/ModuleDescriptor innerClassName Builder flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Provides outerClass java/lang/module/ModuleDescriptor innerClassName Provides flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Opens outerClass java/lang/module/ModuleDescriptor innerClassName Opens flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Exports outerClass java/lang/module/ModuleDescriptor innerClassName Exports flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Requires outerClass java/lang/module/ModuleDescriptor innerClassName Requires flags 19 +innerclass innerClass java/lang/module/ModuleDescriptor$Opens$Modifier outerClass java/lang/module/ModuleDescriptor$Opens innerClassName Modifier flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Exports$Modifier outerClass java/lang/module/ModuleDescriptor$Exports innerClassName Modifier flags 4019 +innerclass innerClass java/lang/module/ModuleDescriptor$Requires$Modifier outerClass java/lang/module/ModuleDescriptor$Requires innerClassName Modifier flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/ref/PhantomReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/Reference +header extends java/lang/Object sealed true permittedSubclasses java/lang/ref/PhantomReference,java/lang/ref/SoftReference,java/lang/ref/WeakReference,java/lang/ref/FinalReference flags 421 signature Ljava/lang/Object; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} +-method name get descriptor ()Ljava/lang/Object; +method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; + +class name java/lang/ref/ReferenceQueue +header extends java/lang/Object flags 21 signature Ljava/lang/Object; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/SoftReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/ref/WeakReference +header extends java/lang/ref/Reference flags 21 signature Ljava/lang/ref/Reference; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} + +class name java/lang/reflect/ClassFileFormatVersion +field name RELEASE_26 descriptor Ljava/lang/reflect/ClassFileFormatVersion; flags 4019 + +class name java/lang/reflect/Field +header extends java/lang/reflect/AccessibleObject implements java/lang/reflect/Member flags 31 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/StackWalker$Option outerClass java/lang/StackWalker innerClassName Option flags 4019 +innerclass innerClass java/lang/StackWalker$StackFrame outerClass java/lang/StackWalker innerClassName StackFrame flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/lang/runtime/ObjectMethods +header extends java/lang/Object flags 31 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/classfile/ClassFile$Option outerClass java/lang/classfile/ClassFile innerClassName Option flags 609 +innerclass innerClass java/lang/classfile/ClassFile$ClassHierarchyResolverOption outerClass java/lang/classfile/ClassFile innerClassName ClassHierarchyResolverOption flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup$ClassOption outerClass java/lang/invoke/MethodHandles$Lookup innerClassName ClassOption flags 4019 + +class name java/math/BigInteger +method name rootn descriptor (I)Ljava/math/BigInteger; flags 1 +method name rootnAndRemainder descriptor (I)[Ljava/math/BigInteger; flags 1 + +class name java/net/DatagramSocketImpl +-method name setTTL descriptor (B)V +-method name getTTL descriptor ()B + +class name java/net/MulticastSocket +-method name setTTL descriptor (B)V +-method name getTTL descriptor ()B +-method name send descriptor (Ljava/net/DatagramPacket;B)V + +class name java/net/ServerSocket +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/Socket +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/SocketImpl +-method name setPerformancePreferences descriptor (III)V +method name setPerformancePreferences descriptor (III)V flags 4 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") + +class name java/net/SocketPermission +header extends java/security/Permission implements java/io/Serializable flags 31 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="26") +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/net/URI +header extends java/lang/Object implements java/lang/Comparable,java/io/Serializable flags 31 signature Ljava/lang/Object;Ljava/lang/Comparable;Ljava/io/Serializable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/text/Normalizer$Form outerClass java/text/Normalizer innerClassName Form flags 4019 + +class name java/net/URL +header extends java/lang/Object implements java/io/Serializable flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/ScopedValue$Carrier outerClass java/lang/ScopedValue innerClassName Carrier flags 19 +innerclass innerClass java/lang/ScopedValue$CallableOp outerClass java/lang/ScopedValue innerClassName CallableOp flags 609 +innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/nio/ByteOrder +header extends java/lang/Enum flags 4031 signature Ljava/lang/Enum; +-field name BIG_ENDIAN descriptor Ljava/nio/ByteOrder; +-field name LITTLE_ENDIAN descriptor Ljava/nio/ByteOrder; +-method name toString descriptor ()Ljava/lang/String; +field name LITTLE_ENDIAN descriptor Ljava/nio/ByteOrder; flags 4019 +field name BIG_ENDIAN descriptor Ljava/nio/ByteOrder; flags 4019 +method name values descriptor ()[Ljava/nio/ByteOrder; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljava/nio/ByteOrder; flags 9 methodParameters 8000:null + +class name java/nio/DirectByteBuffer +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectCharBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectCharBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectDoubleBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectDoubleBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectFloatBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectFloatBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectIntBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectIntBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectLongBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectLongBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectShortBufferS +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/DirectShortBufferU +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 1 + +class name java/nio/charset/Charset +header extends java/lang/Object implements java/lang/Comparable flags 421 signature Ljava/lang/Object;Ljava/lang/Comparable; +innerclass innerClass java/lang/ScopedValue$Carrier outerClass java/lang/ScopedValue innerClassName Carrier flags 19 +innerclass innerClass java/lang/ScopedValue$CallableOp outerClass java/lang/ScopedValue innerClassName CallableOp flags 609 + +class name java/security/DEREncodable +header extends java/lang/Object sealed true permittedSubclasses java/security/AsymmetricKey,java/security/KeyPair,java/security/spec/PKCS8EncodedKeySpec,java/security/spec/X509EncodedKeySpec,javax/crypto/EncryptedPrivateKeyInfo,java/security/cert/X509Certificate,java/security/cert/X509CRL,java/security/PEM flags 601 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) + +class name java/security/PEM +header extends java/lang/Record implements java/security/DEREncodable record true flags 31 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +recordcomponent name type descriptor Ljava/lang/String; +recordcomponent name content descriptor Ljava/lang/String; +recordcomponent name leadingData descriptor [B +innerclass innerClass java/util/Base64$Decoder outerClass java/util/Base64 innerClassName Decoder flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name descriptor (Ljava/lang/String;Ljava/lang/String;[B)V flags 1 methodParameters 8000:type,8000:content,8000:leadingData +method name descriptor (Ljava/lang/String;Ljava/lang/String;)V flags 1 +method name toString descriptor ()Ljava/lang/String; flags 11 +method name decode descriptor ()[B flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name type descriptor ()Ljava/lang/String; flags 1 +method name content descriptor ()Ljava/lang/String; flags 1 +method name leadingData descriptor ()[B flags 1 + +class name java/security/PEMDecoder +header extends java/lang/Object flags 31 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +innerclass innerClass java/lang/ref/Cleaner$Cleanable outerClass java/lang/ref/Cleaner innerClassName Cleanable flags 609 +innerclass innerClass java/util/Base64$Decoder outerClass java/util/Base64 innerClassName Decoder flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +-class name java/security/PEMRecord + +class name java/security/SecureRandom +method name nextLong descriptor ()J flags 1 + +class name java/time/Duration +field name MIN descriptor Ljava/time/Duration; flags 19 +field name MAX descriptor Ljava/time/Duration; flags 19 + +class name java/time/Instant +method name plusSaturating descriptor (Ljava/time/Duration;)Ljava/time/Instant; flags 1 + +class name java/util/AbstractMap +header extends java/lang/Object implements java/util/Map nestMembers java/util/AbstractMap$SimpleImmutableEntry,java/util/AbstractMap$SimpleEntry flags 421 signature Ljava/lang/Object;Ljava/util/Map; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/util/AbstractMap$SimpleImmutableEntry outerClass java/util/AbstractMap innerClassName SimpleImmutableEntry flags 9 +innerclass innerClass java/util/AbstractMap$SimpleEntry outerClass java/util/AbstractMap innerClassName SimpleEntry flags 9 + +class name java/util/Collections +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; + +class name java/util/Comparator +method name max descriptor (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TU;TU;)TU; +method name min descriptor (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TU;TU;)TU; + +class name java/util/List +method name ofLazy descriptor (ILjava/util/function/IntFunction;)Ljava/util/List; flags 9 signature (ILjava/util/function/IntFunction<+TE;>;)Ljava/util/List; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) + +class name java/util/Locale +header extends java/lang/Object implements java/lang/Cloneable,java/io/Serializable nestMembers java/util/Locale$LanguageRange,java/util/Locale$FilteringMode,java/util/Locale$Builder,java/util/Locale$Category,java/util/Locale$IsoCountryCode flags 31 +innerclass innerClass java/util/Locale$Category outerClass java/util/Locale innerClassName Category flags 4019 +innerclass innerClass java/util/Locale$IsoCountryCode outerClass java/util/Locale innerClassName IsoCountryCode flags 4019 +innerclass innerClass java/io/ObjectOutputStream$PutField outerClass java/io/ObjectOutputStream innerClassName PutField flags 409 +innerclass innerClass java/io/ObjectInputStream$GetField outerClass java/io/ObjectInputStream innerClassName GetField flags 409 +innerclass innerClass java/util/Locale$FilteringMode outerClass java/util/Locale innerClassName FilteringMode flags 4019 +innerclass innerClass java/util/Locale$LanguageRange outerClass java/util/Locale innerClassName LanguageRange flags 19 +innerclass innerClass java/util/Locale$Builder outerClass java/util/Locale innerClassName Builder flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/util/Locale$IsoCountryCode +header extends java/lang/Enum nestHost java/util/Locale flags 4031 signature Ljava/lang/Enum; +innerclass innerClass java/util/Locale$IsoCountryCode outerClass java/util/Locale innerClassName IsoCountryCode flags 4019 + +class name java/util/Map +method name ofLazy descriptor (Ljava/util/Set;Ljava/util/function/Function;)Ljava/util/Map; flags 9 signature (Ljava/util/Set<+TK;>;Ljava/util/function/Function<-TK;+TV;>;)Ljava/util/Map; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LAZY_CONSTANTS;) + +class name java/util/UUID +method name ofEpochMillis descriptor (J)Ljava/util/UUID; flags 9 + +class name java/util/WeakHashMap +header extends java/util/AbstractMap implements java/util/Map flags 21 signature Ljava/util/AbstractMap;Ljava/util/Map; runtimeTypeAnnotations @Ljdk/internal/RequiresIdentity;{typeParameterIndex=I0,targetType="CLASS_TYPE_PARAMETER"} +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 + +class name java/util/concurrent/ConcurrentHashMap +header extends java/util/AbstractMap implements java/util/concurrent/ConcurrentMap,java/io/Serializable nestMembers java/util/concurrent/ConcurrentHashMap$EntrySetView,java/util/concurrent/ConcurrentHashMap$ValuesView,java/util/concurrent/ConcurrentHashMap$KeySetView,java/util/concurrent/ConcurrentHashMap$CollectionView flags 21 signature Ljava/util/AbstractMap;Ljava/util/concurrent/ConcurrentMap;Ljava/io/Serializable; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$KeySetView outerClass java/util/concurrent/ConcurrentHashMap innerClassName KeySetView flags 19 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$ValuesView outerClass java/util/concurrent/ConcurrentHashMap innerClassName ValuesView flags 18 +innerclass innerClass java/util/concurrent/ConcurrentHashMap$EntrySetView outerClass java/util/concurrent/ConcurrentHashMap innerClassName EntrySetView flags 18 +innerclass innerClass java/io/ObjectOutputStream$PutField outerClass java/io/ObjectOutputStream innerClassName PutField flags 409 +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/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; + +class name java/util/concurrent/StructuredTaskScope$Joiner +header extends java/lang/Object nestHost java/util/concurrent/StructuredTaskScope flags 601 signature Ljava/lang/Object; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;STRUCTURED_CONCURRENCY;) +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$TimeoutException outerClass java/util/concurrent/StructuredTaskScope innerClassName TimeoutException flags 19 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Joiner outerClass java/util/concurrent/StructuredTaskScope innerClassName Joiner flags 609 +-method name onFork descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +-method name onComplete descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +-method name allSuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +-method name anySuccessfulResultOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +-method name allUntil descriptor (Ljava/util/function/Predicate;)Ljava/util/concurrent/StructuredTaskScope$Joiner; +method name onFork descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z flags 1 signature (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +method name onComplete descriptor (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z flags 1 signature (Ljava/util/concurrent/StructuredTaskScope$Subtask;)Z +method name onTimeout descriptor ()V flags 1 +method name allSuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature ()Ljava/util/concurrent/StructuredTaskScope$Joiner;>; +method name anySuccessfulOrThrow descriptor ()Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature ()Ljava/util/concurrent/StructuredTaskScope$Joiner; +method name allUntil descriptor (Ljava/util/function/Predicate;)Ljava/util/concurrent/StructuredTaskScope$Joiner; flags 9 signature (Ljava/util/function/Predicate;>;)Ljava/util/concurrent/StructuredTaskScope$Joiner;>;>; + +class name java/util/concurrent/StructuredTaskScopeImpl +header extends java/lang/Object implements java/util/concurrent/StructuredTaskScope nestMembers java/util/concurrent/StructuredTaskScopeImpl$ConfigImpl,java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl flags 30 signature Ljava/lang/Object;Ljava/util/concurrent/StructuredTaskScope; +innerclass innerClass java/util/concurrent/StructuredTaskScope$Joiner outerClass java/util/concurrent/StructuredTaskScope innerClassName Joiner flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$ConfigImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName ConfigImpl flags 18 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Configuration outerClass java/util/concurrent/StructuredTaskScope innerClassName Configuration flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName SubtaskImpl flags 18 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$FailedException outerClass java/util/concurrent/StructuredTaskScope innerClassName FailedException flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl +header extends java/lang/Object implements java/util/concurrent/StructuredTaskScope$Subtask,java/lang/Runnable nestHost java/util/concurrent/StructuredTaskScopeImpl flags 30 signature Ljava/lang/Object;Ljava/util/concurrent/StructuredTaskScope$Subtask;Ljava/lang/Runnable; +innerclass innerClass java/util/concurrent/StructuredTaskScopeImpl$SubtaskImpl outerClass java/util/concurrent/StructuredTaskScopeImpl innerClassName SubtaskImpl flags 18 +innerclass innerClass java/lang/Thread$State outerClass java/lang/Thread innerClassName State flags 4019 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask outerClass java/util/concurrent/StructuredTaskScope innerClassName Subtask flags 609 +innerclass innerClass java/util/concurrent/StructuredTaskScope$Subtask$State outerClass java/util/concurrent/StructuredTaskScope$Subtask innerClassName State flags 4019 + +class name java/util/stream/Collectors +header extends java/lang/Object flags 31 runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/util/stream/Collector$Characteristics outerClass java/util/stream/Collector innerClassName Characteristics flags 4019 +innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + +class name javax/crypto/EncryptedPrivateKeyInfo +header extends java/lang/Object implements java/security/DEREncodable flags 21 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +-method name encryptKey descriptor (Ljava/security/PrivateKey;[CLjava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name encryptKey descriptor (Ljava/security/PrivateKey;[C)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name encryptKey descriptor (Ljava/security/PrivateKey;Ljava/security/Key;Ljava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;Ljava/security/SecureRandom;)Ljavax/crypto/EncryptedPrivateKeyInfo; +-method name getKey descriptor ([C)Ljava/security/PrivateKey; +-method name getKey descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/PrivateKey; +method name encrypt descriptor (Ljava/security/DEREncodable;[CLjava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name encrypt descriptor (Ljava/security/DEREncodable;[C)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name encrypt descriptor (Ljava/security/DEREncodable;Ljava/security/Key;Ljava/lang/String;Ljava/security/spec/AlgorithmParameterSpec;Ljava/security/Provider;Ljava/security/SecureRandom;)Ljavax/crypto/EncryptedPrivateKeyInfo; flags 9 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKey descriptor ([C)Ljava/security/PrivateKey; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKey descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/PrivateKey; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKeyPair descriptor ([C)Ljava/security/KeyPair; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) +method name getKeyPair descriptor (Ljava/security/Key;Ljava/security/Provider;)Ljava/security/KeyPair; thrownTypes java/security/NoSuchAlgorithmException,java/security/InvalidKeyException flags 1 classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;PEM_API;) + +class name jdk/internal/classfile/impl/DirectCodeBuilder +header extends jdk/internal/classfile/impl/AbstractDirectBuilder implements jdk/internal/classfile/impl/TerminalCodeBuilder flags 31 signature Ljdk/internal/classfile/impl/AbstractDirectBuilder;Ljdk/internal/classfile/impl/TerminalCodeBuilder; +innerclass innerClass jdk/internal/classfile/impl/AbstractPseudoInstruction$ExceptionCatchImpl outerClass jdk/internal/classfile/impl/AbstractPseudoInstruction innerClassName ExceptionCatchImpl flags 19 +innerclass innerClass java/lang/classfile/Opcode$Kind outerClass java/lang/classfile/Opcode innerClassName Kind flags 4019 + +class name jdk/internal/classfile/impl/SignaturesImpl +method name nextIdentifierEnd descriptor (Ljava/lang/String;I)I flags 9 +method name validateIdentifier descriptor (Ljava/lang/String;)Ljava/lang/String; flags 9 +method name validatePackageSpecifierPlusIdentifier descriptor (Ljava/lang/String;)Ljava/lang/String; flags 9 +method name validateNonVoid descriptor (Ljava/lang/classfile/Signature;)Ljava/lang/classfile/Signature; flags 9 +method name validateArgumentList descriptor ([Ljava/lang/classfile/Signature;)Ljava/util/List; flags 9 signature ([Ljava/lang/classfile/Signature;)Ljava/util/List; +method name validateArgumentList descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;)Ljava/util/List; + +class name jdk/internal/classfile/impl/Util +header extends java/lang/Object nestMembers jdk/internal/classfile/impl/Util$WritableLocalVariable,jdk/internal/classfile/impl/Util$Writable flags 31 +innerclass innerClass java/lang/classfile/AttributeMapper$AttributeStability outerClass java/lang/classfile/AttributeMapper innerClassName AttributeStability flags 4019 +innerclass innerClass java/lang/classfile/ClassFile$AttributesProcessingOption outerClass java/lang/classfile/ClassFile innerClassName AttributesProcessingOption flags 4019 +innerclass innerClass java/lang/classfile/Opcode$Kind outerClass java/lang/classfile/Opcode innerClassName Kind flags 4019 +innerclass innerClass jdk/internal/classfile/impl/AbstractPoolEntry$Utf8EntryImpl outerClass jdk/internal/classfile/impl/AbstractPoolEntry innerClassName Utf8EntryImpl flags 19 +innerclass innerClass jdk/internal/classfile/impl/Util$Writable outerClass jdk/internal/classfile/impl/Util innerClassName Writable flags 608 +innerclass innerClass jdk/internal/classfile/impl/Util$WritableLocalVariable outerClass jdk/internal/classfile/impl/Util innerClassName WritableLocalVariable flags 608 +innerclass innerClass java/lang/reflect/AccessFlag$Location outerClass java/lang/reflect/AccessFlag innerClassName Location flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name sanitizeU1List descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;)Ljava/util/List; +method name sanitizeU2List descriptor (Ljava/util/Collection;)Ljava/util/List; flags 9 signature (Ljava/util/Collection;)Ljava/util/List; +method name sanitizeParameterAnnotations descriptor (Ljava/util/List;)Ljava/util/List; flags 9 signature (Ljava/util/List;>;)Ljava/util/List;>; +method name checkU1 descriptor (ILjava/lang/String;)I flags 9 +method name checkU2 descriptor (ILjava/lang/String;)C flags 9 +method name outOfRangeException descriptor (ILjava/lang/String;Ljava/lang/String;)Ljava/lang/IllegalArgumentException; flags 9 +method name checkFlags descriptor (I)C flags 9 + +class name jdk/internal/constant/AsTypeMethodHandleDesc +header extends java/lang/constant/DynamicConstantDesc implements java/lang/constant/MethodHandleDesc flags 31 signature Ljava/lang/constant/DynamicConstantDesc;Ljava/lang/constant/MethodHandleDesc; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/constant/DirectMethodHandleDesc$Kind outerClass java/lang/constant/DirectMethodHandleDesc innerClassName Kind flags 4019 +method name descriptor (Ljava/lang/constant/MethodHandleDesc;Ljava/lang/constant/MethodTypeDesc;)V flags 1 +method name invocationType descriptor ()Ljava/lang/constant/MethodTypeDesc; flags 1 +method name resolveConstantDesc descriptor (Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/invoke/MethodHandle; thrownTypes java/lang/ReflectiveOperationException flags 1 +method name toString descriptor ()Ljava/lang/String; flags 1 +method name resolveConstantDesc descriptor (Ljava/lang/invoke/MethodHandles$Lookup;)Ljava/lang/Object; thrownTypes java/lang/ReflectiveOperationException flags 1041 methodParameters 1000:null + +class name jdk/internal/constant/PrimitiveClassDescImpl +header extends java/lang/constant/DynamicConstantDesc implements java/lang/constant/ClassDesc flags 31 signature Ljava/lang/constant/DynamicConstantDesc;>;Ljava/lang/constant/ClassDesc; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +innerclass innerClass java/lang/invoke/TypeDescriptor$OfField outerClass java/lang/invoke/TypeDescriptor innerClassName OfField flags 609 + +class name jdk/internal/lang/LazyConstantImpl +header extends java/lang/Object implements java/lang/LazyConstant flags 31 signature Ljava/lang/Object;Ljava/lang/LazyConstant; runtimeAnnotations @Ljdk/internal/vm/annotation/AOTSafeClassInitializer; +method name get descriptor ()Ljava/lang/Object; flags 1 signature ()TT; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name orElse descriptor (Ljava/lang/Object;)Ljava/lang/Object; flags 1 signature (TT;)TT; runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name isInitialized descriptor ()Z flags 1 runtimeAnnotations @Ljdk/internal/vm/annotation/ForceInline; +method name toString descriptor ()Ljava/lang/String; flags 1 +method name ofLazy descriptor (Ljava/util/function/Supplier;)Ljdk/internal/lang/LazyConstantImpl; flags 9 signature (Ljava/util/function/Supplier<+TT;>;)Ljdk/internal/lang/LazyConstantImpl; + +-class name jdk/internal/lang/stable/StableValueImpl + +class name jdk/internal/vm/vector/VectorSupport +-method name loadWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector; +-method name storeWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;Ljava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V +method name loadWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$VectorSpecies;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)Ljdk/internal/vm/vector/VectorSupport$Vector; flags 9 signature ;W:Ljdk/internal/vm/vector/VectorSupport$Vector;S:Ljdk/internal/vm/vector/VectorSupport$VectorSpecies;M:Ljdk/internal/vm/vector/VectorSupport$VectorMask;E:Ljava/lang/Object;>(Ljava/lang/Class<+TV;>;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class<+Ljdk/internal/vm/vector/VectorSupport$Vector;>;ILjava/lang/Object;JTW;TW;TW;TW;TM;TC;I[IITS;Ljdk/internal/vm/vector/VectorSupport$LoadVectorOperationWithMap;)TV; runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; +method name storeWithMap descriptor (Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class;ILjava/lang/Object;JLjdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$Vector;Ljdk/internal/vm/vector/VectorSupport$VectorMask;Ljava/lang/Object;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V flags 9 signature ;W:Ljdk/internal/vm/vector/VectorSupport$Vector;M:Ljdk/internal/vm/vector/VectorSupport$VectorMask;E:Ljava/lang/Object;>(Ljava/lang/Class<+TV;>;Ljava/lang/Class;Ljava/lang/Class;ILjava/lang/Class<+Ljdk/internal/vm/vector/VectorSupport$Vector;>;ILjava/lang/Object;JTW;TV;TM;TC;I[IILjdk/internal/vm/vector/VectorSupport$StoreVectorOperationWithMap;)V runtimeAnnotations @Ljdk/internal/vm/annotation/IntrinsicCandidate; + +class name sun/nio/Cleaner +header extends java/lang/Object flags 601 +method name clean descriptor ()V flags 401 + +class name sun/nio/ch/DirectBuffer +-method name cleaner descriptor ()Ljdk/internal/ref/Cleaner; +method name cleaner descriptor ()Lsun/nio/Cleaner; flags 401 + diff --git a/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt new file mode 100644 index 00000000000..cb6ad893ace --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.compiler-Q.sym.txt @@ -0,0 +1,85 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name javax/lang/model/SourceVersion +field name RELEASE_26 descriptor Ljavax/lang/model/SourceVersion; flags 4019 + +class name javax/lang/model/util/AbstractAnnotationValueVisitor14 +header extends javax/lang/model/util/AbstractAnnotationValueVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractAnnotationValueVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractAnnotationValueVisitorPreview +header extends javax/lang/model/util/AbstractAnnotationValueVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractAnnotationValueVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractElementVisitor14 +header extends javax/lang/model/util/AbstractElementVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractElementVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractElementVisitorPreview +header extends javax/lang/model/util/AbstractElementVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractElementVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractTypeVisitor14 +header extends javax/lang/model/util/AbstractTypeVisitor9 flags 421 signature Ljavax/lang/model/util/AbstractTypeVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/AbstractTypeVisitorPreview +header extends javax/lang/model/util/AbstractTypeVisitor14 flags 421 signature Ljavax/lang/model/util/AbstractTypeVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementKindVisitor14 +header extends javax/lang/model/util/ElementKindVisitor9 flags 21 signature Ljavax/lang/model/util/ElementKindVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementKindVisitorPreview +header extends javax/lang/model/util/ElementKindVisitor14 flags 21 signature Ljavax/lang/model/util/ElementKindVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementScanner14 +header extends javax/lang/model/util/ElementScanner9 flags 21 signature Ljavax/lang/model/util/ElementScanner9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/ElementScannerPreview +header extends javax/lang/model/util/ElementScanner14 flags 21 signature Ljavax/lang/model/util/ElementScanner14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleAnnotationValueVisitor14 +header extends javax/lang/model/util/SimpleAnnotationValueVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleAnnotationValueVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleAnnotationValueVisitorPreview +header extends javax/lang/model/util/SimpleAnnotationValueVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleAnnotationValueVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleElementVisitor14 +header extends javax/lang/model/util/SimpleElementVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleElementVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleElementVisitorPreview +header extends javax/lang/model/util/SimpleElementVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleElementVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleTypeVisitor14 +header extends javax/lang/model/util/SimpleTypeVisitor9 flags 21 signature Ljavax/lang/model/util/SimpleTypeVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/SimpleTypeVisitorPreview +header extends javax/lang/model/util/SimpleTypeVisitor14 flags 21 signature Ljavax/lang/model/util/SimpleTypeVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/TypeKindVisitor14 +header extends javax/lang/model/util/TypeKindVisitor9 flags 21 signature Ljavax/lang/model/util/TypeKindVisitor9; runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + +class name javax/lang/model/util/TypeKindVisitorPreview +header extends javax/lang/model/util/TypeKindVisitor14 flags 21 signature Ljavax/lang/model/util/TypeKindVisitor14; classAnnotations @Ljdk/internal/javac/PreviewFeature;(feature=eLjdk/internal/javac/PreviewFeature$Feature;LANGUAGE_MODEL;,reflective=Ztrue) runtimeAnnotations @Ljavax/annotation/processing/SupportedSourceVersion;(value=eLjavax/lang/model/SourceVersion;RELEASE_26;) + diff --git a/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt new file mode 100644 index 00000000000..f75ff5b3fac --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.desktop-Q.sym.txt @@ -0,0 +1,90 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name java.desktop +header exports java/awt,java/awt/color,java/awt/desktop,java/awt/dnd,java/awt/event,java/awt/font,java/awt/geom,java/awt/im,java/awt/im/spi,java/awt/image,java/awt/image/renderable,java/awt/print,java/beans,java/beans/beancontext,javax/accessibility,javax/imageio,javax/imageio/event,javax/imageio/metadata,javax/imageio/plugins/bmp,javax/imageio/plugins/jpeg,javax/imageio/plugins/tiff,javax/imageio/spi,javax/imageio/stream,javax/print,javax/print/attribute,javax/print/attribute/standard,javax/print/event,javax/sound,javax/sound/midi,javax/sound/midi/spi,javax/sound/sampled,javax/sound/sampled/spi,javax/swing,javax/swing/border,javax/swing/colorchooser,javax/swing/event,javax/swing/filechooser,javax/swing/plaf,javax/swing/plaf/basic,javax/swing/plaf/metal,javax/swing/plaf/multi,javax/swing/plaf/nimbus,javax/swing/plaf/synth,javax/swing/table,javax/swing/text,javax/swing/text/html,javax/swing/text/html/parser,javax/swing/text/rtf,javax/swing/tree,javax/swing/undo extraModulePackages sun/print requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.prefs\u0020;flags\u0020;0,name\u0020;java.datatransfer\u0020;flags\u0020;20,name\u0020;java.xml\u0020;flags\u0020;20 uses java/awt/im/spi/InputMethodDescriptor,javax/accessibility/AccessibilityProvider,javax/imageio/spi/ImageInputStreamSpi,javax/imageio/spi/ImageOutputStreamSpi,javax/imageio/spi/ImageReaderSpi,javax/imageio/spi/ImageTranscoderSpi,javax/imageio/spi/ImageWriterSpi,javax/print/PrintServiceLookup,javax/print/StreamPrintServiceFactory,javax/sound/midi/spi/MidiDeviceProvider,javax/sound/midi/spi/MidiFileReader,javax/sound/midi/spi/MidiFileWriter,javax/sound/midi/spi/SoundbankReader,javax/sound/sampled/spi/AudioFileReader,javax/sound/sampled/spi/AudioFileWriter,javax/sound/sampled/spi/FormatConversionProvider,javax/sound/sampled/spi/MixerProvider,sun/swing/InteropProvider provides interface\u0020;sun/datatransfer/DesktopDatatransferService\u0020;impls\u0020;sun/awt/datatransfer/DesktopDatatransferServiceImpl,interface\u0020;java/net/ContentHandlerFactory\u0020;impls\u0020;sun/awt/www/content/MultimediaContentHandlers,interface\u0020;javax/print/PrintServiceLookup\u0020;impls\u0020;sun/print/PrintServiceLookupProvider,interface\u0020;javax/print/StreamPrintServiceFactory\u0020;impls\u0020;sun/print/PSStreamPrinterFactory,interface\u0020;javax/sound/midi/spi/MidiDeviceProvider\u0020;impls\u0020;com/sun/media/sound/MidiInDeviceProvider\u005C;u002C;com/sun/media/sound/MidiOutDeviceProvider\u005C;u002C;com/sun/media/sound/RealTimeSequencerProvider\u005C;u002C;com/sun/media/sound/SoftProvider,interface\u0020;javax/sound/midi/spi/MidiFileReader\u0020;impls\u0020;com/sun/media/sound/StandardMidiFileReader,interface\u0020;javax/sound/midi/spi/MidiFileWriter\u0020;impls\u0020;com/sun/media/sound/StandardMidiFileWriter,interface\u0020;javax/sound/midi/spi/SoundbankReader\u0020;impls\u0020;com/sun/media/sound/AudioFileSoundbankReader\u005C;u002C;com/sun/media/sound/DLSSoundbankReader\u005C;u002C;com/sun/media/sound/JARSoundbankReader\u005C;u002C;com/sun/media/sound/SF2SoundbankReader,interface\u0020;javax/sound/sampled/spi/AudioFileReader\u0020;impls\u0020;com/sun/media/sound/AiffFileReader\u005C;u002C;com/sun/media/sound/AuFileReader\u005C;u002C;com/sun/media/sound/SoftMidiAudioFileReader\u005C;u002C;com/sun/media/sound/WaveFileReader\u005C;u002C;com/sun/media/sound/WaveFloatFileReader\u005C;u002C;com/sun/media/sound/WaveExtensibleFileReader,interface\u0020;javax/sound/sampled/spi/AudioFileWriter\u0020;impls\u0020;com/sun/media/sound/AiffFileWriter\u005C;u002C;com/sun/media/sound/AuFileWriter\u005C;u002C;com/sun/media/sound/WaveFileWriter\u005C;u002C;com/sun/media/sound/WaveFloatFileWriter,interface\u0020;javax/sound/sampled/spi/FormatConversionProvider\u0020;impls\u0020;com/sun/media/sound/AlawCodec\u005C;u002C;com/sun/media/sound/AudioFloatFormatConverter\u005C;u002C;com/sun/media/sound/PCMtoPCMCodec\u005C;u002C;com/sun/media/sound/UlawCodec,interface\u0020;javax/sound/sampled/spi/MixerProvider\u0020;impls\u0020;com/sun/media/sound/DirectAudioDeviceProvider\u005C;u002C;com/sun/media/sound/PortMixerProvider target macos-aarch64 flags 8000 + +-class name java/applet/Applet + +-class name java/applet/Applet$AccessibleApplet + +-class name java/applet/AppletContext + +-class name java/applet/AppletStub + +-class name java/applet/AudioClip + +class name java/awt/Robot +field name DEFAULT_DELAY descriptor I constantValue 20 flags 19 +field name DEFAULT_STEP_LENGTH descriptor I constantValue 2 flags 19 +method name click descriptor (I)V flags 1 +method name click descriptor ()V flags 1 +method name waitForIdle descriptor (I)V flags 1 +method name glide descriptor (II)V flags 1 +method name glide descriptor (IIII)V flags 1 +method name glide descriptor (IIIIII)V flags 1 +method name type descriptor (I)V flags 21 +method name type descriptor (C)V flags 21 + +-class name java/beans/AppletInitializer + +class name java/beans/Beans +-method name instantiate descriptor (Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/beans/beancontext/BeanContext;Ljava/beans/AppletInitializer;)Ljava/lang/Object; + +class name javax/imageio/spi/ServiceRegistry +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileCacheImageInputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileImageInputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/FileImageOutputStream +-method name finalize descriptor ()V + +class name javax/imageio/stream/ImageInputStreamImpl +-method name finalize descriptor ()V + +class name javax/imageio/stream/MemoryCacheImageInputStream +-method name finalize descriptor ()V + +-class name javax/swing/JApplet + +-class name javax/swing/JApplet$AccessibleJApplet + +class name javax/swing/JTable +-method name setShowGrid descriptor (Z)V +method name setShowGrid descriptor (Z)V flags 1 runtimeAnnotations @Ljava/beans/BeanProperty;(description="Whether\u005C;u0020;grid\u005C;u0020;lines\u005C;u0020;are\u005C;u0020;drawn\u005C;u0020;around\u005C;u0020;the\u005C;u0020;cells.") + +class name javax/swing/RepaintManager +-method name addDirtyRegion descriptor (Ljava/applet/Applet;IIII)V + +class name javax/swing/plaf/synth/SynthPasswordFieldUI +-method name installKeyboardActions descriptor ()V + diff --git a/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt new file mode 100644 index 00000000000..03dacce810b --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.management-Q.sym.txt @@ -0,0 +1,37 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name java/lang/management/MemoryMXBean +method name getTotalGcCpuTime descriptor ()J flags 1 + +class name javax/management/modelmbean/DescriptorSupport +-method name descriptor (Ljava/lang/String;)V +-method name toXMLString descriptor ()Ljava/lang/String; + +-class name javax/management/modelmbean/XMLParseException + diff --git a/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt b/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt new file mode 100644 index 00000000000..bddf5c8d137 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/java.net.http-Q.sym.txt @@ -0,0 +1,125 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name java/net/http/HttpClient$Version +field name HTTP_3 descriptor Ljava/net/http/HttpClient$Version; flags 4019 + +class name java/net/http/HttpOption +header extends java/lang/Object nestMembers java/net/http/HttpOption$Http3DiscoveryMode sealed true permittedSubclasses java/net/http/HttpRequestOptionImpl flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +field name H3_DISCOVERY descriptor Ljava/net/http/HttpOption; flags 19 signature Ljava/net/http/HttpOption; +method name name descriptor ()Ljava/lang/String; flags 401 +method name type descriptor ()Ljava/lang/Class; flags 401 signature ()Ljava/lang/Class; + +class name java/net/http/HttpOption$Http3DiscoveryMode +header extends java/lang/Enum nestHost java/net/http/HttpOption flags 4031 signature Ljava/lang/Enum; +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +field name ANY descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +field name ALT_SVC descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +field name HTTP_3_URI_ONLY descriptor Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 4019 +method name values descriptor ()[Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljava/net/http/HttpOption$Http3DiscoveryMode; flags 9 methodParameters 8000:null + +class name java/net/http/HttpRequest +header extends java/lang/Object nestMembers java/net/http/HttpRequest$BodyPublishers,java/net/http/HttpRequest$BodyPublisher,java/net/http/HttpRequest$Builder flags 421 +innerclass innerClass java/net/http/HttpRequest$Builder outerClass java/net/http/HttpRequest innerClassName Builder flags 609 +innerclass innerClass java/net/http/HttpRequest$BodyPublishers outerClass java/net/http/HttpRequest innerClassName BodyPublishers flags 9 +innerclass innerClass java/net/http/HttpRequest$BodyPublisher outerClass java/net/http/HttpRequest innerClassName BodyPublisher flags 609 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +innerclass innerClass java/net/http/HttpOption$Http3DiscoveryMode outerClass java/net/http/HttpOption innerClassName Http3DiscoveryMode flags 4019 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name getOption descriptor (Ljava/net/http/HttpOption;)Ljava/util/Optional; flags 1 signature (Ljava/net/http/HttpOption;)Ljava/util/Optional; + +class name java/net/http/HttpRequest$BodyPublishers +method name ofFileChannel descriptor (Ljava/nio/channels/FileChannel;JJ)Ljava/net/http/HttpRequest$BodyPublisher; thrownTypes java/io/IOException flags 9 + +class name java/net/http/HttpRequest$Builder +method name setOption descriptor (Ljava/net/http/HttpOption;Ljava/lang/Object;)Ljava/net/http/HttpRequest$Builder; flags 1 signature (Ljava/net/http/HttpOption;TT;)Ljava/net/http/HttpRequest$Builder; + +class name java/net/http/HttpRequestOptionImpl +header extends java/lang/Record implements java/net/http/HttpOption record true flags 30 signature Ljava/lang/Record;Ljava/net/http/HttpOption; +recordcomponent name type descriptor Ljava/lang/Class; signature Ljava/lang/Class; +recordcomponent name name descriptor Ljava/lang/String; +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name toString descriptor ()Ljava/lang/String; flags 1 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name type descriptor ()Ljava/lang/Class; flags 1 signature ()Ljava/lang/Class; +method name name descriptor ()Ljava/lang/String; flags 1 + +class name java/net/http/HttpResponse +header extends java/lang/Object nestMembers java/net/http/HttpResponse$BodySubscribers,java/net/http/HttpResponse$BodySubscriber,java/net/http/HttpResponse$PushPromiseHandler,java/net/http/HttpResponse$PushPromiseHandler$PushId,java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId,java/net/http/HttpResponse$BodyHandlers,java/net/http/HttpResponse$BodyHandler,java/net/http/HttpResponse$ResponseInfo flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpResponse$BodySubscribers outerClass java/net/http/HttpResponse innerClassName BodySubscribers flags 9 +innerclass innerClass java/net/http/HttpResponse$BodySubscriber outerClass java/net/http/HttpResponse innerClassName BodySubscriber flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$BodyHandlers outerClass java/net/http/HttpResponse innerClassName BodyHandlers flags 9 +innerclass innerClass java/net/http/HttpResponse$BodyHandler outerClass java/net/http/HttpResponse innerClassName BodyHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$ResponseInfo outerClass java/net/http/HttpResponse innerClassName ResponseInfo flags 609 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 + +class name java/net/http/HttpResponse$PushPromiseHandler +header extends java/lang/Object nestHost java/net/http/HttpResponse flags 601 signature Ljava/lang/Object; +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$BodyHandler outerClass java/net/http/HttpResponse innerClassName BodyHandler flags 609 +method name applyPushPromise descriptor (Ljava/net/http/HttpRequest;Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;Ljava/util/function/Function;)V flags 1 signature (Ljava/net/http/HttpRequest;Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;Ljava/util/function/Function;Ljava/util/concurrent/CompletableFuture;>;>;)V +method name notifyAdditionalPromise descriptor (Ljava/net/http/HttpRequest;Ljava/net/http/HttpResponse$PushPromiseHandler$PushId;)V flags 1 + +class name java/net/http/HttpResponse$PushPromiseHandler$PushId +header extends java/lang/Object nestHost java/net/http/HttpResponse sealed true permittedSubclasses java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId flags 601 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 + +class name java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId +header extends java/lang/Record implements java/net/http/HttpResponse$PushPromiseHandler$PushId nestHost java/net/http/HttpResponse record true flags 31 +recordcomponent name pushId descriptor J +recordcomponent name connectionLabel descriptor Ljava/lang/String; +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler outerClass java/net/http/HttpResponse innerClassName PushPromiseHandler flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId outerClass java/net/http/HttpResponse$PushPromiseHandler innerClassName PushId flags 609 +innerclass innerClass java/net/http/HttpResponse$PushPromiseHandler$PushId$Http3PushId outerClass java/net/http/HttpResponse$PushPromiseHandler$PushId innerClassName Http3PushId flags 19 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name descriptor (JLjava/lang/String;)V flags 1 methodParameters 0:pushId,0:connectionLabel +method name toString descriptor ()Ljava/lang/String; flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name pushId descriptor ()J flags 1 +method name connectionLabel descriptor ()Ljava/lang/String; flags 1 + +class name java/net/http/StreamLimitException +header extends java/io/IOException flags 31 +innerclass innerClass java/net/http/HttpClient$Version outerClass java/net/http/HttpClient innerClassName Version flags 4019 +method name descriptor (Ljava/net/http/HttpClient$Version;Ljava/lang/String;)V flags 1 +method name version descriptor ()Ljava/net/http/HttpClient$Version; flags 11 + +class name java/net/http/UnsupportedProtocolVersionException +header extends java/io/IOException flags 31 +method name descriptor (Ljava/lang/String;)V flags 1 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt new file mode 100644 index 00000000000..70cc330edca --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.httpserver-Q.sym.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name com/sun/net/httpserver/HttpExchange +field name RSPBODY_EMPTY descriptor J constantValue -1 flags 19 +field name RSPBODY_CHUNKED descriptor J constantValue 0 flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt new file mode 100644 index 00000000000..223be24ab56 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-Q.sym.txt @@ -0,0 +1,32 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +class name jdk/incubator/vector/VectorOperators +-field name SUADD descriptor Ljdk/incubator/vector/VectorOperators$Binary; +field name SUADD descriptor Ljdk/incubator/vector/VectorOperators$Associative; flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt new file mode 100644 index 00000000000..47838de0844 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jartool-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jartool +header exports jdk/security/jarsigner requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;jdk.internal.opt\u0020;flags\u0020;0 provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;sun/tools/jar/JarToolProvider target macos-aarch64 moduleMainClass sun/tools/jar/Main flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt new file mode 100644 index 00000000000..e5d0bb627e5 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jdeps-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jdeps +header requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.compiler\u0020;flags\u0020;0,name\u0020;jdk.compiler\u0020;flags\u0020;0,name\u0020;jdk.internal.opt\u0020;flags\u0020;0 uses com/sun/tools/javac/platform/PlatformProvider provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;com/sun/tools/javap/Main$JavapToolProvider\u005C;u002C;com/sun/tools/jdeps/Main$JDepsToolProvider\u005C;u002C;com/sun/tools/jnativescan/Main$Provider target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt new file mode 100644 index 00000000000..2e3c13ea64c --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jfr-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jfr +header exports jdk/jfr,jdk/jfr/consumer requires name\u0020;java.base\u0020;flags\u0020;8000 target macos-aarch64 moduleMainClass jdk/jfr/internal/tool/Main flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt new file mode 100644 index 00000000000..e3e9eadf355 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jlink-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jlink +header requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;jdk.internal.opt\u0020;flags\u0020;0,name\u0020;jdk.jdeps\u0020;flags\u0020;0 uses jdk/tools/jlink/plugin/Plugin provides interface\u0020;java/util/spi/ToolProvider\u0020;impls\u0020;jdk/tools/jmod/Main$JmodToolProvider\u005C;u002C;jdk/tools/jlink/internal/Main$JlinkToolProvider,interface\u0020;jdk/tools/jlink/plugin/Plugin\u0020;impls\u0020;jdk/tools/jlink/internal/plugins/DefaultStripDebugPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/StripJavaDebugAttributesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludePlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeFilesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeJmodSectionPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/LegalNoticeFilePlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/SystemModulesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/StripNativeCommandsPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/OrderResourcesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/DefaultCompressPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ExcludeVMPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/GenerateJLIClassesPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/AddOptionsPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorBugURLPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorVMBugURLPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/VendorVersionPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/CDSPlugin\u005C;u002C;jdk/tools/jlink/internal/plugins/SaveJlinkArgfilesPlugin target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt new file mode 100644 index 00000000000..1dff60fc776 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jshell-Q.sym.txt @@ -0,0 +1,169 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.jshell +header exports jdk/jshell,jdk/jshell/execution,jdk/jshell/spi,jdk/jshell/tool requires name\u0020;java.base\u0020;flags\u0020;8000,name\u0020;java.logging\u0020;flags\u0020;0,name\u0020;jdk.compiler\u0020;flags\u0020;0,name\u0020;jdk.internal.ed\u0020;flags\u0020;0,name\u0020;jdk.internal.le\u0020;flags\u0020;0,name\u0020;jdk.internal.md\u0020;flags\u0020;0,name\u0020;jdk.internal.opt\u0020;flags\u0020;0,name\u0020;java.compiler\u0020;flags\u0020;20,name\u0020;java.prefs\u0020;flags\u0020;20,name\u0020;jdk.jdi\u0020;flags\u0020;20 uses jdk/jshell/spi/ExecutionControlProvider,jdk/internal/editor/spi/BuildInEditorProvider provides interface\u0020;javax/tools/Tool\u0020;impls\u0020;jdk/internal/jshell/tool/JShellToolProvider,interface\u0020;jdk/jshell/spi/ExecutionControlProvider\u0020;impls\u0020;jdk/jshell/execution/JdiExecutionControlProvider\u005C;u002C;jdk/jshell/execution/LocalExecutionControlProvider\u005C;u002C;jdk/jshell/execution/FailOverExecutionControlProvider,interface\u0020;jdk/internal/io/JdkConsoleProvider\u0020;impls\u0020;jdk/jshell/execution/impl/ConsoleImpl$ConsoleProviderImpl target macos-aarch64 moduleMainClass jdk/internal/jshell/tool/JShellToolProvider flags 8000 + +class name jdk/jshell/SourceCodeAnalysis +header extends java/lang/Object nestMembers jdk/jshell/SourceCodeAnalysis$Attribute,jdk/jshell/SourceCodeAnalysis$Highlight,jdk/jshell/SourceCodeAnalysis$SnippetWrapper,jdk/jshell/SourceCodeAnalysis$QualifiedNames,jdk/jshell/SourceCodeAnalysis$Documentation,jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor,jdk/jshell/SourceCodeAnalysis$CompletionContext,jdk/jshell/SourceCodeAnalysis$CompletionState,jdk/jshell/SourceCodeAnalysis$ElementSuggestion,jdk/jshell/SourceCodeAnalysis$Suggestion,jdk/jshell/SourceCodeAnalysis$Completeness,jdk/jshell/SourceCodeAnalysis$CompletionInfo flags 421 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Attribute outerClass jdk/jshell/SourceCodeAnalysis innerClassName Attribute flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Highlight outerClass jdk/jshell/SourceCodeAnalysis innerClassName Highlight flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$SnippetWrapper outerClass jdk/jshell/SourceCodeAnalysis innerClassName SnippetWrapper flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$QualifiedNames outerClass jdk/jshell/SourceCodeAnalysis innerClassName QualifiedNames flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Documentation outerClass jdk/jshell/SourceCodeAnalysis innerClassName Documentation flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Suggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName Suggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Completeness outerClass jdk/jshell/SourceCodeAnalysis innerClassName Completeness flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionInfo outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionInfo flags 609 +method name completionSuggestions descriptor (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; flags 401 signature (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; + +class name jdk/jshell/SourceCodeAnalysis$CompletionContext +header extends java/lang/Enum nestHost jdk/jshell/SourceCodeAnalysis flags 4031 signature Ljava/lang/Enum; +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +field name ANNOTATION_ATTRIBUTE descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name NO_PAREN descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name TYPES_AS_ANNOTATIONS descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +field name QUALIFIED descriptor Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 4019 +method name values descriptor ()[Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 9 +method name valueOf descriptor (Ljava/lang/String;)Ljdk/jshell/SourceCodeAnalysis$CompletionContext; flags 9 methodParameters 8000:null + +class name jdk/jshell/SourceCodeAnalysis$CompletionState +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis sealed true permittedSubclasses jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl flags 601 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +method name availableUsingSimpleName descriptor (Ljavax/lang/model/element/Element;)Z flags 401 +method name completionContext descriptor ()Ljava/util/Set; flags 401 signature ()Ljava/util/Set; +method name selectorType descriptor ()Ljavax/lang/model/type/TypeMirror; flags 401 +method name elementUtils descriptor ()Ljavax/lang/model/util/Elements; flags 401 +method name typeUtils descriptor ()Ljavax/lang/model/util/Types; flags 401 + +class name jdk/jshell/SourceCodeAnalysis$Documentation +method name activeParameterIndex descriptor ()I flags 1 + +class name jdk/jshell/SourceCodeAnalysis$ElementSuggestion +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis sealed true permittedSubclasses jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl flags 601 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +method name element descriptor ()Ljavax/lang/model/element/Element; flags 401 +method name keyword descriptor ()Ljava/lang/String; flags 401 +method name matchesType descriptor ()Z flags 401 +method name anchor descriptor ()I flags 401 +method name documentation descriptor ()Ljava/util/function/Supplier; flags 401 signature ()Ljava/util/function/Supplier; + +class name jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor +header extends java/lang/Object nestHost jdk/jshell/SourceCodeAnalysis flags 601 signature Ljava/lang/Object; +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +method name convert descriptor (Ljdk/jshell/SourceCodeAnalysis$CompletionState;Ljava/util/List;)Ljava/util/List; flags 401 signature (Ljdk/jshell/SourceCodeAnalysis$CompletionState;Ljava/util/List<+Ljdk/jshell/SourceCodeAnalysis$ElementSuggestion;>;)Ljava/util/List; + +class name jdk/jshell/SourceCodeAnalysisImpl +header extends jdk/jshell/SourceCodeAnalysis nestMembers jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl,jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl flags 20 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Completeness outerClass jdk/jshell/SourceCodeAnalysis innerClassName Completeness flags 4019 +innerclass innerClass com/sun/source/tree/Tree$Kind outerClass com/sun/source/tree/Tree innerClassName Kind flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestionConvertor flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$QualifiedNames outerClass jdk/jshell/SourceCodeAnalysis innerClassName QualifiedNames flags 19 +innerclass innerClass javax/tools/JavaFileManager$Location outerClass javax/tools/JavaFileManager innerClassName Location flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionInfo outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionInfo flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Documentation outerClass jdk/jshell/SourceCodeAnalysis innerClassName Documentation flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Highlight outerClass jdk/jshell/SourceCodeAnalysis innerClassName Highlight flags 19 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Attribute outerClass jdk/jshell/SourceCodeAnalysis innerClassName Attribute flags 4019 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass java/lang/Thread$UncaughtExceptionHandler outerClass java/lang/Thread innerClassName UncaughtExceptionHandler flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$Suggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName Suggestion flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$SnippetWrapper outerClass jdk/jshell/SourceCodeAnalysis innerClassName SnippetWrapper flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name analyzeCompletion descriptor (Ljava/lang/String;)Ljdk/jshell/SourceCodeAnalysis$CompletionInfo; flags 1 +method name completionSuggestions descriptor (Ljava/lang/String;I[I)Ljava/util/List; flags 1 signature (Ljava/lang/String;I[I)Ljava/util/List; +method name completionSuggestions descriptor (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; flags 1 signature (Ljava/lang/String;ILjdk/jshell/SourceCodeAnalysis$ElementSuggestionConvertor;)Ljava/util/List; +method name wrapper descriptor (Ljdk/jshell/Snippet;)Ljdk/jshell/SourceCodeAnalysis$SnippetWrapper; flags 1 +method name wrappers descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name sourceToSnippets descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name dependents descriptor (Ljdk/jshell/Snippet;)Ljava/util/Collection; flags 1 signature (Ljdk/jshell/Snippet;)Ljava/util/Collection; +method name highlights descriptor (Ljava/lang/String;)Ljava/util/List; flags 1 signature (Ljava/lang/String;)Ljava/util/List; +method name documentation descriptor (Ljava/lang/String;IZ)Ljava/util/List; flags 1 signature (Ljava/lang/String;IZ)Ljava/util/List; +method name close descriptor ()V flags 1 +method name analyzeType descriptor (Ljava/lang/String;I)Ljava/lang/String; flags 1 +method name listQualifiedNames descriptor (Ljava/lang/String;I)Ljdk/jshell/SourceCodeAnalysis$QualifiedNames; flags 1 +method name suspendIndexing descriptor ()V flags 1 +method name resumeIndexing descriptor ()V flags 1 +method name waitBackgroundTaskFinished descriptor ()V thrownTypes java/lang/Exception flags 1 +method name waitCurrentBackgroundTasksFinished descriptor ()V thrownTypes java/lang/Exception flags 9 + +class name jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl +header extends java/lang/Object implements jdk/jshell/SourceCodeAnalysis$CompletionState nestHost jdk/jshell/SourceCodeAnalysisImpl flags 30 +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$CompletionStateImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName CompletionStateImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionState outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionState flags 609 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$CompletionContext outerClass jdk/jshell/SourceCodeAnalysis innerClassName CompletionContext flags 4019 +method name descriptor (Ljava/util/Collection;Ljava/util/Set;Ljavax/lang/model/type/TypeMirror;Ljavax/lang/model/util/Elements;Ljavax/lang/model/util/Types;)V flags 1 signature (Ljava/util/Collection<+Ljavax/lang/model/element/Element;>;Ljava/util/Set;Ljavax/lang/model/type/TypeMirror;Ljavax/lang/model/util/Elements;Ljavax/lang/model/util/Types;)V +method name availableUsingSimpleName descriptor (Ljavax/lang/model/element/Element;)Z flags 1 +method name completionContext descriptor ()Ljava/util/Set; flags 1 signature ()Ljava/util/Set; +method name selectorType descriptor ()Ljavax/lang/model/type/TypeMirror; flags 1 +method name elementUtils descriptor ()Ljavax/lang/model/util/Elements; flags 1 +method name typeUtils descriptor ()Ljavax/lang/model/util/Types; flags 1 + +class name jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl +header extends java/lang/Record implements jdk/jshell/SourceCodeAnalysis$ElementSuggestion nestHost jdk/jshell/SourceCodeAnalysisImpl record true flags 30 +recordcomponent name element descriptor Ljavax/lang/model/element/Element; +recordcomponent name keyword descriptor Ljava/lang/String; +recordcomponent name matchesType descriptor Z +recordcomponent name anchor descriptor I +recordcomponent name documentation descriptor Ljava/util/function/Supplier; signature Ljava/util/function/Supplier; +innerclass innerClass jdk/jshell/SourceCodeAnalysisImpl$ElementSuggestionImpl outerClass jdk/jshell/SourceCodeAnalysisImpl innerClassName ElementSuggestionImpl flags 18 +innerclass innerClass jdk/jshell/SourceCodeAnalysis$ElementSuggestion outerClass jdk/jshell/SourceCodeAnalysis innerClassName ElementSuggestion flags 609 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 +method name toString descriptor ()Ljava/lang/String; flags 11 +method name hashCode descriptor ()I flags 11 +method name equals descriptor (Ljava/lang/Object;)Z flags 11 +method name element descriptor ()Ljavax/lang/model/element/Element; flags 1 +method name keyword descriptor ()Ljava/lang/String; flags 1 +method name matchesType descriptor ()Z flags 1 +method name anchor descriptor ()I flags 1 +method name documentation descriptor ()Ljava/util/function/Supplier; flags 1 signature ()Ljava/util/function/Supplier; + +class name jdk/jshell/execution/LocalExecutionControl +header extends jdk/jshell/execution/DirectExecutionControl flags 21 +innerclass innerClass jdk/jshell/spi/ExecutionControl$ClassBytecodes outerClass jdk/jshell/spi/ExecutionControl innerClassName ClassBytecodes flags 19 +innerclass innerClass java/lang/classfile/ClassFile$Option outerClass java/lang/classfile/ClassFile innerClassName Option flags 609 +innerclass innerClass java/lang/classfile/ClassFile$ClassHierarchyResolverOption outerClass java/lang/classfile/ClassFile innerClassName ClassHierarchyResolverOption flags 609 +innerclass innerClass jdk/jshell/spi/ExecutionControl$StoppedException outerClass jdk/jshell/spi/ExecutionControl innerClassName StoppedException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$InternalException outerClass jdk/jshell/spi/ExecutionControl innerClassName InternalException flags 9 +innerclass innerClass java/lang/classfile/CodeBuilder$BlockCodeBuilder outerClass java/lang/classfile/CodeBuilder innerClassName BlockCodeBuilder flags 609 +innerclass innerClass jdk/jshell/spi/ExecutionControl$ClassInstallException outerClass jdk/jshell/spi/ExecutionControl innerClassName ClassInstallException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$NotImplementedException outerClass jdk/jshell/spi/ExecutionControl innerClassName NotImplementedException flags 9 +innerclass innerClass jdk/jshell/spi/ExecutionControl$EngineTerminationException outerClass jdk/jshell/spi/ExecutionControl innerClassName EngineTerminationException flags 9 +innerclass innerClass java/lang/invoke/MethodHandles$Lookup outerClass java/lang/invoke/MethodHandles innerClassName Lookup flags 19 + diff --git a/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt new file mode 100644 index 00000000000..c8b83f6800b --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.jsobject-Q.sym.txt @@ -0,0 +1,34 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +-module name jdk.jsobject + +-class name netscape/javascript/JSException + +-class name netscape/javascript/JSObject + diff --git a/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt new file mode 100644 index 00000000000..71d9c3fea14 --- /dev/null +++ b/src/jdk.compiler/share/data/symbols/jdk.localedata-Q.sym.txt @@ -0,0 +1,31 @@ +# +# Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# +# ########################################################## +# ### THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. ### +# ########################################################## +# +module name jdk.localedata +header requires name\u0020;java.base\u0020;flags\u0020;8000 provides interface\u0020;sun/util/locale/provider/LocaleDataMetaInfo\u0020;impls\u0020;sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo\u005C;u002C;sun/util/resources/provider/NonBaseLocaleDataMetaInfo,interface\u0020;sun/util/resources/LocaleData$LocaleDataResourceBundleProvider\u0020;impls\u0020;sun/util/resources/provider/LocaleDataProvider target macos-aarch64 flags 8000 + diff --git a/src/jdk.compiler/share/data/symbols/symbols b/src/jdk.compiler/share/data/symbols/symbols index 34619bed887..4bc5127310f 100644 --- a/src/jdk.compiler/share/data/symbols/symbols +++ b/src/jdk.compiler/share/data/symbols/symbols @@ -29,7 +29,7 @@ #command used to generate this file: #build.tools.symbolgenerator.CreateSymbols build-description-incremental symbols include.list # -generate platforms 8:9:A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P +generate platforms 8:9:A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q platform version 8 files java.activation-8.sym.txt:java.base-8.sym.txt:java.compiler-8.sym.txt:java.corba-8.sym.txt:java.datatransfer-8.sym.txt:java.desktop-8.sym.txt:java.instrument-8.sym.txt:java.logging-8.sym.txt:java.management-8.sym.txt:java.management.rmi-8.sym.txt:java.naming-8.sym.txt:java.prefs-8.sym.txt:java.rmi-8.sym.txt:java.scripting-8.sym.txt:java.security.jgss-8.sym.txt:java.security.sasl-8.sym.txt:java.sql-8.sym.txt:java.sql.rowset-8.sym.txt:java.transaction-8.sym.txt:java.xml-8.sym.txt:java.xml.bind-8.sym.txt:java.xml.crypto-8.sym.txt:java.xml.ws-8.sym.txt:java.xml.ws.annotation-8.sym.txt:jdk.httpserver-8.sym.txt:jdk.management-8.sym.txt:jdk.net-8.sym.txt:jdk.scripting.nashorn-8.sym.txt:jdk.sctp-8.sym.txt:jdk.security.auth-8.sym.txt:jdk.security.jgss-8.sym.txt platform version 9 base 8 files java.activation-9.sym.txt:java.base-9.sym.txt:java.compiler-9.sym.txt:java.corba-9.sym.txt:java.datatransfer-9.sym.txt:java.desktop-9.sym.txt:java.instrument-9.sym.txt:java.logging-9.sym.txt:java.management-9.sym.txt:java.management.rmi-9.sym.txt:java.naming-9.sym.txt:java.prefs-9.sym.txt:java.rmi-9.sym.txt:java.scripting-9.sym.txt:java.se-9.sym.txt:java.se.ee-9.sym.txt:java.security.jgss-9.sym.txt:java.security.sasl-9.sym.txt:java.smartcardio-9.sym.txt:java.sql-9.sym.txt:java.sql.rowset-9.sym.txt:java.transaction-9.sym.txt:java.xml-9.sym.txt:java.xml.bind-9.sym.txt:java.xml.crypto-9.sym.txt:java.xml.ws-9.sym.txt:java.xml.ws.annotation-9.sym.txt:jdk.accessibility-9.sym.txt:jdk.attach-9.sym.txt:jdk.charsets-9.sym.txt:jdk.compiler-9.sym.txt:jdk.crypto.cryptoki-9.sym.txt:jdk.crypto.ec-9.sym.txt:jdk.dynalink-9.sym.txt:jdk.editpad-9.sym.txt:jdk.hotspot.agent-9.sym.txt:jdk.httpserver-9.sym.txt:jdk.incubator.httpclient-9.sym.txt:jdk.jartool-9.sym.txt:jdk.javadoc-9.sym.txt:jdk.jcmd-9.sym.txt:jdk.jconsole-9.sym.txt:jdk.jdeps-9.sym.txt:jdk.jdi-9.sym.txt:jdk.jdwp.agent-9.sym.txt:jdk.jlink-9.sym.txt:jdk.jshell-9.sym.txt:jdk.jsobject-9.sym.txt:jdk.jstatd-9.sym.txt:jdk.localedata-9.sym.txt:jdk.management-9.sym.txt:jdk.management.agent-9.sym.txt:jdk.naming.dns-9.sym.txt:jdk.naming.rmi-9.sym.txt:jdk.net-9.sym.txt:jdk.pack-9.sym.txt:jdk.policytool-9.sym.txt:jdk.rmic-9.sym.txt:jdk.scripting.nashorn-9.sym.txt:jdk.sctp-9.sym.txt:jdk.security.auth-9.sym.txt:jdk.security.jgss-9.sym.txt:jdk.unsupported-9.sym.txt:jdk.xml.dom-9.sym.txt:jdk.zipfs-9.sym.txt platform version A base 9 files java.activation-A.sym.txt:java.base-A.sym.txt:java.compiler-A.sym.txt:java.corba-A.sym.txt:java.datatransfer-A.sym.txt:java.desktop-A.sym.txt:java.instrument-A.sym.txt:java.logging-A.sym.txt:java.management-A.sym.txt:java.management.rmi-A.sym.txt:java.naming-A.sym.txt:java.prefs-A.sym.txt:java.rmi-A.sym.txt:java.scripting-A.sym.txt:java.se-A.sym.txt:java.se.ee-A.sym.txt:java.security.jgss-A.sym.txt:java.security.sasl-A.sym.txt:java.smartcardio-A.sym.txt:java.sql-A.sym.txt:java.sql.rowset-A.sym.txt:java.transaction-A.sym.txt:java.xml-A.sym.txt:java.xml.bind-A.sym.txt:java.xml.crypto-A.sym.txt:java.xml.ws-A.sym.txt:java.xml.ws.annotation-A.sym.txt:jdk.accessibility-A.sym.txt:jdk.attach-A.sym.txt:jdk.charsets-A.sym.txt:jdk.compiler-A.sym.txt:jdk.crypto.cryptoki-A.sym.txt:jdk.crypto.ec-A.sym.txt:jdk.dynalink-A.sym.txt:jdk.editpad-A.sym.txt:jdk.hotspot.agent-A.sym.txt:jdk.httpserver-A.sym.txt:jdk.incubator.httpclient-A.sym.txt:jdk.jartool-A.sym.txt:jdk.javadoc-A.sym.txt:jdk.jcmd-A.sym.txt:jdk.jconsole-A.sym.txt:jdk.jdeps-A.sym.txt:jdk.jdi-A.sym.txt:jdk.jdwp.agent-A.sym.txt:jdk.jlink-A.sym.txt:jdk.jshell-A.sym.txt:jdk.jsobject-A.sym.txt:jdk.jstatd-A.sym.txt:jdk.localedata-A.sym.txt:jdk.management-A.sym.txt:jdk.management.agent-A.sym.txt:jdk.naming.dns-A.sym.txt:jdk.naming.rmi-A.sym.txt:jdk.net-A.sym.txt:jdk.pack-A.sym.txt:jdk.policytool-A.sym.txt:jdk.rmic-A.sym.txt:jdk.scripting.nashorn-A.sym.txt:jdk.sctp-A.sym.txt:jdk.security.auth-A.sym.txt:jdk.security.jgss-A.sym.txt:jdk.unsupported-A.sym.txt:jdk.xml.dom-A.sym.txt:jdk.zipfs-A.sym.txt @@ -48,3 +48,4 @@ platform version M base L files java.base-M.sym.txt:java.compiler-M.sym.txt:java platform version N base M files java.base-N.sym.txt:java.compiler-N.sym.txt:java.desktop-N.sym.txt:java.management-N.sym.txt:java.management.rmi-N.sym.txt:jdk.compiler-N.sym.txt:jdk.httpserver-N.sym.txt:jdk.incubator.foreign-N.sym.txt:jdk.javadoc-N.sym.txt:jdk.jshell-N.sym.txt:jdk.localedata-N.sym.txt:jdk.unsupported-N.sym.txt platform version O base N files java.base-O.sym.txt:java.compiler-O.sym.txt:java.datatransfer-O.sym.txt:java.desktop-O.sym.txt:java.instrument-O.sym.txt:java.logging-O.sym.txt:java.management-O.sym.txt:java.management.rmi-O.sym.txt:java.naming-O.sym.txt:java.net.http-O.sym.txt:java.prefs-O.sym.txt:java.rmi-O.sym.txt:java.scripting-O.sym.txt:java.se-O.sym.txt:java.security.jgss-O.sym.txt:java.security.sasl-O.sym.txt:java.smartcardio-O.sym.txt:java.sql-O.sym.txt:java.sql.rowset-O.sym.txt:java.transaction.xa-O.sym.txt:java.xml-O.sym.txt:java.xml.crypto-O.sym.txt:jdk.accessibility-O.sym.txt:jdk.attach-O.sym.txt:jdk.charsets-O.sym.txt:jdk.compiler-O.sym.txt:jdk.crypto.cryptoki-O.sym.txt:jdk.dynalink-O.sym.txt:jdk.editpad-O.sym.txt:jdk.hotspot.agent-O.sym.txt:jdk.httpserver-O.sym.txt:jdk.incubator.foreign-O.sym.txt:jdk.incubator.vector-O.sym.txt:jdk.jartool-O.sym.txt:jdk.javadoc-O.sym.txt:jdk.jcmd-O.sym.txt:jdk.jconsole-O.sym.txt:jdk.jdeps-O.sym.txt:jdk.jdi-O.sym.txt:jdk.jdwp.agent-O.sym.txt:jdk.jfr-O.sym.txt:jdk.jlink-O.sym.txt:jdk.jpackage-O.sym.txt:jdk.jshell-O.sym.txt:jdk.jsobject-O.sym.txt:jdk.jstatd-O.sym.txt:jdk.localedata-O.sym.txt:jdk.management-O.sym.txt:jdk.management.agent-O.sym.txt:jdk.management.jfr-O.sym.txt:jdk.naming.dns-O.sym.txt:jdk.naming.rmi-O.sym.txt:jdk.net-O.sym.txt:jdk.nio.mapmode-O.sym.txt:jdk.sctp-O.sym.txt:jdk.security.auth-O.sym.txt:jdk.security.jgss-O.sym.txt:jdk.unsupported-O.sym.txt:jdk.xml.dom-O.sym.txt:jdk.zipfs-O.sym.txt platform version P base O files java.base-P.sym.txt:java.compiler-P.sym.txt:java.desktop-P.sym.txt:java.logging-P.sym.txt:java.management-P.sym.txt:java.net.http-P.sym.txt:java.security.jgss-P.sym.txt:java.xml.crypto-P.sym.txt:jdk.attach-P.sym.txt:jdk.compiler-P.sym.txt:jdk.incubator.foreign-P.sym.txt:jdk.incubator.vector-P.sym.txt:jdk.jdi-P.sym.txt:jdk.jfr-P.sym.txt:jdk.jpackage-P.sym.txt:jdk.jshell-P.sym.txt:jdk.net-P.sym.txt:jdk.security.jgss-P.sym.txt +platform version Q base P files java.base-Q.sym.txt:java.compiler-Q.sym.txt:java.desktop-Q.sym.txt:java.management-Q.sym.txt:java.net.http-Q.sym.txt:jdk.httpserver-Q.sym.txt:jdk.incubator.vector-Q.sym.txt:jdk.jartool-Q.sym.txt:jdk.jdeps-Q.sym.txt:jdk.jfr-Q.sym.txt:jdk.jlink-Q.sym.txt:jdk.jshell-Q.sym.txt:jdk.jsobject-Q.sym.txt:jdk.localedata-Q.sym.txt diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 72a248408ac..c838cbc56e6 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -817,3 +817,4 @@ java/awt/Cursor/CursorDragTest/ListDragCursor.java 7177297 macosx-all # jdk_since_checks tools/sincechecker/modules/jdk.management.jfr/JdkManagementJfrCheckSince.java 8354921 generic-all +tools/sincechecker/modules/java.base/JavaBaseCheckSince.java 8372801 generic-all diff --git a/test/langtools/tools/javac/api/TestGetSourceVersions.java b/test/langtools/tools/javac/api/TestGetSourceVersions.java index 4df60355aad..61147bc458d 100644 --- a/test/langtools/tools/javac/api/TestGetSourceVersions.java +++ b/test/langtools/tools/javac/api/TestGetSourceVersions.java @@ -24,7 +24,7 @@ /* * @test * @bug 6395981 6458819 7025784 8028543 8028544 8193291 8193292 8193292 8205393 8245585 8245585 8245585 8286034 - * 8296150 8306585 8319414 8330183 8342982 8355748 + * 8296150 8306585 8319414 8330183 8342982 8355748 8370893 * @summary JavaCompilerTool and Tool must specify version of JLS and JVMS * @author Peter von der Ahé * @modules java.compiler @@ -37,7 +37,7 @@ * RELEASE_8 RELEASE_9 RELEASE_10 RELEASE_11 RELEASE_12 * RELEASE_13 RELEASE_14 RELEASE_15 RELEASE_16 RELEASE_17 * RELEASE_18 RELEASE_19 RELEASE_20 RELEASE_21 RELEASE_22 - * RELEASE_23 RELEASE_24 RELEASE_25 RELEASE_26 + * RELEASE_23 RELEASE_24 RELEASE_25 RELEASE_26 RELEASE_27 */ import java.util.EnumSet; diff --git a/test/langtools/tools/javac/classfiles/ClassVersionChecker.java b/test/langtools/tools/javac/classfiles/ClassVersionChecker.java index 6afa7ad9e30..8cf30373e29 100644 --- a/test/langtools/tools/javac/classfiles/ClassVersionChecker.java +++ b/test/langtools/tools/javac/classfiles/ClassVersionChecker.java @@ -24,7 +24,7 @@ /* * @test * @bug 7157626 8001112 8188870 8173382 8193290 8205619 8245586 8257453 8306586 8330184 - * 8342983 8355751 + * 8342983 8355751 8370894 * @summary Test major version for all legal combinations for -source and -target * @author sgoel * @@ -62,6 +62,7 @@ public class ClassVersionChecker { TWENTY_FOUR("24", 68), TWENTY_FIVE("25", 69), TWENTY_SIX("26", 70), + TWENTY_SEVEN("27", 71), ; // Reduce code churn when appending new constants private Version(String release, int classFileVer) { diff --git a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java index e181ef8bf63..70a1e028839 100644 --- a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java +++ b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java @@ -113,7 +113,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { * corresponding platform visitor type. */ - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static abstract class AbstractAnnotationValueVisitor extends AbstractAnnotationValueVisitorPreview { @@ -125,7 +125,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static abstract class AbstractElementVisitor extends AbstractElementVisitorPreview { /** @@ -136,7 +136,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static abstract class AbstractTypeVisitor extends AbstractTypeVisitorPreview { /** @@ -147,7 +147,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class ElementKindVisitor extends ElementKindVisitorPreview { /** @@ -169,7 +169,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class ElementScanner extends ElementScannerPreview { /** @@ -189,7 +189,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class SimpleAnnotationValueVisitor extends SimpleAnnotationValueVisitorPreview { /** @@ -211,7 +211,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class SimpleElementVisitor extends SimpleElementVisitorPreview { /** @@ -233,7 +233,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class SimpleTypeVisitor extends SimpleTypeVisitorPreview { /** @@ -255,7 +255,7 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor { } } - @SupportedSourceVersion(RELEASE_26) + @SupportedSourceVersion(RELEASE_27) @SuppressWarnings("preview") public static class TypeKindVisitor extends TypeKindVisitorPreview { /** diff --git a/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out b/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out index 8c455009ae5..f46b53f80db 100644 --- a/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out +++ b/test/langtools/tools/javac/preview/classReaderTest/Client.nopreview.out @@ -1,2 +1,2 @@ -- compiler.err.preview.feature.disabled.classfile: Bar.class, 26 +- compiler.err.preview.feature.disabled.classfile: Bar.class, 27 1 error diff --git a/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out b/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out index 26ff05b085a..7ae297ee2fb 100644 --- a/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out +++ b/test/langtools/tools/javac/preview/classReaderTest/Client.preview.out @@ -1,4 +1,4 @@ -- compiler.warn.preview.feature.use.classfile: Bar.class, 26 +- compiler.warn.preview.feature.use.classfile: Bar.class, 27 - compiler.err.warnings.and.werror 1 error 1 warning diff --git a/test/langtools/tools/javac/versions/Versions.java b/test/langtools/tools/javac/versions/Versions.java index 43fcb0353d0..e83f7b8c308 100644 --- a/test/langtools/tools/javac/versions/Versions.java +++ b/test/langtools/tools/javac/versions/Versions.java @@ -26,7 +26,7 @@ * @bug 4981566 5028634 5094412 6304984 7025786 7025789 8001112 8028545 * 8000961 8030610 8028546 8188870 8173382 8173382 8193290 8205619 8028563 * 8245147 8245586 8257453 8286035 8306586 8320806 8306586 8319414 8330183 - * 8342982 8355748 8356108 + * 8342982 8355748 8356108 8370893 * @summary Check interpretation of -target and -source options * @modules java.compiler * jdk.compiler @@ -73,9 +73,9 @@ public class Versions { public static final Set VALID_SOURCES = Set.of("1.8", "1.9", "1.10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", - "23", "24", "25", "26"); + "23", "24", "25", "26", "27"); - public static final String LATEST_MAJOR_VERSION = "70.0"; + public static final String LATEST_MAJOR_VERSION = "71.0"; static enum SourceTarget { EIGHT(true, "52.0", "8"), @@ -97,6 +97,7 @@ public class Versions { TWENTY_FOUR(false,"68.0", "24"), TWENTY_FIVE(false,"69.0", "25"), TWENTY_SIX(false, "70.0", "26"), + TWENTY_SEVEN(false, "71.0", "27"), ; // Reduce code churn when appending new constants private final boolean dotOne; From c7aa10339aa40d37dc52e6dcec102f8dca114634 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 4 Dec 2025 18:34:51 +0000 Subject: [PATCH 066/141] 8372844: Improve usage of test/jdk/java/text/testlib/TestUtils.java locale methods Reviewed-by: naoto --- .../text/Format/DateFormat/Bug4407042.java | 27 ++-- .../text/Format/DateFormat/Bug4845901.java | 17 ++- .../text/Format/DateFormat/Bug6530336.java | 134 ++++++++---------- .../DateFormat/DateFormatRegression.java | 7 +- .../MessageFormat/MessageRegression.java | 9 +- .../Format/NumberFormat/NumberRegression.java | 7 +- .../java/util/Calendar/CalendarLimitTest.java | 9 +- .../util/Calendar/CalendarRegression.java | 52 +++---- test/jdk/java/util/Calendar/CalendarTest.java | 15 +- test/jdk/java/util/Calendar/bug4409072.java | 9 +- test/jdk/java/util/Locale/LocaleCategory.java | 18 +-- .../util/TimeZone/TimeZoneRegression.java | 13 +- 12 files changed, 136 insertions(+), 181 deletions(-) diff --git a/test/jdk/java/text/Format/DateFormat/Bug4407042.java b/test/jdk/java/text/Format/DateFormat/Bug4407042.java index 1960cb2b151..85825ff8b21 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug4407042.java +++ b/test/jdk/java/text/Format/DateFormat/Bug4407042.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,29 +27,31 @@ * @summary Make sure that cloned SimpleDateFormat objects work * independently in multiple threads. * @library /java/text/testlib - * @run main Bug4407042 10 + * @run junit Bug4407042 */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + import java.io.*; import java.text.*; import java.util.*; -// Usage: java Bug4407042 [duration] public class Bug4407042 { static final String TIME_STRING = "2000/11/18 00:01:00"; static final long UTC_LONG = 974534460000L; static SimpleDateFormat masterFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); static boolean runrun = true; - static int duration = 100; + static int duration = 10; + @Test void test() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale) - || !TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); masterFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles")); DateParseThread d1 = new DateParseThread(); @@ -124,11 +126,4 @@ public class Bug4407042 { } } } - - public static void main (String[] args) { - if (args.length == 1) { - duration = Math.max(10, Integer.parseInt(args[0])); - } - new Bug4407042().test(); - } } diff --git a/test/jdk/java/text/Format/DateFormat/Bug4845901.java b/test/jdk/java/text/Format/DateFormat/Bug4845901.java index 363a3518bf0..754197dbe0d 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug4845901.java +++ b/test/jdk/java/text/Format/DateFormat/Bug4845901.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,19 +28,22 @@ * the same time zone abbreviation for standard and daylight saving * time. * @library /java/text/testlib - * @run main Bug4845901 + * @run junit/othervm Bug4845901 */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + import java.util.*; import java.text.SimpleDateFormat; public class Bug4845901 { - public static void main (String args[]) { + + @Test + void test() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); TimeZone savedTZ = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone("Australia/Sydney")); diff --git a/test/jdk/java/text/Format/DateFormat/Bug6530336.java b/test/jdk/java/text/Format/DateFormat/Bug6530336.java index 552343cb1ba..880e8b3ae2b 100644 --- a/test/jdk/java/text/Format/DateFormat/Bug6530336.java +++ b/test/jdk/java/text/Format/DateFormat/Bug6530336.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,93 +25,73 @@ * @test * @bug 6530336 6537997 8008577 8174269 8333582 * @library /java/text/testlib - * @run main Bug6530336 + * @run junit/othervm Bug6530336 */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.FieldSource; + import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.Locale; import java.util.TimeZone; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class Bug6530336 { - public static void main(String[] args) throws Exception { - Locale defaultLocale = Locale.getDefault(); - TimeZone defaultTimeZone = TimeZone.getDefault(); + private static final Locale[] locales = Locale.getAvailableLocales(); + private static final TimeZone[] timezones = { + TimeZone.getTimeZone("America/New_York"), + TimeZone.getTimeZone("America/Denver"), + }; + private static final TimeZone timezone_LA = TimeZone.getTimeZone("America/Los_Angeles"); + private static final String[] expected = { + "Sun Jul 15 12:00:00 PDT 2007", + "Sun Jul 15 14:00:00 PDT 2007", + }; + private static final Date[] dates = new Date[2]; - boolean err = false; - - try { - Locale locales[] = Locale.getAvailableLocales(); - TimeZone timezone_LA = TimeZone.getTimeZone("America/Los_Angeles"); - TimeZone.setDefault(timezone_LA); - - TimeZone timezones[] = { - TimeZone.getTimeZone("America/New_York"), - TimeZone.getTimeZone("America/Denver"), - }; - - String[] expected = { - "Sun Jul 15 12:00:00 PDT 2007", - "Sun Jul 15 14:00:00 PDT 2007", - }; - - Date[] dates = new Date[2]; - - for (int i = 0; i < locales.length; i++) { - Locale locale = locales[i]; - if (!TestUtils.usesGregorianCalendar(locale)) { - continue; - } - - Locale.setDefault(locale); - - for (int j = 0; j < timezones.length; j++) { - Calendar cal = Calendar.getInstance(timezones[j]); - cal.set(2007, 6, 15, 15, 0, 0); - dates[j] = cal.getTime(); - } - - SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"); - - for (int j = 0; j < timezones.length; j++) { - sdf.setTimeZone(timezones[j]); - String date = sdf.format(dates[j]); - // CLDR localizes GMT format into for some locales. Ignore those cases - if (date.matches(".*GMT[\\s+-]\\D.*") || - date.contains("UTC") || - date.contains("TMG") || // Interlingue - date.contains("\u07dc\u07ed\u07d5\u07d6") || // N’Ko - date.contains("\ua2e7\ua0c5\ua395\ua3e6\ua12e\ua209") || // Sichuan Yi, Nuosu - date.contains("\u06af\u0631\u06cc\u0646\u06cc\u0686")) { // Central Kurdish - continue; - } - sdf.setTimeZone(timezone_LA); - String date_LA = sdf.parse(date).toString(); - - if (!expected[j].equals(date_LA)) { - System.err.println("Got wrong Pacific time (" + - date_LA + ") for (" + date + ") in " + locale + - " in " + timezones[j] + - ".\nExpected=" + expected[j]); - err = true; - } - } - } - } - catch (Exception e) { - e.printStackTrace(); - err = true; - } - finally { - Locale.setDefault(defaultLocale); - TimeZone.setDefault(defaultTimeZone); - - if (err) { - throw new RuntimeException("Failed."); - } - } + @BeforeAll + static void setup() { + TimeZone.setDefault(timezone_LA); } + @ParameterizedTest + @FieldSource("locales") + void test(Locale locale) { + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); + Locale.setDefault(locale); + + for (int j = 0; j < timezones.length; j++) { + Calendar cal = Calendar.getInstance(timezones[j]); + cal.set(2007, 6, 15, 15, 0, 0); + dates[j] = cal.getTime(); + } + + SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"); + + for (int j = 0; j < timezones.length; j++) { + sdf.setTimeZone(timezones[j]); + String date = sdf.format(dates[j]); + // CLDR localizes GMT format into for some locales. Ignore those cases + if (date.matches(".*GMT[\\s+-]\\D.*") || + date.contains("UTC") || + date.contains("TMG") || // Interlingue + date.contains("ߜ߭ߕߖ") || // N’Ko + date.contains("ꋧꃅꎕꏦꄮꈉ") || // Sichuan Yi, Nuosu + date.contains("گرینیچ")) { // Central Kurdish + continue; + } + sdf.setTimeZone(timezone_LA); + String date_LA = assertDoesNotThrow(() -> sdf.parse(date).toString()); + assertEquals(expected[j], date_LA, + "Got wrong Pacific time (%s) for (%s) in %s in %s.".formatted(date_LA, date, locale, timezones[j])); + } + } } diff --git a/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java b/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java index dbd12e66f60..2e3fed17ce5 100644 --- a/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java +++ b/test/jdk/java/text/Format/DateFormat/DateFormatRegression.java @@ -25,6 +25,7 @@ import java.text.*; import java.util.*; import java.io.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -170,10 +171,8 @@ public class DateFormatRegression { @Test public void Test4059917() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); SimpleDateFormat fmt; String myDate; diff --git a/test/jdk/java/text/Format/MessageFormat/MessageRegression.java b/test/jdk/java/text/Format/MessageFormat/MessageRegression.java index e10e4899202..31aa5189ba2 100644 --- a/test/jdk/java/text/Format/MessageFormat/MessageRegression.java +++ b/test/jdk/java/text/Format/MessageFormat/MessageRegression.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,7 @@ import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.Serializable; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -126,10 +127,8 @@ public class MessageRegression { @Test public void Test4031438() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); String pattern1 = "Impossible {1} has occurred -- status code is {0} and message is {2}."; String pattern2 = "Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'."; diff --git a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java index a0a096e6782..90f60151197 100644 --- a/test/jdk/java/text/Format/NumberFormat/NumberRegression.java +++ b/test/jdk/java/text/Format/NumberFormat/NumberRegression.java @@ -58,6 +58,7 @@ import java.math.BigDecimal; import java.io.*; import java.math.BigInteger; +import org.junit.jupiter.api.Assumptions; import sun.util.resources.LocaleData; import org.junit.jupiter.api.Test; @@ -109,10 +110,8 @@ public class NumberRegression { @Test public void Test4088161 (){ Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); DecimalFormat df = new DecimalFormat(); double d = 100; diff --git a/test/jdk/java/util/Calendar/CalendarLimitTest.java b/test/jdk/java/util/Calendar/CalendarLimitTest.java index e8a92f180ec..552aa5f9866 100644 --- a/test/jdk/java/util/Calendar/CalendarLimitTest.java +++ b/test/jdk/java/util/Calendar/CalendarLimitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, 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 @@ -32,6 +32,7 @@ import java.util.*; import java.text.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -130,10 +131,8 @@ public class CalendarLimitTest public void TestCalendarLimit() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); ORIGIN = julianDayToMillis(JAN_1_1_JULIAN_DAY); Calendar cal = Calendar.getInstance(); diff --git a/test/jdk/java/util/Calendar/CalendarRegression.java b/test/jdk/java/util/Calendar/CalendarRegression.java index 7b0f2025005..6e5148c0c20 100644 --- a/test/jdk/java/util/Calendar/CalendarRegression.java +++ b/test/jdk/java/util/Calendar/CalendarRegression.java @@ -55,6 +55,7 @@ import java.util.function.Predicate; import static java.util.Calendar.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -575,10 +576,8 @@ public class CalendarRegression { @Test public void Test4100311() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance(); cal.set(YEAR, 1997); @@ -593,10 +592,8 @@ public class CalendarRegression { @Test public void Test4103271() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); SimpleDateFormat sdf = new SimpleDateFormat(); int numYears = 40, startYear = 1997, numDays = 15; @@ -833,10 +830,8 @@ public class CalendarRegression { @Test public void Test4114578() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); int ONE_HOUR = 60 * 60 * 1000; TimeZone saveZone = TimeZone.getDefault(); @@ -921,10 +916,8 @@ public class CalendarRegression { @Test public void Test4125881() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance(); DateFormat fmt = new SimpleDateFormat("MMMM d, yyyy G"); @@ -947,10 +940,8 @@ public class CalendarRegression { @Test public void Test4125892() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance(); DateFormat fmt = new SimpleDateFormat("MMMM d, yyyy G"); @@ -1373,10 +1364,8 @@ public class CalendarRegression { @Test public void Test4173516() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); int[][] fieldsList = { {1997, FEBRUARY, 1, 10, 45, 15, 900}, @@ -1852,11 +1841,10 @@ public class CalendarRegression { @Test public void Test4685354() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesAsciiDigits(locale) - || !TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesAsciiDigits(locale), + locale + " does not use ASCII digits"); + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); Calendar calendar = Calendar.getInstance(Locale.US); DateFormat df = new SimpleDateFormat("yyyy/MM/dd", Locale.US); @@ -1961,10 +1949,8 @@ public class CalendarRegression { @Test public void Test4655637() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); Calendar cal = Calendar.getInstance(); cal.setTime(new Date(1029814211523L)); diff --git a/test/jdk/java/util/Calendar/CalendarTest.java b/test/jdk/java/util/Calendar/CalendarTest.java index 5092c6adec0..0b50b07179d 100644 --- a/test/jdk/java/util/Calendar/CalendarTest.java +++ b/test/jdk/java/util/Calendar/CalendarTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, 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 @@ -48,6 +48,7 @@ import java.util.TimeZone; import static java.util.Calendar.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -223,10 +224,8 @@ public class CalendarTest { @Test public void TestGenericAPI() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); String str; Date when = new Date(90, APRIL, 15); @@ -625,10 +624,8 @@ public class CalendarTest { @Test public void TestGMTvsLocal4064654() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); // Sample output 1: // % /usr/local/java/jdk1.1.3/solaris/bin/java test 1997 1 1 12 0 0 diff --git a/test/jdk/java/util/Calendar/bug4409072.java b/test/jdk/java/util/Calendar/bug4409072.java index 617550fe1aa..132934daa98 100644 --- a/test/jdk/java/util/Calendar/bug4409072.java +++ b/test/jdk/java/util/Calendar/bug4409072.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import java.util.*; import static java.util.Calendar.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -44,10 +45,8 @@ public class bug4409072 { @Test public void Test4409072() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); Locale savedLocale = Locale.getDefault(); TimeZone savedTZ = TimeZone.getDefault(); diff --git a/test/jdk/java/util/Locale/LocaleCategory.java b/test/jdk/java/util/Locale/LocaleCategory.java index ed63203916a..ec4277d43c0 100644 --- a/test/jdk/java/util/Locale/LocaleCategory.java +++ b/test/jdk/java/util/Locale/LocaleCategory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. * 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,14 +29,17 @@ * @library /java/text/testlib * @build TestUtils LocaleCategory * @comment test user.xxx.display user.xxx.format properties - * @run main/othervm -Duser.language.display=ja + * @run junit/othervm -Duser.language.display=ja * -Duser.language.format=zh LocaleCategory * @comment test user.xxx properties overriding user.xxx.display/format - * @run main/othervm -Duser.language=en + * @run junit/othervm -Duser.language=en * -Duser.language.display=ja * -Duser.language.format=zh LocaleCategory */ +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + import java.util.Locale; public class LocaleCategory { @@ -44,12 +47,11 @@ public class LocaleCategory { private static Locale disp = null; private static Locale fmt = null; - public static void main(String[] args) { + @Test + void test() { Locale reservedLocale = Locale.getDefault(); - if (TestUtils.hasSpecialVariant(reservedLocale)) { - System.out.println("Skipping this test because locale is " + reservedLocale); - return; - } + Assumptions.assumeFalse(TestUtils.hasSpecialVariant(reservedLocale), + reservedLocale + " has special variant"); try { Locale.Builder builder = new Locale.Builder(); diff --git a/test/jdk/java/util/TimeZone/TimeZoneRegression.java b/test/jdk/java/util/TimeZone/TimeZoneRegression.java index 241afd3f7cf..c1b1b98369e 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneRegression.java +++ b/test/jdk/java/util/TimeZone/TimeZoneRegression.java @@ -34,6 +34,7 @@ import java.util.*; import java.io.*; import java.text.*; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.fail; @@ -164,10 +165,8 @@ public class TimeZoneRegression { @Test public void Test4109314() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); // test both SimpleTimeZone and ZoneInfo objects. // @since 1.4 @@ -292,10 +291,8 @@ public class TimeZoneRegression { @Test public void Test4126678() { Locale locale = Locale.getDefault(); - if (!TestUtils.usesGregorianCalendar(locale)) { - System.out.println("Skipping this test because locale is " + locale); - return; - } + Assumptions.assumeTrue(TestUtils.usesGregorianCalendar(locale), + locale + " does not use a Gregorian calendar"); // Note: this test depends on the PST time zone. TimeZone initialZone = TimeZone.getDefault(); From b19163b107584118056073dc24a960ca04ca14e4 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Thu, 4 Dec 2025 18:38:57 +0000 Subject: [PATCH 067/141] 8356544: Implement additional tests for ciphersuites disabled with wildcards Reviewed-by: rhalade --- .../DisabledCipherSuitesNotNegotiated.java | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java diff --git a/test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java b/test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java new file mode 100644 index 00000000000..229ab03b568 --- /dev/null +++ b/test/jdk/sun/security/ssl/CipherSuite/DisabledCipherSuitesNotNegotiated.java @@ -0,0 +1,158 @@ +/* + * 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 8341964 + * @library /test/lib + * @run main/othervm DisabledCipherSuitesNotNegotiated client + * @run main/othervm DisabledCipherSuitesNotNegotiated server + */ + +import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import jdk.test.lib.security.SecurityUtils; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.SSLHandshakeException; + +public class DisabledCipherSuitesNotNegotiated { + private static final String TLS_PROTOCOL = "TLSv1.2"; + private static volatile int serverPort = 0; + private static volatile Exception serverException = null; + + private static final CountDownLatch waitForServer = new CountDownLatch(1); + private static final int WAIT_FOR_SERVER_SECS = 5; + + private static final String DISABLED_CIPHERSUITE = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; + private static final String DISABLED_CIPHER_WILDCARD = "TLS_ECDH*WITH_AES_256_GCM_*"; + + private static void runServer(boolean disabledInClient) throws Exception { + SSLContext ctx = SSLContext.getInstance(TLS_PROTOCOL); + ctx.init(null, null, null); + SSLServerSocketFactory factory = ctx.getServerSocketFactory(); + try(SSLServerSocket serverSocket = (SSLServerSocket)factory + .createServerSocket(0, -1, InetAddress.getLoopbackAddress())) { + serverPort = serverSocket.getLocalPort(); + waitForServer.countDown(); + + if (disabledInClient) { + // set cipher suite to disabled ciphersuite + serverSocket.setEnabledCipherSuites(new String[]{DISABLED_CIPHERSUITE}); + } + + try(SSLSocket clientSocket = (SSLSocket) serverSocket.accept()) { + try { + clientSocket.getInputStream().readAllBytes(); + throw new Exception("SERVER: The expected handshake exception was not thrown."); + } catch (SSLHandshakeException exc) { + System.out.println("Server caught expected SSLHandshakeException"); + exc.printStackTrace(System.out); + } + } + } + } + + private static void runClient(boolean disableInClient, int portNumber) throws Exception { + SSLContext ctx = SSLContext.getInstance(TLS_PROTOCOL); + ctx.init(null, null, null); + SSLSocketFactory factory = ctx.getSocketFactory(); + try(SSLSocket socket = (SSLSocket)factory.createSocket("localhost", portNumber)) { + if (!disableInClient) { + socket.setEnabledCipherSuites(new String[]{DISABLED_CIPHERSUITE}); + } + + try { + socket.getOutputStream().write("hello".getBytes(StandardCharsets.UTF_8)); + throw new Exception("CLIENT: The expected handshake exception was not thrown."); + } catch (SSLHandshakeException exc) { + System.out.println("Client caught expected SSLHandshakeException"); + } + } + } + + public static void main(String [] args) throws Exception { + if (args.length == 1) { + // run server-side + final boolean disabledInClient = args[0].equals("client"); + if (!disabledInClient) { + SecurityUtils.addToDisabledTlsAlgs(DISABLED_CIPHER_WILDCARD); + } + try(ExecutorService executorService = Executors.newSingleThreadExecutor()) { + executorService.submit(() -> { + try { + runServer(disabledInClient); + } catch (Exception exc) { + System.out.println("Server Exception:"); + exc.printStackTrace(System.out); + serverException = exc; + throw new RuntimeException(exc); + } + }); + + if (!waitForServer.await(WAIT_FOR_SERVER_SECS, TimeUnit.SECONDS)) { + throw new Exception("Server did not start within " + + WAIT_FOR_SERVER_SECS + " seconds."); + } + + System.out.printf("Server listening on port %d.%nStarting client process...", + serverPort); + + OutputAnalyzer oa = ProcessTools.executeProcess( + ProcessTools.createTestJavaProcessBuilder("DisabledCipherSuitesNotNegotiated", + "" + disabledInClient, "" + serverPort)); + oa.shouldHaveExitValue(0); + System.out.println("Client output:"); + System.out.println(oa.getOutput()); + if (serverException != null) { + throw new Exception ("Server-side threw an unexpected exception: " + + serverException); + } + } + + } else if (args.length == 2) { + // run client-side + boolean disabledInClient = Boolean.parseBoolean(args[0]); + if (disabledInClient) { + SecurityUtils.addToDisabledTlsAlgs(DISABLED_CIPHER_WILDCARD); + } + runClient(Boolean.parseBoolean(args[0]), Integer.parseInt(args[1])); + + } else { + throw new Exception( + "DisabledCipherSuitesNotNegotiated called with invalid arguments"); + } + } + +} From ef7532e7e625628d6181c65116804ebb65f18061 Mon Sep 17 00:00:00 2001 From: Mikhail Yankelevich Date: Thu, 4 Dec 2025 18:41:12 +0000 Subject: [PATCH 068/141] 8367994: test/jdk/sun/security/pkcs11/Signature/ tests pass when they should skip Reviewed-by: rhalade --- .../pkcs11/Signature/InitAgainPSS.java | 17 +++-- .../Signature/KeyAndParamCheckForPSS.java | 36 ++++++--- .../pkcs11/Signature/SigInteropPSS.java | 18 +++-- .../pkcs11/Signature/SigInteropPSS2.java | 19 +++-- .../pkcs11/Signature/SignatureTestPSS.java | 76 ++++++++++++++----- .../pkcs11/Signature/SignatureTestPSS2.java | 47 +++++++++--- .../security/pkcs11/Signature/TestDSA.java | 7 +- 7 files changed, 160 insertions(+), 60 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java b/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java index a2fa7294977..1acf6c250ef 100644 --- a/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/InitAgainPSS.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 @@ -20,8 +20,15 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.spec.*; +import jtreg.SkippedException; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Signature; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; /** * @test @@ -46,9 +53,7 @@ public class InitAgainPSS extends PKCS11Test { try { s1 = Signature.getInstance(sigAlg, p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing " + sigAlg + - " due to no support"); - return; + throw new SkippedException("No support " + sigAlg); } byte[] msg = "hello".getBytes(); diff --git a/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java b/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java index adf7a08908e..45e26ec3930 100644 --- a/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/KeyAndParamCheckForPSS.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 @@ -20,9 +20,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; +import java.util.ArrayList; +import java.util.List; import jtreg.SkippedException; @@ -43,7 +52,7 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { main(new KeyAndParamCheckForPSS(), args); } - private static boolean skipTest = true; + private static final List skippedAlgs = new ArrayList<>(); @Override public void main(Provider p) throws Exception { @@ -73,8 +82,8 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { runTest(p, 1040, "SHA3-512", "SHA3-384"); runTest(p, 1040, "SHA3-512", "SHA3-512"); - if (skipTest) { - throw new SkippedException("Test Skipped"); + if (!skippedAlgs.isEmpty()) { + throw new SkippedException("Tests Skipped: " + skippedAlgs); } } @@ -84,7 +93,17 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { System.out.println("Testing " + hashAlg + " and MGF1" + mgfHashAlg); PSSUtil.AlgoSupport s = PSSUtil.isHashSupported(p, hashAlg, mgfHashAlg); if (s == PSSUtil.AlgoSupport.NO) { - System.out.println("=> Skip; no support"); + System.out.printf("=> Skip; no support keysize: %d, hash alg: %s, mgf Hash Alg: %s%n", + keySize, + hashAlg, + mgfHashAlg); + skippedAlgs.add( + String.format( + "[keysize: %s, hash alg: %s, mgf Hash Alg: %s]", + keySize, + hashAlg, + mgfHashAlg) + ); return; } @@ -108,7 +127,6 @@ public class KeyAndParamCheckForPSS extends PKCS11Test { sig.setParameter(paramsGood); sig.initSign(priv); // algorithm support confirmed - skipTest = false; } catch (Exception ex) { if (s == PSSUtil.AlgoSupport.MAYBE) { // confirmed to be unsupported; skip the rest of the test diff --git a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java index d5b22400bff..c9efa8fdf76 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS.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 @@ -21,9 +21,15 @@ * questions. */ -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; +import jtreg.SkippedException; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Signature; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; /* * @test @@ -53,9 +59,7 @@ public class SigInteropPSS extends PKCS11Test { try { sigPkcs11 = Signature.getInstance("RSASSA-PSS", p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing RSASSA-PSS" + - " due to no support"); - return; + throw new SkippedException("No support for RSASSA-PSS"); } Signature sigSunRsaSign = diff --git a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java index dfe56167848..ca0368841c5 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java +++ b/test/jdk/sun/security/pkcs11/Signature/SigInteropPSS2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, 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,9 +21,16 @@ * questions. */ -import java.security.*; -import java.security.spec.*; -import java.security.interfaces.*; +import jtreg.SkippedException; + +import java.security.AlgorithmParameters; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.security.Signature; +import java.security.spec.PSSParameterSpec; /* * @test @@ -67,9 +74,7 @@ public class SigInteropPSS2 extends PKCS11Test { try { sigPkcs11 = Signature.getInstance(digest + "withRSASSA-PSS", p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing " + digest + "withRSASSA-PSS" + - " due to no support"); - continue; + throw new SkippedException("No support for " + digest + "withRSASSA-PSS"); } runTest(sigPkcs11, sigSunRsaSign, kp); diff --git a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java index c87554a51b1..778a7758562 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.java +++ b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS.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 @@ -20,29 +20,55 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; -import java.util.stream.IntStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; +import java.util.ArrayList; +import java.util.List; + import jtreg.SkippedException; /** - * @test + * @test id=sha * @bug 8080462 8226651 8242332 * @summary Generate a RSASSA-PSS signature and verify it using PKCS11 provider * @library /test/lib .. * @modules jdk.crypto.cryptoki * @run main SignatureTestPSS */ + +/** + * @test id=sha3 + * @bug 8080462 8226651 8242332 + * @summary Generate a RSASSA-PSS signature and verify it using PKCS11 provider + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + * @run main SignatureTestPSS sha3 + */ public class SignatureTestPSS extends PKCS11Test { private static final String SIGALG = "RSASSA-PSS"; private static final int[] KEYSIZES = { 2048, 3072 }; - private static final String[] DIGESTS = { + + private static String[] DIGESTS = null; + + private static final String[] SHA_DIGESTS = { "SHA-224", "SHA-256", "SHA-384" , "SHA-512", - "SHA3-224", "SHA3-256", "SHA3-384" , "SHA3-512", }; + private static final String[] SHA3_DIGESTS = { + "SHA3-224", "SHA3-256", "SHA3-384" , "SHA3-512" + }; + private static final byte[] DATA = generateData(100); /** @@ -55,9 +81,12 @@ public class SignatureTestPSS extends PKCS11Test { */ private static final int UPDATE_TIMES_HUNDRED = 100; - private static boolean skipTest = true; + private static final List skippedAlgs = new ArrayList<>(); public static void main(String[] args) throws Exception { + DIGESTS = (args.length > 0 && "sha3".equals(args[0])) ? + SHA3_DIGESTS : SHA_DIGESTS; + main(new SignatureTestPSS(), args); } @@ -80,6 +109,8 @@ public class SignatureTestPSS extends PKCS11Test { PSSUtil.isHashSupported(p, hash, mgfHash); if (s == PSSUtil.AlgoSupport.NO) { System.out.println(" => Skip; no support"); + skippedAlgs.add("[Hash = " + hash + + ", MGF1 Hash = " + mgfHash + "]"); continue; } checkSignature(p, DATA, pubKey, privKey, hash, mgfHash, s); @@ -87,17 +118,15 @@ public class SignatureTestPSS extends PKCS11Test { }; } - // start testing below - if (skipTest) { - throw new SkippedException("Test Skipped"); + if (!skippedAlgs.isEmpty()) { + throw new SkippedException("Test Skipped :" + skippedAlgs); } } private static void checkSignature(Provider p, byte[] data, PublicKey pub, PrivateKey priv, String hash, String mgfHash, PSSUtil.AlgoSupport s) throws NoSuchAlgorithmException, InvalidKeyException, - SignatureException, NoSuchProviderException, - InvalidAlgorithmParameterException { + SignatureException { // only test RSASSA-PSS signature against the supplied hash/mgfHash // if they are supported; otherwise PKCS11 library will throw @@ -112,14 +141,27 @@ public class SignatureTestPSS extends PKCS11Test { } catch (InvalidAlgorithmParameterException iape) { if (s == PSSUtil.AlgoSupport.MAYBE) { // confirmed to be unsupported; skip the rest of the test - System.out.println(" => Skip; no PSS support"); + System.out.printf(" => Skip; no PSS support public key: %s, private key: %s, " + + "hash: %s, mgf hash: %s, Algo Support: %s%n", + pub, + priv, + hash, + mgfHash, + s); + skippedAlgs.add(String.format( + "[public key: %s, private key: %s, " + + "hash: %s, mgf hash: %s, Algo Support: %s]", + pub, + priv, + hash, + mgfHash, + s) + ); return; } else { throw new RuntimeException("Unexpected Exception", iape); } } - // start testing below - skipTest = false; for (int i = 0; i < UPDATE_TIMES_HUNDRED; i++) { sig.update(data); diff --git a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java index 516b17972e5..ac6c13523a2 100644 --- a/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.java +++ b/test/jdk/sun/security/pkcs11/Signature/SignatureTestPSS2.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 @@ -20,13 +20,23 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; +import jtreg.SkippedException; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; import java.util.stream.IntStream; /** - * @test + * @test id=sha * @bug 8244154 8242332 * @summary Generate a withRSASSA-PSS signature and verify it using * PKCS11 provider @@ -34,13 +44,28 @@ import java.util.stream.IntStream; * @modules jdk.crypto.cryptoki * @run main SignatureTestPSS2 */ + +/** + * @test id=sha3 + * @bug 8244154 8242332 + * @summary Generate a withRSASSA-PSS signature and verify it using + * PKCS11 provider + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + * @run main SignatureTestPSS2 sha3 + */ public class SignatureTestPSS2 extends PKCS11Test { // PKCS11 does not support RSASSA-PSS keys yet private static final String KEYALG = "RSA"; - private static final String[] SIGALGS = { + + private static String[] SIGALGS = null; + + private static final String[] SHA_SIGALGS = { "SHA224withRSASSA-PSS", "SHA256withRSASSA-PSS", - "SHA384withRSASSA-PSS", "SHA512withRSASSA-PSS", + "SHA384withRSASSA-PSS", "SHA512withRSASSA-PSS" + }; + private static final String[] SHA3_SIGALGS = { "SHA3-224withRSASSA-PSS", "SHA3-256withRSASSA-PSS", "SHA3-384withRSASSA-PSS", "SHA3-512withRSASSA-PSS" }; @@ -53,6 +78,8 @@ public class SignatureTestPSS2 extends PKCS11Test { private static final int UPDATE_TIMES = 2; public static void main(String[] args) throws Exception { + SIGALGS = (args.length > 0 && "sha3".equals(args[0])) ? SHA3_SIGALGS : SHA_SIGALGS; + main(new SignatureTestPSS2(), args); } @@ -63,9 +90,7 @@ public class SignatureTestPSS2 extends PKCS11Test { try { sig = Signature.getInstance(sa, p); } catch (NoSuchAlgorithmException e) { - System.out.println("Skip testing " + sa + - " due to no support"); - return; + throw new SkippedException("No support for " + sa); } for (int i : KEYSIZES) { runTest(sig, i); @@ -94,7 +119,7 @@ public class SignatureTestPSS2 extends PKCS11Test { SignatureException | NoSuchProviderException ex) { throw new RuntimeException(ex); } catch (InvalidAlgorithmParameterException ex2) { - System.out.println("Skip test due to " + ex2); + throw new SkippedException(ex2.toString()); } } diff --git a/test/jdk/sun/security/pkcs11/Signature/TestDSA.java b/test/jdk/sun/security/pkcs11/Signature/TestDSA.java index e7b937d6190..0a086bd2ed0 100644 --- a/test/jdk/sun/security/pkcs11/Signature/TestDSA.java +++ b/test/jdk/sun/security/pkcs11/Signature/TestDSA.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 @@ -32,6 +32,8 @@ * @run main/othervm TestDSA */ +import jtreg.SkippedException; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; @@ -122,8 +124,7 @@ public class TestDSA extends PKCS11Test { System.out.println("Testing provider " + provider + "..."); if (provider.getService("Signature", "SHA1withDSA") == null) { - System.out.println("DSA not supported, skipping"); - return; + throw new SkippedException("DSA not supported"); } KeyFactory kf = KeyFactory.getInstance("DSA", provider); From 8e653d394e45180e16714124ed6584f912eb5cba Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 4 Dec 2025 20:17:02 +0000 Subject: [PATCH 069/141] 8373099: Problem list intermittently failing test sun/awt/image/bug8038000.java Reviewed-by: dholmes --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index c838cbc56e6..814fd2caae9 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -500,6 +500,7 @@ java/awt/GraphicsDevice/DisplayModes/UnknownRefrshRateTest.java 8286436 macosx-a java/awt/image/multiresolution/MultiresolutionIconTest.java 8291979 linux-x64,windows-all java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java 8305061 macosx-x64 sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java 8301177 linux-x64 +sun/awt/image/bug8038000.java 8373065 generic-all # Several tests which fail on some hidpi systems/macosx12-aarch64 system java/awt/Window/8159168/SetShapeTest.java 8274106 macosx-aarch64 From 5ec5a6ea6c8e887b4e21f81e382f57129bffbab8 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 4 Dec 2025 21:37:09 +0000 Subject: [PATCH 070/141] 8373054: Shenandoah: Remove unnecessary BarrierSetNMethod::arm in shenandoahCodeRoots Reviewed-by: wkemper, ysr, shade --- src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index ec39e0c0ccb..07d339eb32e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -144,13 +144,12 @@ public: { ShenandoahReentrantLocker locker(nm_data->lock()); - // Heal oops and disarm + // Heal oops if (_bs->is_armed(nm)) { ShenandoahEvacOOMScope oom_evac_scope; ShenandoahNMethod::heal_nmethod_metadata(nm_data); - // Code cache unloading needs to know about on-stack nmethods. Arm the nmethods to get - // mark_as_maybe_on_stack() callbacks when they are used again. - _bs->arm(nm); + // Must remain armed to complete remaining work in nmethod entry barrier + assert(_bs->is_armed(nm), "Should remain armed"); } } From c8b30da7ef48edb3d43e07d2c1b8622d8123c3a9 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Thu, 4 Dec 2025 22:11:48 +0000 Subject: [PATCH 071/141] 8373039: Remove Incorrect Asserts in shenandoahScanRemembered Reviewed-by: wkemper, ysr, xpeng --- .../gc/shenandoah/shenandoahScanRemembered.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp index 44064dbd1a9..a3c96a7d53b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.cpp @@ -335,7 +335,6 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con if (ctx->is_marked(p)) { oop obj = cast_to_oop(p); assert(oopDesc::is_oop(obj), "Should be an object"); - assert(Klass::is_valid(obj->klass()), "Not a valid klass ptr"); assert(p + obj->size() > left, "This object should span start of card"); assert(p < right, "Result must precede right"); return p; @@ -362,15 +361,15 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con // Recall that we already dealt with the co-initial object case above assert(p < left, "obj should start before left"); - // While it is safe to ask an object its size in the loop that - // follows, the (ifdef'd out) loop should never be needed. + // While it is safe to ask an object its size in the block that + // follows, the (ifdef'd out) block should never be needed. // 1. we ask this question only for regions in the old generation, and those // that are not humongous regions // 2. there is no direct allocation ever by mutators in old generation // regions walked by this code. Only GC will ever allocate in old regions, // and then too only during promotion/evacuation phases. Thus there is no danger // of races between reading from and writing to the object start array, - // or of asking partially initialized objects their size (in the loop below). + // or of asking partially initialized objects their size (in the ifdef below). // Furthermore, humongous regions (and their dirty cards) are never processed // by this code. // 3. only GC asks this question during phases when it is not concurrently @@ -382,15 +381,6 @@ HeapWord* ShenandoahCardCluster::first_object_start(const size_t card_index, con #ifdef ASSERT oop obj = cast_to_oop(p); assert(oopDesc::is_oop(obj), "Should be an object"); - while (p + obj->size() < left) { - p += obj->size(); - obj = cast_to_oop(p); - assert(oopDesc::is_oop(obj), "Should be an object"); - assert(Klass::is_valid(obj->klass()), "Not a valid klass ptr"); - // Check assumptions in previous block comment if this assert fires - fatal("Should never need forward walk in block start"); - } - assert(p <= left, "p should start at or before left end of card"); assert(p + obj->size() > left, "obj should end after left end of card"); #endif // ASSERT return p; From 6db1c4f5b93a1b7f7d9da36745dc433c9985a169 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 4 Dec 2025 22:34:42 +0000 Subject: [PATCH 072/141] 8371409: Wrong lock ordering between FullGCALot_lock and ThreadsLockThrottle_lock/MethodCompileQueue_lock Reviewed-by: rehn, pchilanomate --- src/hotspot/share/memory/universe.cpp | 4 ++-- src/hotspot/share/runtime/mutexLocker.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index 4d2897be5eb..cfbab1b8afb 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -544,7 +544,7 @@ void Universe::genesis(TRAPS) { // Only modify the global variable inside the mutex. // If we had a race to here, the other dummy_array instances // and their elements just get dropped on the floor, which is fine. - MutexLocker ml(THREAD, FullGCALot_lock); + MutexLocker ml(THREAD, FullGCALot_lock, Mutex::_no_safepoint_check_flag); if (_fullgc_alot_dummy_array.is_empty()) { _fullgc_alot_dummy_array = OopHandle(vm_global(), dummy_array()); } @@ -1458,7 +1458,7 @@ uintptr_t Universe::verify_mark_bits() { #ifdef ASSERT // Release dummy object(s) at bottom of heap bool Universe::release_fullgc_alot_dummy() { - MutexLocker ml(FullGCALot_lock); + MutexLocker ml(FullGCALot_lock, Mutex::_no_safepoint_check_flag); objArrayOop fullgc_alot_dummy_array = (objArrayOop)_fullgc_alot_dummy_array.resolve(); if (fullgc_alot_dummy_array != nullptr) { if (_fullgc_alot_dummy_next >= fullgc_alot_dummy_array->length()) { diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 5d7e310fb11..b102e6424f1 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -244,7 +244,7 @@ void mutex_init() { MUTEX_DEFN(SymbolArena_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(ExceptionCache_lock , PaddedMutex , safepoint); #ifndef PRODUCT - MUTEX_DEFN(FullGCALot_lock , PaddedMutex , safepoint); // a lock to make FullGCALot MT safe + MUTEX_DEFN(FullGCALot_lock , PaddedMutex , nosafepoint); // a lock to make FullGCALot MT safe #endif MUTEX_DEFN(BeforeExit_lock , PaddedMonitor, safepoint); From 13e32bf1667a3be8492d1e4e3a273951202acd9c Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 4 Dec 2025 22:39:58 +0000 Subject: [PATCH 073/141] 8372098: Move AccessFlags to InstanceKlass Reviewed-by: liach, vlivanov, dlong, sspitsyn --- src/hotspot/share/ci/ciInstanceKlass.hpp | 4 ++++ src/hotspot/share/ci/ciKlass.cpp | 9 -------- src/hotspot/share/ci/ciKlass.hpp | 3 --- .../share/classfile/defaultMethods.cpp | 2 +- src/hotspot/share/classfile/javaClasses.cpp | 8 +++---- .../share/classfile/systemDictionary.cpp | 7 +++--- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 2 +- src/hotspot/share/oops/arrayKlass.cpp | 3 ++- src/hotspot/share/oops/fieldInfo.hpp | 1 + src/hotspot/share/oops/instanceKlass.cpp | 11 ++++++++++ src/hotspot/share/oops/instanceKlass.hpp | 20 ++++++++++++++++- src/hotspot/share/oops/klass.cpp | 11 ---------- src/hotspot/share/oops/klass.hpp | 22 +++++-------------- src/hotspot/share/opto/compile.cpp | 8 +++++-- src/hotspot/share/opto/library_call.cpp | 14 +++++++----- src/hotspot/share/opto/memnode.cpp | 8 ++++--- src/hotspot/share/runtime/vmStructs.cpp | 2 +- src/hotspot/share/utilities/accessFlags.hpp | 2 +- .../sun/jvm/hotspot/oops/InstanceKlass.java | 17 ++++++++++++-- .../classes/sun/jvm/hotspot/oops/Klass.java | 16 +------------- .../sun/jvm/hotspot/oops/ObjectHeap.java | 6 ++--- .../runtime/ConcurrentLocksPrinter.java | 4 ++-- .../jvm/hotspot/tools/ClassLoaderStats.java | 4 ++-- .../HotSpotResolvedObjectTypeImpl.java | 10 ++++++--- .../jdk/vm/ci/hotspot/HotSpotVMConfig.java | 2 +- 25 files changed, 106 insertions(+), 90 deletions(-) diff --git a/src/hotspot/share/ci/ciInstanceKlass.hpp b/src/hotspot/share/ci/ciInstanceKlass.hpp index 1f887771f54..a1b2d8dd12d 100644 --- a/src/hotspot/share/ci/ciInstanceKlass.hpp +++ b/src/hotspot/share/ci/ciInstanceKlass.hpp @@ -149,6 +149,10 @@ public: assert(is_loaded(), "must be loaded"); return _flags; } + + // Fetch Klass::access_flags. + jint access_flags() { return flags().as_int(); } + bool has_finalizer() { assert(is_loaded(), "must be loaded"); return _has_finalizer; } diff --git a/src/hotspot/share/ci/ciKlass.cpp b/src/hotspot/share/ci/ciKlass.cpp index f3e49634d29..0a0379af97e 100644 --- a/src/hotspot/share/ci/ciKlass.cpp +++ b/src/hotspot/share/ci/ciKlass.cpp @@ -216,15 +216,6 @@ jint ciKlass::modifier_flags() { ) } -// ------------------------------------------------------------------ -// ciKlass::access_flags -jint ciKlass::access_flags() { - assert(is_loaded(), "not loaded"); - GUARDED_VM_ENTRY( - return get_Klass()->access_flags().as_unsigned_short(); - ) -} - // ------------------------------------------------------------------ // ciKlass::misc_flags klass_flags_t ciKlass::misc_flags() { diff --git a/src/hotspot/share/ci/ciKlass.hpp b/src/hotspot/share/ci/ciKlass.hpp index 8d03b910de5..f95602b9717 100644 --- a/src/hotspot/share/ci/ciKlass.hpp +++ b/src/hotspot/share/ci/ciKlass.hpp @@ -122,9 +122,6 @@ public: // Fetch modifier flags. jint modifier_flags(); - // Fetch Klass::access_flags. - jint access_flags(); - // Fetch Klass::misc_flags. klass_flags_t misc_flags(); diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp index e5cb5d8f354..2588ebd60ca 100644 --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -439,7 +439,7 @@ class MethodFamily : public ResourceObj { StreamIndentor si(str, indent * 2); str->print("Selected method: "); print_method(str, _selected_target); - Klass* method_holder = _selected_target->method_holder(); + InstanceKlass* method_holder = _selected_target->method_holder(); if (!method_holder->is_interface()) { str->print(" : in superclass"); } diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 614a0199beb..77a94c8afa5 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1091,10 +1091,6 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // Set the modifiers flag. u2 computed_modifiers = k->compute_modifier_flags(); set_modifiers(mirror(), computed_modifiers); - // Set the raw access_flags, this is used by reflection instead of modifier flags. - // The Java code for array classes gets the access flags from the element type. - assert(!k->is_array_klass() || k->access_flags().as_unsigned_short() == 0, "access flags are not set for arrays"); - set_raw_access_flags(mirror(), k->access_flags().as_unsigned_short()); InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass()); assert(oop_size(mirror()) == mk->instance_size(k), "should have been set"); @@ -1103,6 +1099,8 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // It might also have a component mirror. This mirror must already exist. if (k->is_array_klass()) { + // The Java code for array classes gets the access flags from the element type. + set_raw_access_flags(mirror(), 0); if (k->is_typeArray_klass()) { BasicType type = TypeArrayKlass::cast(k)->element_type(); if (is_scratch) { @@ -1129,6 +1127,8 @@ void java_lang_Class::allocate_mirror(Klass* k, bool is_scratch, Handle protecti // and java_mirror in this klass. } else { assert(k->is_instance_klass(), "Must be"); + // Set the raw access_flags, this is used by reflection instead of modifier flags. + set_raw_access_flags(mirror(), InstanceKlass::cast(k)->access_flags().as_unsigned_short()); initialize_mirror_fields(InstanceKlass::cast(k), mirror, protection_domain, classData, THREAD); if (HAS_PENDING_EXCEPTION) { // If any of the fields throws an exception like OOM remove the klass field diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index c873347a197..e03d198eb9f 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -2172,9 +2172,10 @@ static bool is_always_visible_class(oop mirror) { return true; // primitive array } assert(klass->is_instance_klass(), "%s", klass->external_name()); - return klass->is_public() && - (InstanceKlass::cast(klass)->is_same_class_package(vmClasses::Object_klass()) || // java.lang - InstanceKlass::cast(klass)->is_same_class_package(vmClasses::MethodHandle_klass())); // java.lang.invoke + InstanceKlass* ik = InstanceKlass::cast(klass); + return ik->is_public() && + (ik->is_same_class_package(vmClasses::Object_klass()) || // java.lang + ik->is_same_class_package(vmClasses::MethodHandle_klass())); // java.lang.invoke } // Find or construct the Java mirror (java.lang.Class instance) for diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 77e98db9156..91482e825cd 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -223,6 +223,7 @@ volatile_nonstatic_field(InstanceKlass, _init_state, InstanceKlass::ClassState) \ volatile_nonstatic_field(InstanceKlass, _init_thread, JavaThread*) \ nonstatic_field(InstanceKlass, _misc_flags._flags, u2) \ + nonstatic_field(InstanceKlass, _access_flags, AccessFlags) \ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_sp, intptr_t*) \ @@ -282,7 +283,6 @@ nonstatic_field(Klass, _name, Symbol*) \ volatile_nonstatic_field(Klass, _next_sibling, Klass*) \ nonstatic_field(Klass, _java_mirror, OopHandle) \ - nonstatic_field(Klass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _class_loader_data, ClassLoaderData*) \ nonstatic_field(Klass, _secondary_supers_bitmap, uintx) \ nonstatic_field(Klass, _hash_slot, uint8_t) \ diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index cd929a3bfe1..30a2bc5102a 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -99,7 +99,8 @@ ArrayKlass::ArrayKlass(Symbol* name, KlassKind kind) : set_name(name); set_super(Universe::is_bootstrapping() ? nullptr : vmClasses::Object_klass()); set_layout_helper(Klass::_lh_neutral_value); - set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5) + // All arrays are considered to be cloneable (See JLS 20.1.5) + set_is_cloneable_fast(); JFR_ONLY(INIT_ID(this);) log_array_class_load(this); } diff --git a/src/hotspot/share/oops/fieldInfo.hpp b/src/hotspot/share/oops/fieldInfo.hpp index a98895da9cf..b6d9c4d34e5 100644 --- a/src/hotspot/share/oops/fieldInfo.hpp +++ b/src/hotspot/share/oops/fieldInfo.hpp @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "oops/typeArrayOop.hpp" +#include "utilities/accessFlags.hpp" #include "utilities/unsigned5.hpp" #include "utilities/vmEnums.hpp" diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 24358f662bc..e74bc80d893 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -552,6 +552,17 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind, Refe assert(size_helper() == parser.layout_size(), "incorrect size_helper?"); } +void InstanceKlass::set_is_cloneable() { + if (name() == vmSymbols::java_lang_invoke_MemberName()) { + assert(is_final(), "no subclasses allowed"); + // MemberName cloning should not be intrinsified and always happen in JVM_Clone. + } else if (reference_type() != REF_NONE) { + // Reference cloning should not be intrinsified and always happen in JVM_Clone. + } else { + set_is_cloneable_fast(); + } +} + void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data, Array* methods) { if (methods != nullptr && methods != Universe::the_empty_method_array() && diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 8bb9741af9f..a03e6c05b54 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -229,7 +229,9 @@ class InstanceKlass: public Klass { // _idnum_allocated_count. volatile ClassState _init_state; // state of class - u1 _reference_type; // reference type + u1 _reference_type; // reference type + + AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. // State is set either at parse time or while executing, atomically to not disturb other state InstanceKlassFlags _misc_flags; @@ -305,6 +307,22 @@ class InstanceKlass: public Klass { // Sets finalization state static void set_finalization_enabled(bool val) { _finalization_enabled = val; } + // Access flags + AccessFlags access_flags() const { return _access_flags; } + void set_access_flags(AccessFlags flags) { _access_flags = flags; } + + bool is_public() const { return _access_flags.is_public(); } + bool is_final() const { return _access_flags.is_final(); } + bool is_interface() const { return _access_flags.is_interface(); } + bool is_abstract() const { return _access_flags.is_abstract(); } + bool is_super() const { return _access_flags.is_super(); } + bool is_synthetic() const { return _access_flags.is_synthetic(); } + void set_is_synthetic() { _access_flags.set_is_synthetic(); } + + static ByteSize access_flags_offset() { return byte_offset_of(InstanceKlass, _access_flags); } + + void set_is_cloneable(); + // Quick checks for the loader that defined this class (without switching on this->class_loader()) bool defined_by_boot_loader() const { return _misc_flags.defined_by_boot_loader(); } bool defined_by_platform_loader() const { return _misc_flags.defined_by_platform_loader(); } diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index 772541cdd10..001e9eba790 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -72,17 +72,6 @@ bool Klass::is_cloneable() const { is_subtype_of(vmClasses::Cloneable_klass()); } -void Klass::set_is_cloneable() { - if (name() == vmSymbols::java_lang_invoke_MemberName()) { - assert(is_final(), "no subclasses allowed"); - // MemberName cloning should not be intrinsified and always happen in JVM_Clone. - } else if (is_instance_klass() && InstanceKlass::cast(this)->reference_type() != REF_NONE) { - // Reference cloning should not be intrinsified and always happen in JVM_Clone. - } else { - _misc_flags.set_is_cloneable_fast(true); - } -} - uint8_t Klass::compute_hash_slot(Symbol* n) { uint hash_code; // Special cases for the two superclasses of all Array instances. diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 5ac393d7614..25fb900e7d6 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -30,7 +30,6 @@ #include "oops/metadata.hpp" #include "oops/oop.hpp" #include "oops/oopHandle.hpp" -#include "utilities/accessFlags.hpp" #include "utilities/macros.hpp" #if INCLUDE_JFR #include "jfr/support/jfrTraceIdExtension.hpp" @@ -120,9 +119,8 @@ class Klass : public Metadata { // - Various type checking in the JVM const KlassKind _kind; - AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. - // Some flags created by the JVM, not in the class file itself, - // are in _misc_flags below. + // Some flags created by the JVM, not in the class file itself, + // are in _misc_flags below. KlassFlags _misc_flags; // The fields _super_check_offset, _secondary_super_cache, _secondary_supers @@ -453,7 +451,6 @@ protected: static ByteSize java_mirror_offset() { return byte_offset_of(Klass, _java_mirror); } static ByteSize class_loader_data_offset() { return byte_offset_of(Klass, _class_loader_data); } static ByteSize layout_helper_offset() { return byte_offset_of(Klass, _layout_helper); } - static ByteSize access_flags_offset() { return byte_offset_of(Klass, _access_flags); } #if INCLUDE_JVMCI static ByteSize subklass_offset() { return byte_offset_of(Klass, _subklass); } static ByteSize next_sibling_offset() { return byte_offset_of(Klass, _next_sibling); } @@ -707,17 +704,10 @@ public: bool is_typeArray_klass() const { return assert_same_query( _kind == TypeArrayKlassKind, is_typeArray_klass_slow()); } #undef assert_same_query - // Access flags - AccessFlags access_flags() const { return _access_flags; } - void set_access_flags(AccessFlags flags) { _access_flags = flags; } - bool is_public() const { return _access_flags.is_public(); } - bool is_final() const { return _access_flags.is_final(); } - bool is_interface() const { return _access_flags.is_interface(); } - bool is_abstract() const { return _access_flags.is_abstract(); } - bool is_super() const { return _access_flags.is_super(); } - bool is_synthetic() const { return _access_flags.is_synthetic(); } - void set_is_synthetic() { _access_flags.set_is_synthetic(); } + virtual bool is_interface() const { return false; } + virtual bool is_abstract() const { return false; } + bool has_finalizer() const { return _misc_flags.has_finalizer(); } void set_has_finalizer() { _misc_flags.set_has_finalizer(true); } bool is_hidden() const { return _misc_flags.is_hidden_class(); } @@ -730,7 +720,7 @@ public: inline bool is_non_strong_hidden() const; bool is_cloneable() const; - void set_is_cloneable(); + void set_is_cloneable_fast() { _misc_flags.set_is_cloneable_fast(true); } inline markWord prototype_header() const; inline void set_prototype_header(markWord header); diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index a89b5b00a25..bf7feeed0a2 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1726,8 +1726,6 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr } if (flat->offset() == in_bytes(Klass::super_check_offset_offset())) alias_type(idx)->set_rewritable(false); - if (flat->offset() == in_bytes(Klass::access_flags_offset())) - alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::misc_flags_offset())) alias_type(idx)->set_rewritable(false); if (flat->offset() == in_bytes(Klass::java_mirror_offset())) @@ -1735,6 +1733,12 @@ Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_cr if (flat->offset() == in_bytes(Klass::secondary_super_cache_offset())) alias_type(idx)->set_rewritable(false); } + + if (flat->isa_instklassptr()) { + if (flat->offset() == in_bytes(InstanceKlass::access_flags_offset())) { + alias_type(idx)->set_rewritable(false); + } + } // %%% (We would like to finalize JavaThread::threadObj_offset(), // but the base pointer type is not distinctive enough to identify // references into JavaThread.) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 6d4a9104580..113530c8835 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4020,7 +4020,7 @@ Node* LibraryCallKit::generate_klass_flags_guard(Node* kls, int modifier_mask, i } Node* LibraryCallKit::generate_interface_guard(Node* kls, RegionNode* region) { return generate_klass_flags_guard(kls, JVM_ACC_INTERFACE, 0, region, - Klass::access_flags_offset(), TypeInt::CHAR, T_CHAR); + InstanceKlass::access_flags_offset(), TypeInt::CHAR, T_CHAR); } // Use this for testing if Klass is_hidden, has_finalizer, and is_cloneable_fast. @@ -4132,12 +4132,16 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) { // Arrays store an intermediate super as _super, but must report Object. // Other types can report the actual _super. // (To verify this code sequence, check the asserts in JVM_IsInterface.) - if (generate_interface_guard(kls, region) != nullptr) - // A guard was added. If the guard is taken, it was an interface. - phi->add_req(null()); - if (generate_array_guard(kls, region) != nullptr) + if (generate_array_guard(kls, region) != nullptr) { // A guard was added. If the guard is taken, it was an array. phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror()))); + } + // Check for interface after array since this checks AccessFlags offset into InstanceKlass. + // In other words, we are accessing subtype-specific information, so we need to determine the subtype first. + if (generate_interface_guard(kls, region) != nullptr) { + // A guard was added. If the guard is taken, it was an interface. + 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())); kls = _gvn.transform(LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeInstKlassPtr::OBJECT_OR_NULL)); diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 61300ab4fcb..19ff90df5ed 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1979,10 +1979,12 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, ciKlass* klass) const { assert(!UseCompactObjectHeaders || tkls->offset() != in_bytes(Klass::prototype_header_offset()), "must not happen"); - if (tkls->offset() == in_bytes(Klass::access_flags_offset())) { - // The field is Klass::_access_flags. Return its (constant) value. + + if (tkls->isa_instklassptr() && tkls->offset() == in_bytes(InstanceKlass::access_flags_offset())) { + // The field is InstanceKlass::_access_flags. Return its (constant) value. assert(Opcode() == Op_LoadUS, "must load an unsigned short from _access_flags"); - return TypeInt::make(klass->access_flags()); + ciInstanceKlass* iklass = tkls->is_instklassptr()->instance_klass(); + return TypeInt::make(iklass->access_flags()); } if (tkls->offset() == in_bytes(Klass::misc_flags_offset())) { // The field is Klass::_misc_flags. Return its (constant) value. diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 25a99c2d758..50748fd7e45 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -216,6 +216,7 @@ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ nonstatic_field(InstanceKlass, _method_ordering, Array*) \ nonstatic_field(InstanceKlass, _default_vtable_indices, Array*) \ + nonstatic_field(InstanceKlass, _access_flags, AccessFlags) \ nonstatic_field(Klass, _super_check_offset, juint) \ nonstatic_field(Klass, _secondary_super_cache, Klass*) \ nonstatic_field(Klass, _secondary_supers, Array*) \ @@ -225,7 +226,6 @@ volatile_nonstatic_field(Klass, _subklass, Klass*) \ nonstatic_field(Klass, _layout_helper, jint) \ nonstatic_field(Klass, _name, Symbol*) \ - nonstatic_field(Klass, _access_flags, AccessFlags) \ volatile_nonstatic_field(Klass, _next_sibling, Klass*) \ nonstatic_field(Klass, _next_link, Klass*) \ nonstatic_field(Klass, _vtable_len, int) \ diff --git a/src/hotspot/share/utilities/accessFlags.hpp b/src/hotspot/share/utilities/accessFlags.hpp index a752c09cb42..54bbaeb2c13 100644 --- a/src/hotspot/share/utilities/accessFlags.hpp +++ b/src/hotspot/share/utilities/accessFlags.hpp @@ -67,7 +67,7 @@ class AccessFlags { void set_flags(u2 flags) { _flags = flags; } private: - friend class Klass; + friend class InstanceKlass; friend class ClassFileParser; // the functions below should only be called on the _access_flags inst var directly, // otherwise they are just changing a copy of the flags diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index 0cd743372d5..785bb85e640 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -62,6 +62,16 @@ public class InstanceKlass extends Klass { private static int CLASS_STATE_FULLY_INITIALIZED; private static int CLASS_STATE_INITIALIZATION_ERROR; + public long getAccessFlags() { return accessFlags.getValue(this); } + // Convenience routine + public AccessFlags getAccessFlagsObj() { return new AccessFlags(getAccessFlags()); } + + public boolean isPublic() { return getAccessFlagsObj().isPublic(); } + public boolean isFinal() { return getAccessFlagsObj().isFinal(); } + public boolean isInterface() { return getAccessFlagsObj().isInterface(); } + public boolean isAbstract() { return getAccessFlagsObj().isAbstract(); } + public boolean isSuper() { return getAccessFlagsObj().isSuper(); } + public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { Type type = db.lookupType("InstanceKlass"); @@ -88,6 +98,7 @@ public class InstanceKlass extends Klass { breakpoints = type.getAddressField("_breakpoints"); } headerSize = type.getSize(); + accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); // read internal field flags constants FIELD_FLAG_IS_INITIALIZED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_initialized"); @@ -150,6 +161,7 @@ public class InstanceKlass extends Klass { private static CIntField initState; private static CIntField itableLen; private static CIntField nestHostIndex; + private static CIntField accessFlags; private static AddressField breakpoints; // type safe enum for ClassState from instanceKlass.hpp @@ -499,7 +511,7 @@ public class InstanceKlass extends Klass { } } - public boolean implementsInterface(Klass k) { + public boolean implementsInterface(InstanceKlass k) { if (Assert.ASSERTS_ENABLED) { Assert.that(k.isInterface(), "should not reach here"); } @@ -511,7 +523,7 @@ public class InstanceKlass extends Klass { return false; } - boolean computeSubtypeOf(Klass k) { + boolean computeSubtypeOf(InstanceKlass k) { if (k.isInterface()) { return implementsInterface(k); } else { @@ -535,6 +547,7 @@ public class InstanceKlass extends Klass { visitor.doCInt(nonstaticOopMapSize, true); visitor.doCInt(initState, true); visitor.doCInt(itableLen, true); + visitor.doCInt(accessFlags, true); } /* diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java index 1b8a9d0ef69..561c4683d29 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Klass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, 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 @@ -57,7 +57,6 @@ public class Klass extends Metadata implements ClassConstants { superField = new MetadataField(type.getAddressField("_super"), 0); layoutHelper = new IntField(type.getJIntField("_layout_helper"), 0); name = type.getAddressField("_name"); - accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0); try { traceIDField = type.getField("_trace_id"); } catch(Exception e) { @@ -95,7 +94,6 @@ public class Klass extends Metadata implements ClassConstants { private static MetadataField superField; private static IntField layoutHelper; private static AddressField name; - private static CIntField accessFlags; private static MetadataField subklass; private static MetadataField nextSibling; private static MetadataField nextLink; @@ -117,9 +115,6 @@ public class Klass extends Metadata implements ClassConstants { public Klass getJavaSuper() { return null; } public int getLayoutHelper() { return layoutHelper.getValue(this); } public Symbol getName() { return getSymbol(name); } - public long getAccessFlags() { return accessFlags.getValue(this); } - // Convenience routine - public AccessFlags getAccessFlagsObj(){ return new AccessFlags(getAccessFlags()); } public Klass getSubklassKlass() { return (Klass) subklass.getValue(this); } public Klass getNextSiblingKlass() { return (Klass) nextSibling.getValue(this); } public Klass getNextLinkKlass() { return (Klass) nextLink.getValue(this); } @@ -175,7 +170,6 @@ public class Klass extends Metadata implements ClassConstants { visitor.doMetadata(superField, true); visitor.doInt(layoutHelper, true); // visitor.doOop(name, true); - visitor.doCInt(accessFlags, true); visitor.doMetadata(subklass, true); visitor.doMetadata(nextSibling, true); visitor.doCInt(vtableLen, true); @@ -205,12 +199,4 @@ public class Klass extends Metadata implements ClassConstants { // The subclasses override this to produce the correct form, eg // Ljava/lang/String; For ArrayKlasses getName itself is the signature. public String signature() { return getName().asString(); } - - // Convenience routines - public boolean isPublic() { return getAccessFlagsObj().isPublic(); } - public boolean isFinal() { return getAccessFlagsObj().isFinal(); } - public boolean isInterface() { return getAccessFlagsObj().isInterface(); } - public boolean isAbstract() { return getAccessFlagsObj().isAbstract(); } - public boolean isSuper() { return getAccessFlagsObj().isSuper(); } - public boolean isSynthetic() { return getAccessFlagsObj().isSynthetic(); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java index a4cdb671959..c71cb3156ea 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/ObjectHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, 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 @@ -107,7 +107,7 @@ public class ObjectHeap { /** iterate objects of given Klass. param 'includeSubtypes' tells whether to * include objects of subtypes or not */ - public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k, boolean includeSubtypes) { + public void iterateObjectsOfKlass(HeapVisitor visitor, final InstanceKlass k, boolean includeSubtypes) { if (includeSubtypes) { if (k.isFinal()) { // do the simpler "exact" klass loop @@ -124,7 +124,7 @@ public class ObjectHeap { } /** iterate objects of given Klass (objects of subtypes included) */ - public void iterateObjectsOfKlass(HeapVisitor visitor, final Klass k) { + public void iterateObjectsOfKlass(HeapVisitor visitor, final InstanceKlass k) { iterateObjectsOfKlass(visitor, k, true); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java index fa28a96e333..c4abb3e946d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ConcurrentLocksPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ public class ConcurrentLocksPrinter { private void fillLocks() { VM vm = VM.getVM(); SystemDictionary sysDict = vm.getSystemDictionary(); - Klass absOwnSyncKlass = sysDict.getAbstractOwnableSynchronizerKlass(); + InstanceKlass absOwnSyncKlass = sysDict.getAbstractOwnableSynchronizerKlass(); ObjectHeap heap = vm.getObjectHeap(); // may be not loaded at all if (absOwnSyncKlass != null) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java index b7c470e3477..0e65a41c571 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, 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 @@ -90,7 +90,7 @@ public class ClassLoaderStats extends Tool { VM vm = VM.getVM(); ObjectHeap heap = vm.getObjectHeap(); - Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); + InstanceKlass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); try { heap.iterateObjectsOfKlass(new DefaultHeapVisitor() { public boolean doObj(Oop oop) { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java index 46e53411dee..6074b2b32dc 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2024, 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 @@ -165,8 +165,12 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem } public int getAccessFlags() { - HotSpotVMConfig config = config(); - return UNSAFE.getInt(getKlassPointer() + config.klassAccessFlagsOffset); + if (isArray()) { + return 0; // Array Metadata doesn't set access_flags + } else { + HotSpotVMConfig config = config(); + return UNSAFE.getInt(getKlassPointer() + config.instanceKlassAccessFlagsOffset); + } } public int getMiscFlags() { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index e4e23c6d8b8..c058f785715 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -84,7 +84,6 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { */ final int javaMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle"); - final int klassAccessFlagsOffset = getFieldOffset("Klass::_access_flags", Integer.class, "AccessFlags"); final int klassLayoutHelperOffset = getFieldOffset("Klass::_layout_helper", Integer.class, "jint"); final int klassLayoutHelperNeutralValue = getConstant("Klass::_lh_neutral_value", Integer.class); @@ -93,6 +92,7 @@ class HotSpotVMConfig extends HotSpotVMConfigAccess { final int vtableEntrySize = getFieldValue("CompilerToVM::Data::sizeof_vtableEntry", Integer.class, "int"); final int vtableEntryMethodOffset = getFieldOffset("vtableEntry::_method", Integer.class, "Method*"); + final int instanceKlassAccessFlagsOffset = getFieldOffset("InstanceKlass::_access_flags", Integer.class, "AccessFlags"); final int instanceKlassInitStateOffset = getFieldOffset("InstanceKlass::_init_state", Integer.class, "InstanceKlass::ClassState"); final int instanceKlassConstantsOffset = getFieldOffset("InstanceKlass::_constants", Integer.class, "ConstantPool*"); final int instanceKlassFieldInfoStreamOffset = getFieldOffset("InstanceKlass::_fieldinfo_stream", Integer.class, "Array*"); From 15f25389435288881644f7aeab48fd2eae410999 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Thu, 4 Dec 2025 23:56:20 +0000 Subject: [PATCH 074/141] 8373056: Shenandoah: Remove unnecessary use of ShenandoahAllocRequest.type() Reviewed-by: wkemper, kdnilsen --- .../gc/shenandoah/shenandoahAllocRequest.hpp | 11 ++-- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 12 ++-- .../share/gc/shenandoah/shenandoahHeap.cpp | 14 ++++- .../gc/shenandoah/shenandoahHeapRegion.hpp | 2 +- .../shenandoahHeapRegion.inline.hpp | 30 ++++------ .../gc/shenandoah/shenandoahOldGeneration.cpp | 56 ++++++++----------- 6 files changed, 58 insertions(+), 67 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp index 05ecfb254a2..c667048ad47 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAllocRequest.hpp @@ -83,16 +83,15 @@ public: return "PLAB"; default: ShouldNotReachHere(); - return ""; } } private: // When ShenandoahElasticTLAB is enabled, the request cannot be made smaller than _min_size. - size_t _min_size; + size_t const _min_size; // The size of the request in words. - size_t _requested_size; + size_t const _requested_size; // The allocation may be increased for padding or decreased to fit in the remaining space of a region. size_t _actual_size; @@ -104,7 +103,7 @@ private: size_t _waste; // This is the type of the request. - Type _alloc_type; + Type const _alloc_type; #ifdef ASSERT // Check that this is set before being read. @@ -209,6 +208,10 @@ public: return (_alloc_type & bit_old_alloc) == 0; } + inline bool is_cds() const { + return _alloc_type == _alloc_cds; + } + inline ShenandoahAffiliation affiliation() const { return (_alloc_type & bit_old_alloc) == 0 ? YOUNG_GENERATION : OLD_GENERATION ; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 6a6cad68fd9..eb05bf24028 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -1369,7 +1369,7 @@ template HeapWord* ShenandoahFreeSet::allocate_from_regions(Iter& iterator, ShenandoahAllocRequest &req, bool &in_new_region) { for (idx_t idx = iterator.current(); iterator.has_next(); idx = iterator.next()) { ShenandoahHeapRegion* r = _heap->get_region(idx); - size_t min_size = (req.type() == ShenandoahAllocRequest::_alloc_tlab) ? req.min_size() : req.size(); + size_t min_size = req.is_lab_alloc() ? req.min_size() : req.size(); if (alloc_capacity(r) >= min_size * HeapWordSize) { HeapWord* result = try_allocate_in(r, req, in_new_region); if (result != nullptr) { @@ -1501,7 +1501,7 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah if (in_new_region) { log_debug(gc, free)("Using new region (%zu) for %s (" PTR_FORMAT ").", - r->index(), ShenandoahAllocRequest::alloc_type_to_string(req.type()), p2i(&req)); + r->index(), req.type_string(), p2i(&req)); assert(!r->is_affiliated(), "New region %zu should be unaffiliated", r->index()); r->set_affiliation(req.affiliation()); if (r->is_old()) { @@ -1520,7 +1520,7 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah assert(ctx->is_bitmap_range_within_region_clear(ctx->top_bitmap(r), r->end()), "Bitmap above top_bitmap() must be clear"); #endif log_debug(gc, free)("Using new region (%zu) for %s (" PTR_FORMAT ").", - r->index(), ShenandoahAllocRequest::alloc_type_to_string(req.type()), p2i(&req)); + r->index(), req.type_string(), p2i(&req)); } else { assert(r->is_affiliated(), "Region %zu that is not new should be affiliated", r->index()); if (r->affiliation() != req.affiliation()) { @@ -1534,8 +1534,8 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah if (req.is_lab_alloc()) { size_t adjusted_size = req.size(); size_t free = r->free(); // free represents bytes available within region r - if (req.type() == ShenandoahAllocRequest::_alloc_plab) { - // This is a PLAB allocation + if (req.is_old()) { + // This is a PLAB allocation(lab alloc in old gen) assert(_heap->mode()->is_generational(), "PLABs are only for generational mode"); assert(_partitions.in_free_set(ShenandoahFreeSetPartitionId::OldCollector, r->index()), "PLABS must be allocated in old_collector_free regions"); @@ -1596,8 +1596,6 @@ HeapWord* ShenandoahFreeSet::try_allocate_in(ShenandoahHeapRegion* r, Shenandoah r->set_update_watermark(r->top()); if (r->is_old()) { _partitions.increase_used(ShenandoahFreeSetPartitionId::OldCollector, (req.actual_size() + req.waste()) * HeapWordSize); - assert(req.type() != ShenandoahAllocRequest::_alloc_gclab, "old-gen allocations use PLAB or shared allocation"); - // for plabs, we'll sort the difference between evac and promotion usage when we retire the plab } else { _partitions.increase_used(ShenandoahFreeSetPartitionId::Collector, (req.actual_size() + req.waste()) * HeapWordSize); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 6d569e9b4ce..3bf53f800a2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -985,7 +985,7 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { assert (req.is_lab_alloc() || (requested == actual), "Only LAB allocations are elastic: %s, requested = %zu, actual = %zu", - ShenandoahAllocRequest::alloc_type_to_string(req.type()), requested, actual); + req.type_string(), requested, actual); } return result; @@ -1014,8 +1014,9 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req // Record the plab configuration for this result and register the object. if (result != nullptr && req.is_old()) { - old_generation()->configure_plab_for_current_thread(req); - if (!req.is_lab_alloc()) { + if (req.is_lab_alloc()) { + old_generation()->configure_plab_for_current_thread(req); + } else { // Register the newly allocated object while we're holding the global lock since there's no synchronization // built in to the implementation of register_object(). There are potential races when multiple independent // threads are allocating objects, some of which might span the same card region. For example, consider @@ -1035,6 +1036,13 @@ HeapWord* ShenandoahHeap::allocate_memory_under_lock(ShenandoahAllocRequest& req // last-start representing object b while first-start represents object c. This is why we need to require all // register_object() invocations to be "mutually exclusive" with respect to each card's memory range. old_generation()->card_scan()->register_object(result); + + if (req.is_promotion()) { + // Shared promotion. + const size_t actual_size = req.actual_size() * HeapWordSize; + log_debug(gc, plab)("Expend shared promotion of %zu bytes", actual_size); + old_generation()->expend_promoted(actual_size); + } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index 32382f5e594..2ed5614c698 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -447,7 +447,7 @@ public: return (bottom() <= p) && (p < top()); } - inline void adjust_alloc_metadata(ShenandoahAllocRequest::Type type, size_t); + inline void adjust_alloc_metadata(const ShenandoahAllocRequest &req, size_t); void reset_alloc_metadata(); size_t get_shared_allocs() const; size_t get_tlab_allocs() const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp index 4feeed815da..69673eb7a60 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.inline.hpp @@ -71,7 +71,7 @@ HeapWord* ShenandoahHeapRegion::allocate_aligned(size_t size, ShenandoahAllocReq } make_regular_allocation(req.affiliation()); - adjust_alloc_metadata(req.type(), size); + adjust_alloc_metadata(req, size); HeapWord* new_top = aligned_obj + size; assert(new_top <= end(), "PLAB cannot span end of heap region"); @@ -111,7 +111,7 @@ HeapWord* ShenandoahHeapRegion::allocate(size_t size, const ShenandoahAllocReque HeapWord* obj = top(); if (pointer_delta(end(), obj) >= size) { make_regular_allocation(req.affiliation()); - adjust_alloc_metadata(req.type(), size); + adjust_alloc_metadata(req, size); HeapWord* new_top = obj + size; set_top(new_top); @@ -125,26 +125,16 @@ HeapWord* ShenandoahHeapRegion::allocate(size_t size, const ShenandoahAllocReque } } -inline void ShenandoahHeapRegion::adjust_alloc_metadata(ShenandoahAllocRequest::Type type, size_t size) { - switch (type) { - case ShenandoahAllocRequest::_alloc_shared: - case ShenandoahAllocRequest::_alloc_shared_gc: - case ShenandoahAllocRequest::_alloc_shared_gc_old: - case ShenandoahAllocRequest::_alloc_shared_gc_promotion: - case ShenandoahAllocRequest::_alloc_cds: - // Counted implicitly by tlab/gclab allocs - break; - case ShenandoahAllocRequest::_alloc_tlab: +inline void ShenandoahHeapRegion::adjust_alloc_metadata(const ShenandoahAllocRequest &req, size_t size) { + // Only need to update alloc metadata for lab alloc, shared alloc is counted implicitly by tlab/gclab allocs + if (req.is_lab_alloc()) { + if (req.is_mutator_alloc()) { _tlab_allocs += size; - break; - case ShenandoahAllocRequest::_alloc_gclab: - _gclab_allocs += size; - break; - case ShenandoahAllocRequest::_alloc_plab: + } else if (req.is_old()) { _plab_allocs += size; - break; - default: - ShouldNotReachHere(); + } else { + _gclab_allocs += size; + } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp index 838326c0288..6a0f986cde5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahOldGeneration.cpp @@ -168,7 +168,7 @@ size_t ShenandoahOldGeneration::get_promoted_expended() const { } bool ShenandoahOldGeneration::can_allocate(const ShenandoahAllocRequest &req) const { - assert(req.type() != ShenandoahAllocRequest::_alloc_gclab, "GCLAB pertains only to young-gen memory"); + assert(req.is_old(), "Must be old allocation request"); const size_t requested_bytes = req.size() * HeapWordSize; // The promotion reserve may also be used for evacuations. If we can promote this object, @@ -180,7 +180,7 @@ bool ShenandoahOldGeneration::can_allocate(const ShenandoahAllocRequest &req) co return true; } - if (req.type() == ShenandoahAllocRequest::_alloc_plab) { + if (req.is_lab_alloc()) { // The promotion reserve cannot accommodate this plab request. Check if we still have room for // evacuations. Note that we cannot really know how much of the plab will be used for evacuations, // so here we only check that some evacuation reserve still exists. @@ -195,37 +195,29 @@ bool ShenandoahOldGeneration::can_allocate(const ShenandoahAllocRequest &req) co void ShenandoahOldGeneration::configure_plab_for_current_thread(const ShenandoahAllocRequest &req) { - // Note: Even when a mutator is performing a promotion outside a LAB, we use a 'shared_gc' request. - if (req.is_gc_alloc()) { - const size_t actual_size = req.actual_size() * HeapWordSize; - if (req.type() == ShenandoahAllocRequest::_alloc_plab) { - // We've created a new plab. Now we configure it whether it will be used for promotions - // and evacuations - or just evacuations. - Thread* thread = Thread::current(); - ShenandoahThreadLocalData::reset_plab_promoted(thread); + assert(req.is_gc_alloc() && req.is_old() && req.is_lab_alloc(), "Must be a plab alloc request"); + const size_t actual_size = req.actual_size() * HeapWordSize; + // We've created a new plab. Now we configure it whether it will be used for promotions + // and evacuations - or just evacuations. + Thread* thread = Thread::current(); + ShenandoahThreadLocalData::reset_plab_promoted(thread); - // The actual size of the allocation may be larger than the requested bytes (due to alignment on card boundaries). - // If this puts us over our promotion budget, we need to disable future PLAB promotions for this thread. - if (can_promote(actual_size)) { - // Assume the entirety of this PLAB will be used for promotion. This prevents promotion from overreach. - // When we retire this plab, we'll unexpend what we don't really use. - log_debug(gc, plab)("Thread can promote using PLAB of %zu bytes. Expended: %zu, available: %zu", - actual_size, get_promoted_expended(), get_promoted_reserve()); - expend_promoted(actual_size); - ShenandoahThreadLocalData::enable_plab_promotions(thread); - ShenandoahThreadLocalData::set_plab_actual_size(thread, actual_size); - } else { - // Disable promotions in this thread because entirety of this PLAB must be available to hold old-gen evacuations. - ShenandoahThreadLocalData::disable_plab_promotions(thread); - ShenandoahThreadLocalData::set_plab_actual_size(thread, 0); - log_debug(gc, plab)("Thread cannot promote using PLAB of %zu bytes. Expended: %zu, available: %zu, mixed evacuations? %s", - actual_size, get_promoted_expended(), get_promoted_reserve(), BOOL_TO_STR(ShenandoahHeap::heap()->collection_set()->has_old_regions())); - } - } else if (req.is_promotion()) { - // Shared promotion. - log_debug(gc, plab)("Expend shared promotion of %zu bytes", actual_size); - expend_promoted(actual_size); - } + // The actual size of the allocation may be larger than the requested bytes (due to alignment on card boundaries). + // If this puts us over our promotion budget, we need to disable future PLAB promotions for this thread. + if (can_promote(actual_size)) { + // Assume the entirety of this PLAB will be used for promotion. This prevents promotion from overreach. + // When we retire this plab, we'll unexpend what we don't really use. + log_debug(gc, plab)("Thread can promote using PLAB of %zu bytes. Expended: %zu, available: %zu", + actual_size, get_promoted_expended(), get_promoted_reserve()); + expend_promoted(actual_size); + ShenandoahThreadLocalData::enable_plab_promotions(thread); + ShenandoahThreadLocalData::set_plab_actual_size(thread, actual_size); + } else { + // Disable promotions in this thread because entirety of this PLAB must be available to hold old-gen evacuations. + ShenandoahThreadLocalData::disable_plab_promotions(thread); + ShenandoahThreadLocalData::set_plab_actual_size(thread, 0); + log_debug(gc, plab)("Thread cannot promote using PLAB of %zu bytes. Expended: %zu, available: %zu, mixed evacuations? %s", + actual_size, get_promoted_expended(), get_promoted_reserve(), BOOL_TO_STR(ShenandoahHeap::heap()->collection_set()->has_old_regions())); } } From 7e91d34f3e83b4c39d6ce5de34373d7d74d54512 Mon Sep 17 00:00:00 2001 From: Anjian Wen Date: Fri, 5 Dec 2025 02:51:13 +0000 Subject: [PATCH 075/141] 8365732: RISC-V: implement AES CTR intrinsics Reviewed-by: fyang, mli --- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 229 +++++++++++++++++- src/hotspot/cpu/riscv/vm_version_riscv.cpp | 18 +- 2 files changed, 238 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index dff9a3d508e..d0cbe8ea347 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2493,8 +2493,8 @@ class StubGenerator: public StubCodeGenerator { __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); __ vle32_v(res, from); - __ mv(t2, 52); - __ blt(keylen, t2, L_aes128); + __ mv(t2, 52); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} + __ bltu(keylen, t2, L_aes128); __ beq(keylen, t2, L_aes192); // Else we fallthrough to the biggest case (256-bit key size) @@ -2572,8 +2572,8 @@ class StubGenerator: public StubCodeGenerator { __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); __ vle32_v(res, from); - __ mv(t2, 52); - __ blt(keylen, t2, L_aes128); + __ mv(t2, 52); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} + __ bltu(keylen, t2, L_aes128); __ beq(keylen, t2, L_aes192); // Else we fallthrough to the biggest case (256-bit key size) @@ -2606,6 +2606,223 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Load big-endian 128-bit from memory. + void be_load_counter_128(Register counter_hi, Register counter_lo, Register counter) { + __ ld(counter_lo, Address(counter, 8)); // Load 128-bits from counter + __ ld(counter_hi, Address(counter)); + __ rev8(counter_lo, counter_lo); // Convert big-endian to little-endian + __ rev8(counter_hi, counter_hi); + } + + // Little-endian 128-bit + 64-bit -> 128-bit addition. + void add_counter_128(Register counter_hi, Register counter_lo) { + assert_different_registers(counter_hi, counter_lo, t0); + __ addi(counter_lo, counter_lo, 1); + __ seqz(t0, counter_lo); // Check for result overflow + __ add(counter_hi, counter_hi, t0); // Add 1 if overflow otherwise 0 + } + + // Store big-endian 128-bit to memory. + void be_store_counter_128(Register counter_hi, Register counter_lo, Register counter) { + assert_different_registers(counter_hi, counter_lo, t0, t1); + __ rev8(t0, counter_lo); // Convert little-endian to big-endian + __ rev8(t1, counter_hi); + __ sd(t0, Address(counter, 8)); // Store 128-bits to counter + __ sd(t1, Address(counter)); + } + + void counterMode_AESCrypt(int round, Register in, Register out, Register key, Register counter, + Register input_len, Register saved_encrypted_ctr, Register used_ptr) { + // Algorithm: + // + // generate_aes_loadkeys(); + // load_counter_128(counter_hi, counter_lo, counter); + // + // L_next: + // if (used >= BLOCK_SIZE) goto L_main_loop; + // + // L_encrypt_next: + // *out = *in ^ saved_encrypted_ctr[used]); + // out++; in++; used++; len--; + // if (len == 0) goto L_exit; + // goto L_next; + // + // L_main_loop: + // if (len == 0) goto L_exit; + // saved_encrypted_ctr = generate_aes_encrypt(counter); + // + // add_counter_128(counter_hi, counter_lo); + // be_store_counter_128(counter_hi, counter_lo, counter); + // used = 0; + // + // if(len < BLOCK_SIZE) goto L_encrypt_next; + // + // v_in = load_16Byte(in); + // v_out = load_16Byte(out); + // v_saved_encrypted_ctr = load_16Byte(saved_encrypted_ctr); + // v_out = v_in ^ v_saved_encrypted_ctr; + // out += BLOCK_SIZE; + // in += BLOCK_SIZE; + // len -= BLOCK_SIZE; + // used = BLOCK_SIZE; + // goto L_main_loop; + // + // + // L_exit: + // store(used); + // result = input_len + // return result; + + const Register used = x28; + const Register len = x29; + const Register counter_hi = x30; + const Register counter_lo = x31; + const Register block_size = t2; + + const unsigned int BLOCK_SIZE = 16; + + VectorRegister working_vregs[] = { + v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15 + }; + + __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); + + __ lwu(used, Address(used_ptr)); + __ mv(len, input_len); + __ mv(block_size, BLOCK_SIZE); + + // load keys to working_vregs according to round + generate_aes_loadkeys(key, working_vregs, round); + + // 128-bit big-endian load + be_load_counter_128(counter_hi, counter_lo, counter); + + Label L_next, L_encrypt_next, L_main_loop, L_exit; + // Check the last saved_encrypted_ctr used value, we fall through + // to L_encrypt_next when the used value lower than block_size + __ bind(L_next); + __ bgeu(used, block_size, L_main_loop); + + // There is still data left fewer than block_size after L_main_loop + // or last used, we encrypt them one by one. + __ bind(L_encrypt_next); + __ add(t0, saved_encrypted_ctr, used); + __ lbu(t1, Address(t0)); + __ lbu(t0, Address(in)); + __ xorr(t1, t1, t0); + __ sb(t1, Address(out)); + __ addi(in, in, 1); + __ addi(out, out, 1); + __ addi(used, used, 1); + __ subi(len, len, 1); + __ beqz(len, L_exit); + __ j(L_next); + + // We will calculate the next saved_encrypted_ctr and encrypt the blocks of data + // one by one until there is less than a full block remaining if len not zero + __ bind(L_main_loop); + __ beqz(len, L_exit); + __ vle32_v(v16, counter); + + // encrypt counter according to round + generate_aes_encrypt(v16, working_vregs, round); + + __ vse32_v(v16, saved_encrypted_ctr); + + // 128-bit little-endian increment + add_counter_128(counter_hi, counter_lo); + // 128-bit big-endian store + be_store_counter_128(counter_hi, counter_lo, counter); + + __ mv(used, 0); + // Check if we have a full block_size + __ bltu(len, block_size, L_encrypt_next); + + // We have one full block to encrypt at least + __ vle32_v(v17, in); + __ vxor_vv(v16, v16, v17); + __ vse32_v(v16, out); + __ add(out, out, block_size); + __ add(in, in, block_size); + __ sub(len, len, block_size); + __ mv(used, block_size); + __ j(L_main_loop); + + __ bind(L_exit); + __ sw(used, Address(used_ptr)); + __ mv(x10, input_len); + __ leave(); + __ ret(); + }; + + // CTR AES crypt. + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // c_rarg3 - counter vector byte array address + // c_rarg4 - input length + // c_rarg5 - saved encryptedCounter start + // c_rarg6 - saved used length + // + // Output: + // x10 - input length + // + address generate_counterMode_AESCrypt() { + assert(UseZvkn, "need AES instructions (Zvkned extension) support"); + assert(UseAESCTRIntrinsics, "need AES instructions (Zvkned extension) support"); + assert(UseZbb, "need basic bit manipulation (Zbb extension) support"); + + __ align(CodeEntryAlignment); + StubId stub_id = StubId::stubgen_counterMode_AESCrypt_id; + StubCodeMark mark(this, stub_id); + + const Register in = c_rarg0; + const Register out = c_rarg1; + const Register key = c_rarg2; + const Register counter = c_rarg3; + const Register input_len = c_rarg4; + const Register saved_encrypted_ctr = c_rarg5; + const Register used_len_ptr = c_rarg6; + + const Register keylen = c_rarg7; // temporary register + + const address start = __ pc(); + __ enter(); + + Label L_exit; + __ beqz(input_len, L_exit); + + Label L_aes128, L_aes192; + // Compute #rounds for AES based on the length of the key array + __ lwu(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + __ mv(t0, 52); // key length could be only {11, 13, 15} * 4 = {44, 52, 60} + __ bltu(keylen, t0, L_aes128); + __ beq(keylen, t0, L_aes192); + // Else we fallthrough to the biggest case (256-bit key size) + + // Note: the following function performs crypt with key += 15*16 + counterMode_AESCrypt(15, in, out, key, counter, input_len, saved_encrypted_ctr, used_len_ptr); + + // Note: the following function performs crypt with key += 13*16 + __ bind(L_aes192); + counterMode_AESCrypt(13, in, out, key, counter, input_len, saved_encrypted_ctr, used_len_ptr); + + // Note: the following function performs crypt with key += 11*16 + __ bind(L_aes128); + counterMode_AESCrypt(11, in, out, key, counter, input_len, saved_encrypted_ctr, used_len_ptr); + + __ bind(L_exit); + __ mv(x10, input_len); + __ leave(); + __ ret(); + + return start; + } + // code for comparing 8 characters of strings with Latin1 and Utf16 encoding void compare_string_8_x_LU(Register tmpL, Register tmpU, Register strL, Register strU, Label& DIFF) { @@ -6826,6 +7043,10 @@ static const int64_t right_3_bits = right_n_bits(3); StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); } + if (UseAESCTRIntrinsics) { + StubRoutines::_counterMode_AESCrypt = generate_counterMode_AESCrypt(); + } + if (UsePoly1305Intrinsics) { StubRoutines::_poly1305_processBlocks = generate_poly1305_processBlocks(); } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 6f4babc872f..75605f25759 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -434,6 +434,15 @@ void VM_Version::c2_initialize() { warning("UseAESIntrinsics enabled, but UseAES not, enabling"); UseAES = true; } + + if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics) && UseZbb) { + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true); + } + + if (UseAESCTRIntrinsics && !UseZbb) { + warning("Cannot enable UseAESCTRIntrinsics on cpu without UseZbb support."); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } } else { if (UseAES) { warning("AES instructions are not available on this CPU"); @@ -443,11 +452,10 @@ void VM_Version::c2_initialize() { warning("AES intrinsics are not available on this CPU"); FLAG_SET_DEFAULT(UseAESIntrinsics, false); } - } - - if (UseAESCTRIntrinsics) { - warning("AES/CTR intrinsics are not available on this CPU"); - FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + if (UseAESCTRIntrinsics) { + warning("Cannot enable UseAESCTRIntrinsics on cpu without UseZvkn support."); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } } } From 674cc3eeca77f1f2a6d937b1df5c5cd8a13c2d31 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 5 Dec 2025 03:30:31 +0000 Subject: [PATCH 076/141] 8042054: JTree.updateUI uses out-of-date item size information Reviewed-by: dnguyen, serb --- .../share/classes/javax/swing/JTree.java | 6 +- .../javax/swing/JTree/JTreeUpdateTest.java | 96 +++++++++++++++++++ 2 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 test/jdk/javax/swing/JTree/JTreeUpdateTest.java diff --git a/src/java.desktop/share/classes/javax/swing/JTree.java b/src/java.desktop/share/classes/javax/swing/JTree.java index c081b3cfff8..622c55e2ede 100644 --- a/src/java.desktop/share/classes/javax/swing/JTree.java +++ b/src/java.desktop/share/classes/javax/swing/JTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, 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 @@ -777,10 +777,10 @@ public class JTree extends JComponent implements Scrollable, Accessible updateInProgress = true; try { - setUI((TreeUI)UIManager.getUI(this)); - SwingUtilities.updateRendererOrEditorUI(getCellRenderer()); SwingUtilities.updateRendererOrEditorUI(getCellEditor()); + + setUI((TreeUI)UIManager.getUI(this)); } finally { updateInProgress = false; } diff --git a/test/jdk/javax/swing/JTree/JTreeUpdateTest.java b/test/jdk/javax/swing/JTree/JTreeUpdateTest.java new file mode 100644 index 00000000000..6b0a4f03c29 --- /dev/null +++ b/test/jdk/javax/swing/JTree/JTreeUpdateTest.java @@ -0,0 +1,96 @@ +/* + * 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 8042054 + * @summary JTree.updateUI should use updated item size information + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual JTreeUpdateTest + */ + +import java.awt.BorderLayout; +import java.awt.Dimension; +import javax.swing.BorderFactory; +import javax.swing.JFrame; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.UIManager; + +public class JTreeUpdateTest { + + static final String INSTRUCTIONS = """ + A frame with two identical JTrees is shown. + If the left JTree's text is abbreviated and JTree items + are cramped with little space between rows then press Fail. + If the left JTree is identical with right JTree, press Pass. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("JTreeUpdateTest Test instructions") + .instructions(INSTRUCTIONS) + .columns(30) + .testUI(JTreeUpdateTest::createUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createUI() { + setLaf("javax.swing.plaf.metal.MetalLookAndFeel"); + + final JFrame frame = new JFrame("JTreeUpdateTest"); + + final JTree tree = new JTree(); + tree.setPreferredSize(new Dimension(200, 200)); + tree.setCellRenderer(new DefaultTreeCellRenderer()); + tree.setBorder(BorderFactory.createTitledBorder("updateUI() called once")); + frame.add(tree); + + final JTree tree2 = new JTree(); + tree2.setPreferredSize(new Dimension(200, 200)); + tree2.setCellRenderer(new DefaultTreeCellRenderer()); + tree2.setBorder(BorderFactory.createTitledBorder("updateUI() called twice")); + frame.add(tree2, BorderLayout.EAST); + + frame.pack(); + frame.setLocationRelativeTo(null); + + SwingUtilities.invokeLater(() -> { + setLaf("javax.swing.plaf.nimbus.NimbusLookAndFeel"); + SwingUtilities.updateComponentTreeUI(frame); + SwingUtilities.updateComponentTreeUI(tree2); + }); + return frame; + } + + private static void setLaf(String className) { + try { + UIManager.setLookAndFeel(className); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} From c09167df60f44642492ec20f133713388f4802ad Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 5 Dec 2025 14:01:36 +0000 Subject: [PATCH 077/141] 8373113: Fix whitespace in RunTests.gmk Reviewed-by: tbell --- make/RunTests.gmk | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index 1f50b97531b..946b1332edc 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -873,7 +873,7 @@ define SetupRunJtregTestBody $1_JTREG_BASIC_OPTIONS += -testThreadFactoryPath:$$(JTREG_TEST_THREAD_FACTORY_JAR) $1_JTREG_BASIC_OPTIONS += -testThreadFactory:$$(JTREG_TEST_THREAD_FACTORY) $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ - $$(addprefix $$($1_TEST_ROOT)/, ProblemList-$$(JTREG_TEST_THREAD_FACTORY).txt) \ + $$(addprefix $$($1_TEST_ROOT)/, ProblemList-$$(JTREG_TEST_THREAD_FACTORY).txt) \ )) endif @@ -881,8 +881,8 @@ define SetupRunJtregTestBody AGENT := $$(LIBRARY_PREFIX)JvmtiStressAgent$$(SHARED_LIBRARY_SUFFIX)=$$(JTREG_JVMTI_STRESS_AGENT) $1_JTREG_BASIC_OPTIONS += -javaoption:'-agentpath:$(TEST_IMAGE_DIR)/hotspot/jtreg/native/$$(AGENT)' $1_JTREG_BASIC_OPTIONS += $$(addprefix $$(JTREG_PROBLEM_LIST_PREFIX), $$(wildcard \ - $$(addprefix $$($1_TEST_ROOT)/, ProblemList-jvmti-stress-agent.txt) \ - )) + $$(addprefix $$($1_TEST_ROOT)/, ProblemList-jvmti-stress-agent.txt) \ + )) endif @@ -1092,7 +1092,7 @@ define SetupRunJtregTestBody $$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR) \ $$($1_TEST_TMP_DIR)) $$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/jtreg, \ - $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ + $$(COV_ENVIRONMENT) $$($1_COMMAND_LINE) \ ) $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt @@ -1102,11 +1102,11 @@ define SetupRunJtregTestBody $$(call LogWarn, Test report is stored in $$(strip \ $$(subst $$(TOPDIR)/, , $$($1_TEST_RESULTS_DIR)))) - # Read jtreg documentation to learn on the test stats categories: - # https://github.com/openjdk/jtreg/blob/master/src/share/doc/javatest/regtest/faq.md#what-do-all-those-numbers-in-the-test-results-line-mean - # In jtreg, "skipped:" category accounts for tests that threw jtreg.SkippedException at runtime. - # At the same time these tests contribute to "passed:" tests. - # In here we don't want that and so we substract number of "skipped:" from "passed:". + # Read jtreg documentation to learn on the test stats categories: + # https://github.com/openjdk/jtreg/blob/master/src/share/doc/javatest/regtest/faq.md#what-do-all-those-numbers-in-the-test-results-line-mean + # In jtreg, "skipped:" category accounts for tests that threw jtreg.SkippedException at runtime. + # At the same time these tests contribute to "passed:" tests. + # In here we don't want that and so we substract number of "skipped:" from "passed:". $$(if $$(wildcard $$($1_RESULT_FILE)), \ $$(eval $1_PASSED_AND_RUNTIME_SKIPPED := $$(shell $$(AWK) '{ gsub(/[,;]/, ""); \ From ee0b8a72c64f7ac5058dbe5b2062cb35b6195484 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 5 Dec 2025 15:39:49 +0000 Subject: [PATCH 078/141] 8373102: com/sun/jdi/MethodInvokeWithTraceOnTest.java can fail with ObjectCollectedException when run with a small heap Reviewed-by: amenkov, sspitsyn --- .../com/sun/tools/jdi/EventSetImpl.java | 20 ++++++++++++++++--- test/jdk/ProblemList.txt | 1 - 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java index 19e8b45c491..9a13eb3dca5 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.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 @@ -37,6 +37,7 @@ import com.sun.jdi.InternalException; import com.sun.jdi.Locatable; import com.sun.jdi.Location; import com.sun.jdi.Method; +import com.sun.jdi.ObjectCollectedException; import com.sun.jdi.ObjectReference; import com.sun.jdi.ReferenceType; import com.sun.jdi.ThreadReference; @@ -206,6 +207,19 @@ public class EventSetImpl extends ArrayList implements EventSet { } + /* Safely fetch the thread name in case there is an ObjectCollectedException. + * This can happen when dealing with SUSPEND_NONE events. + */ + private static String getThreadName(ThreadReference thread) { + String name; + try { + name = thread.name(); + } catch (ObjectCollectedException oce) { + name = ""; + } + return name; + } + abstract class ThreadedEventImpl extends EventImpl { private ThreadReference thread; @@ -220,7 +234,7 @@ public class EventSetImpl extends ArrayList implements EventSet { } public String toString() { - return eventName() + " in thread " + thread.name(); + return eventName() + " in thread " + getThreadName(thread); } } @@ -249,7 +263,7 @@ public class EventSetImpl extends ArrayList implements EventSet { public String toString() { return eventName() + "@" + ((location() == null) ? " null" : location().toString()) + - " in thread " + thread().name(); + " in thread " + getThreadName(thread()); } } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 814fd2caae9..0076b1cf891 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -716,7 +716,6 @@ javax/swing/plaf/synth/7158712/bug7158712.java 8324782 macosx-all # jdk_jdi com/sun/jdi/InvokeHangTest.java 8218463 linux-all -com/sun/jdi/MethodInvokeWithTraceOnTest.java 8373022 generic-all ############################################################################ From 4d696d0d0ed523e3c99c68214586673913b1c7b5 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 5 Dec 2025 15:46:07 +0000 Subject: [PATCH 079/141] 8373086: Make isexceeded001.java more robust Reviewed-by: jsikstro, tschatzl --- test/hotspot/jtreg/ProblemList.txt | 6 ------ .../isUsageThresholdExceeded/isexceeded001.java | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 6c3d907961d..ddc6e55dc05 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -187,9 +187,3 @@ 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 - -vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001/TestDescription.java 8373022 generic-all -vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded002/TestDescription.java 8373022 generic-all -vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded003/TestDescription.java 8373022 generic-all -vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded004/TestDescription.java 8373022 generic-all -vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded005/TestDescription.java 8373022 generic-all diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java index a684c03e67a..5fbb4d2444e 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java @@ -92,7 +92,8 @@ public class isexceeded001 { // but cannot assume this affects the pool we are testing. b = new byte[INCREMENT]; - isExceeded = monitor.isUsageThresholdExceeded(pool); + // Ensure the observation of isExceeded is sticky to match peakUsage. + isExceeded = isExceeded || monitor.isUsageThresholdExceeded(pool); log.display(" Allocated heap. isExceeded = " + isExceeded); // Fetch usage information: use peak usage in comparisons below, in case usage went up and then down. From 520c092a658559a5d65f06a51061db3aae09931e Mon Sep 17 00:00:00 2001 From: Neha Joshi Date: Fri, 5 Dec 2025 16:46:26 +0000 Subject: [PATCH 080/141] 8362658: sun/security/ssl/SSLEngineImpl/* tests duplicate jvm flags Co-authored-by: Lei Zhu Reviewed-by: myankelevich, rhalade --- test/jdk/ProblemList-jvmti-stress-agent.txt | 16 ---------------- .../ssl/SSLEngineImpl/SSLEngineKeyLimit.java | 5 +---- .../ssl/SSLSessionImpl/MultiNSTClient.java | 4 +--- .../MultiNSTNoSessionCreation.java | 3 +-- .../ssl/SSLSessionImpl/MultiNSTParallel.java | 4 +--- .../ssl/SSLSessionImpl/MultiNSTSequence.java | 4 +--- .../ResumptionUpdateBoundValues.java | 3 +-- .../ssl/SSLSocketImpl/SSLSocketKeyLimit.java | 4 +--- 8 files changed, 7 insertions(+), 36 deletions(-) diff --git a/test/jdk/ProblemList-jvmti-stress-agent.txt b/test/jdk/ProblemList-jvmti-stress-agent.txt index 4a6e80a9402..09be19c3d94 100644 --- a/test/jdk/ProblemList-jvmti-stress-agent.txt +++ b/test/jdk/ProblemList-jvmti-stress-agent.txt @@ -21,22 +21,6 @@ # questions. # -############################################################################# -# -# List of quarantined tests failing with jvmti stress agent in any mode. -# -############################################################################# - - -sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTClient.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java 8362658 generic-all -sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java 8362658 generic-all -sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java 8362658 generic-all - - # List of tests incompatible with jvmti stress agent or requiring more investigation com/sun/jdi/EATests.java#id0 0000000 generic-all diff --git a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java index 65311e97701..5a704ef4d1f 100644 --- a/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java +++ b/test/jdk/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java @@ -60,7 +60,6 @@ import java.util.Arrays; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.process.OutputAnalyzer; -import jdk.test.lib.Utils; public class SSLEngineKeyLimit extends SSLContextTemplate { @@ -119,9 +118,7 @@ public class SSLEngineKeyLimit extends SSLContextTemplate { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("SSLEngineKeyLimit", "p", args[1], - args[2])); - + "SSLEngineKeyLimit", "p", args[1], args[2]); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { output.shouldContain(String.format( diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java index d6cdbf2e015..1c9c259c38d 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java @@ -37,7 +37,6 @@ * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.2 -Djdk.tls.server.enableSessionTicketExtension=true -Djdk.tls.client.enableSessionTicketExtension=true */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -77,8 +76,7 @@ public class MultiNSTClient { System.out.println("test.java.opts: " + System.getProperty("test.java.opts")); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTClient", "p")); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("MultiNSTClient", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); boolean pass = true; diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java index 41f6ec0ada4..a851a5d72bb 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java @@ -31,7 +31,6 @@ * @run main/othervm MultiNSTNoSessionCreation -Djdk.tls.client.protocols=TLSv1.2 -Djdk.tls.server.newSessionTicketCount=0 */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -61,7 +60,7 @@ public class MultiNSTNoSessionCreation { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTNoSessionCreation", "p")); + "MultiNSTNoSessionCreation", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java index 32ee7db7b4b..a2609130e0b 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java @@ -30,7 +30,6 @@ * @run main/othervm MultiNSTParallel 10 -Djdk.tls.client.protocols=TLSv1.3 */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -116,8 +115,7 @@ public class MultiNSTParallel { System.out.println("test.java.opts: " + System.getProperty("test.java.opts")); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTParallel", "p")); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("MultiNSTParallel", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java index 125b006055b..b63ebc5ec1e 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java @@ -30,7 +30,6 @@ * @run main/othervm MultiNSTSequence -Djdk.tls.server.newSessionTicketCount=2 */ -import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -69,8 +68,7 @@ public class MultiNSTSequence { System.out.println("test.java.opts: " + System.getProperty("test.java.opts")); - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("MultiNSTSequence", "p")); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("MultiNSTSequence", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); boolean pass = true; diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java index 87db7eed296..2784875d426 100644 --- a/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/ResumptionUpdateBoundValues.java @@ -45,7 +45,6 @@ import javax.net.ssl.SSLSocketFactory; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Utils; public class ResumptionUpdateBoundValues extends SSLContextTemplate { @@ -188,7 +187,7 @@ public class ResumptionUpdateBoundValues extends SSLContextTemplate { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("ResumptionUpdateBoundValues", "p")); + "ResumptionUpdateBoundValues", "p"); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java index fc26b60e4d4..7ce4d97a7a2 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java @@ -68,7 +68,6 @@ import java.util.Arrays; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Utils; import jdk.test.lib.hexdump.HexPrinter; public class SSLSocketKeyLimit { @@ -135,8 +134,7 @@ public class SSLSocketKeyLimit { System.getProperty("test.java.opts")); ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( - Utils.addTestJavaOpts("SSLSocketKeyLimit", "p", args[1], - args[2])); + "SSLSocketKeyLimit", "p", args[1], args[2]); OutputAnalyzer output = ProcessTools.executeProcess(pb); try { From a20b7eb943c19f9852bfaaec1fbbff647f1f5273 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 5 Dec 2025 17:35:30 +0000 Subject: [PATCH 081/141] 8373125: Add defensive screening of modifiers for Field and Parameter toString() results Reviewed-by: alanb, liach --- .../classes/java/lang/reflect/Field.java | 4 +- .../classes/java/lang/reflect/Parameter.java | 2 +- .../lang/reflect/Modifier/toStringTest.java | 63 ++++++++++++++----- 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/java/lang/reflect/Field.java b/src/java.base/share/classes/java/lang/reflect/Field.java index 663e3453343..a4f0afa0199 100644 --- a/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/src/java.base/share/classes/java/lang/reflect/Field.java @@ -367,7 +367,7 @@ class Field extends AccessibleObject implements Member { * @jls 8.3.1 Field Modifiers */ public String toString() { - int mod = getModifiers(); + int mod = getModifiers() & Modifier.fieldModifiers(); return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) + getType().getTypeName() + " " + getDeclaringClass().getTypeName() + "." @@ -400,7 +400,7 @@ class Field extends AccessibleObject implements Member { * @jls 8.3.1 Field Modifiers */ public String toGenericString() { - int mod = getModifiers(); + int mod = getModifiers() & Modifier.fieldModifiers(); Type fieldType = getGenericType(); return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) + fieldType.getTypeName() + " " diff --git a/src/java.base/share/classes/java/lang/reflect/Parameter.java b/src/java.base/share/classes/java/lang/reflect/Parameter.java index d4a53e193a9..8ecf8060615 100644 --- a/src/java.base/share/classes/java/lang/reflect/Parameter.java +++ b/src/java.base/share/classes/java/lang/reflect/Parameter.java @@ -126,7 +126,7 @@ public final class Parameter implements AnnotatedElement { final Type type = getParameterizedType(); final String typename = type.getTypeName(); - sb.append(Modifier.toString(getModifiers())); + sb.append(Modifier.toString(getModifiers() & Modifier.parameterModifiers() )); if(0 != modifiers) sb.append(' '); diff --git a/test/jdk/java/lang/reflect/Modifier/toStringTest.java b/test/jdk/java/lang/reflect/Modifier/toStringTest.java index 85bceb48339..f36d83f1ad8 100644 --- a/test/jdk/java/lang/reflect/Modifier/toStringTest.java +++ b/test/jdk/java/lang/reflect/Modifier/toStringTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,36 +23,71 @@ /** * @test - * @bug 4394937 8051382 + * @bug 4394937 8051382 8373125 * @summary tests the toString method of reflect.Modifier */ import java.lang.reflect.Modifier; +import static java.lang.reflect.Modifier.*; public class toStringTest { static void testString(int test, String expected) { - if(!Modifier.toString(test).equals(expected)) - throw new RuntimeException(test + - " yields incorrect toString result"); + String result = Modifier.toString(test); + if(!expected.equals(result)) { + System.err.println("For input 0x" + Integer.toHexString(test)); + System.err.println("expected:\t" + expected + "\ngot\t\t" + result); + + throw new RuntimeException(); + } } - public static void main(String [] argv) { - int allMods = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE | - Modifier.ABSTRACT | Modifier.STATIC | Modifier.FINAL | - Modifier.TRANSIENT | Modifier.VOLATILE | Modifier.SYNCHRONIZED | - Modifier.NATIVE | Modifier.STRICT | Modifier.INTERFACE; + public static void main(String... argv) { + int allMods = PUBLIC | PROTECTED | PRIVATE | + ABSTRACT | STATIC | FINAL | + TRANSIENT | VOLATILE | SYNCHRONIZED | + NATIVE | STRICT | INTERFACE; String allModsString = "public protected private abstract static " + "final transient volatile synchronized native strictfp interface"; - /* zero should have an empty string */ + final int ALL_ONES = ~0; + + // zero should have an empty string testString(0, ""); - /* test to make sure all modifiers print out in the proper order */ + // test to make sure all modifiers print out in the proper order testString(allMods, allModsString); - /* verify no extraneous modifiers are printed */ - testString(~0, allModsString); + // verify no extraneous modifiers are printed + testString(ALL_ONES, allModsString); + + ModifierKindCase[] kindModifiers = { + new ModifierKindCase(classModifiers(), + "public protected private abstract " + + "static final strictfp"), + + new ModifierKindCase(constructorModifiers(),"public protected private"), + + new ModifierKindCase(fieldModifiers(), + "public protected private " + + "static final transient volatile"), + + new ModifierKindCase(interfaceModifiers(), + "public protected private " + + "abstract static strictfp"), + + new ModifierKindCase(methodModifiers(), + "public protected private abstract " + + "static final synchronized native strictfp"), + + new ModifierKindCase(parameterModifiers(), "final"), + }; + + for (var modKindCase : kindModifiers) { + testString(ALL_ONES & modKindCase.mask(), modKindCase.expected()); + } } + + private record ModifierKindCase(int mask, String expected){} } From 43787890291d71de61b28b8a4e3bf9aaba46757a Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 5 Dec 2025 19:17:45 +0000 Subject: [PATCH 082/141] 8373145: [BACKOUT] Remove ThreadLocalAllocBuffer::_reserve_for_allocation_prefetch Reviewed-by: mdoerr, kvn --- src/hotspot/cpu/ppc/ppc.ad | 29 +++++++++++++++++++ .../gc/shared/threadLocalAllocBuffer.cpp | 28 +++++++++++++++++- .../gc/shared/threadLocalAllocBuffer.hpp | 1 + src/hotspot/share/opto/macro.cpp | 3 +- src/hotspot/share/runtime/vmStructs.cpp | 1 + .../runtime/ThreadLocalAllocBuffer.java | 3 +- .../classes/sun/jvm/hotspot/runtime/VM.java | 7 +++++ 7 files changed, 69 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index aa00609094e..2a0a9149bb3 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -6335,8 +6335,36 @@ instruct loadConD_Ex(regD dst, immD src) %{ // Prefetch instructions. // Must be safe to execute with invalid address (cannot fault). +// Special prefetch versions which use the dcbz instruction. +instruct prefetch_alloc_zero(indirectMemory mem, iRegLsrc src) %{ + match(PrefetchAllocation (AddP mem src)); + predicate(AllocatePrefetchStyle == 3); + ins_cost(MEMORY_REF_COST); + + format %{ "PREFETCH $mem, 2, $src \t// Prefetch write-many with zero" %} + size(4); + ins_encode %{ + __ dcbz($src$$Register, $mem$$base$$Register); + %} + ins_pipe(pipe_class_memory); +%} + +instruct prefetch_alloc_zero_no_offset(indirectMemory mem) %{ + match(PrefetchAllocation mem); + predicate(AllocatePrefetchStyle == 3); + ins_cost(MEMORY_REF_COST); + + format %{ "PREFETCH $mem, 2 \t// Prefetch write-many with zero" %} + size(4); + ins_encode %{ + __ dcbz($mem$$base$$Register); + %} + ins_pipe(pipe_class_memory); +%} + instruct prefetch_alloc(indirectMemory mem, iRegLsrc src) %{ match(PrefetchAllocation (AddP mem src)); + predicate(AllocatePrefetchStyle != 3); ins_cost(MEMORY_REF_COST); format %{ "PREFETCH $mem, 2, $src \t// Prefetch write-many" %} @@ -6349,6 +6377,7 @@ instruct prefetch_alloc(indirectMemory mem, iRegLsrc src) %{ instruct prefetch_alloc_no_offset(indirectMemory mem) %{ match(PrefetchAllocation mem); + predicate(AllocatePrefetchStyle != 3); ins_cost(MEMORY_REF_COST); format %{ "PREFETCH $mem, 2 \t// Prefetch write-many" %} diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp index 2181e089663..9635ed4d0cb 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp @@ -37,6 +37,7 @@ #include "utilities/copy.hpp" size_t ThreadLocalAllocBuffer::_max_size = 0; +int ThreadLocalAllocBuffer::_reserve_for_allocation_prefetch = 0; unsigned int ThreadLocalAllocBuffer::_target_refills = 0; ThreadLocalAllocBuffer::ThreadLocalAllocBuffer() : @@ -224,6 +225,30 @@ void ThreadLocalAllocBuffer::startup_initialization() { // abort during VM initialization. _target_refills = MAX2(_target_refills, 2U); +#ifdef COMPILER2 + // If the C2 compiler is present, extra space is needed at the end of + // TLABs, otherwise prefetching instructions generated by the C2 + // compiler will fault (due to accessing memory outside of heap). + // The amount of space is the max of the number of lines to + // prefetch for array and for instance allocations. (Extra space must be + // reserved to accommodate both types of allocations.) + // + // Only SPARC-specific BIS instructions are known to fault. (Those + // instructions are generated if AllocatePrefetchStyle==3 and + // AllocatePrefetchInstr==1). To be on the safe side, however, + // extra space is reserved for all combinations of + // AllocatePrefetchStyle and AllocatePrefetchInstr. + // + // If the C2 compiler is not present, no space is reserved. + + // +1 for rounding up to next cache line, +1 to be safe + if (CompilerConfig::is_c2_or_jvmci_compiler_enabled()) { + int lines = MAX2(AllocatePrefetchLines, AllocateInstancePrefetchLines) + 2; + _reserve_for_allocation_prefetch = (AllocatePrefetchDistance + AllocatePrefetchStepSize * lines) / + (int)HeapWordSize; + } +#endif + // During jvm startup, the main thread is initialized // before the heap is initialized. So reinitialize it now. guarantee(Thread::current()->is_Java_thread(), "tlab initialization thread not Java thread"); @@ -429,7 +454,8 @@ void ThreadLocalAllocStats::publish() { } size_t ThreadLocalAllocBuffer::end_reserve() { - return CollectedHeap::lab_alignment_reserve(); + size_t reserve_size = CollectedHeap::lab_alignment_reserve(); + return MAX2(reserve_size, (size_t)_reserve_for_allocation_prefetch); } const HeapWord* ThreadLocalAllocBuffer::start_relaxed() const { diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp index b64fa8d6ad1..59979646395 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.hpp @@ -58,6 +58,7 @@ private: size_t _allocated_before_last_gc; // total bytes allocated up until the last gc static size_t _max_size; // maximum size of any TLAB + static int _reserve_for_allocation_prefetch; // Reserve at the end of the TLAB static unsigned _target_refills; // expected number of refills between GCs unsigned _number_of_refills; diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 6f2171bbd75..90602bc2b35 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -1914,7 +1914,8 @@ Node* PhaseMacroExpand::prefetch_allocation(Node* i_o, Node*& needgc_false, transform_later(cache_adr); cache_adr = new CastP2XNode(needgc_false, cache_adr); transform_later(cache_adr); - // Address is aligned to execute prefetch to the beginning of cache line size. + // Address is aligned to execute prefetch to the beginning of cache line size + // (it is important when BIS instruction is used on SPARC as prefetch). Node* mask = _igvn.MakeConX(~(intptr_t)(step_size-1)); cache_adr = new AndXNode(cache_adr, mask); transform_later(cache_adr); diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 50748fd7e45..4ecc8f9ca01 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -353,6 +353,7 @@ nonstatic_field(ThreadLocalAllocBuffer, _pf_top, HeapWord*) \ nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \ + static_field(ThreadLocalAllocBuffer, _reserve_for_allocation_prefetch, int) \ static_field(ThreadLocalAllocBuffer, _target_refills, unsigned) \ nonstatic_field(ThreadLocalAllocBuffer, _number_of_refills, unsigned) \ nonstatic_field(ThreadLocalAllocBuffer, _refill_waste, unsigned) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java index e23e63806bd..1dc67330d3d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ThreadLocalAllocBuffer.java @@ -76,9 +76,10 @@ public class ThreadLocalAllocBuffer extends VMObject { private long endReserve() { long labAlignmentReserve = VM.getVM().getLabAlignmentReserve(); + long reserveForAllocationPrefetch = VM.getVM().getReserveForAllocationPrefetch(); long heapWordSize = VM.getVM().getHeapWordSize(); - return labAlignmentReserve * heapWordSize; + return Math.max(labAlignmentReserve, reserveForAllocationPrefetch) * heapWordSize; } /** Support for iteration over heap -- not sure how this will diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index 1607563150a..dc27a4fc59e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -123,6 +123,7 @@ public class VM { private int invocationEntryBCI; private ReversePtrs revPtrs; private VMRegImpl vmregImpl; + private int reserveForAllocationPrefetch; private int labAlignmentReserve; // System.getProperties from debuggee VM @@ -446,6 +447,8 @@ public class VM { boolType = (CIntegerType) db.lookupType("bool"); Type threadLocalAllocBuffer = db.lookupType("ThreadLocalAllocBuffer"); + CIntegerField reserveForAllocationPrefetchField = threadLocalAllocBuffer.getCIntegerField("_reserve_for_allocation_prefetch"); + reserveForAllocationPrefetch = (int)reserveForAllocationPrefetchField.getCInteger(intType); Type collectedHeap = db.lookupType("CollectedHeap"); CIntegerField labAlignmentReserveField = collectedHeap.getCIntegerField("_lab_alignment_reserve"); @@ -912,6 +915,10 @@ public class VM { return vmInternalInfo; } + public int getReserveForAllocationPrefetch() { + return reserveForAllocationPrefetch; + } + public int getLabAlignmentReserve() { return labAlignmentReserve; } From f3dd8daaa92896be51254e5abf3e0ec5b1ff5173 Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Fri, 5 Dec 2025 19:30:04 +0000 Subject: [PATCH 083/141] 8371748: Remove the (empty) ThreadPoolExecutor.finalize() method Reviewed-by: vklang, jpai, alanb --- .../util/concurrent/ThreadPoolExecutor.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java index 029e31ef9f6..b45b6eac83e 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java @@ -1426,23 +1426,6 @@ public class ThreadPoolExecutor extends AbstractExecutorService { } } - // Override without "throws Throwable" for compatibility with subclasses - // whose finalize method invokes super.finalize() (as is recommended). - // Before JDK 11, finalize() had a non-empty method body. - - /** - * @implNote Previous versions of this class had a finalize method - * that shut down this executor, but in this version, finalize - * does nothing. - * - * @deprecated Finalization has been deprecated for removal. See - * {@link java.lang.Object#finalize} for background information and details - * about migration options. - */ - @Deprecated(since="9", forRemoval=true) - @SuppressWarnings("removal") - protected void finalize() {} - /** * Sets the thread factory used to create new threads. * From be8cbfa6129d19403c9871c22721b902856f1886 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 5 Dec 2025 20:37:10 +0000 Subject: [PATCH 084/141] 8362083: JDI VirtualMachine/dispose/dispose001 failed with FATAL ERROR in native method: JDWP cannot set thread local storage, jvmtiError=JVMTI_ERROR_WRONG_PHASE(112) Reviewed-by: lmesnik, sspitsyn, amenkov --- src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 734dd5eb7dc..8a02f3f9ee9 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -170,6 +170,10 @@ setThreadLocalStorage(jthread thread, ThreadNode *node) return; } } + if (error == JVMTI_ERROR_WRONG_PHASE && gdata->vmDead && isVThread(thread)) { + // Just return. This can happen with vthreads when the vm is exiting. + return; + } if (error != JVMTI_ERROR_NONE) { // The jthread object must be valid, so this must be a fatal error. EXIT_ERROR(error, "cannot set thread local storage"); From 2596608ba1bb1b271dfa062bf732a5095e22fffd Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Fri, 5 Dec 2025 21:20:20 +0000 Subject: [PATCH 085/141] 8370846: Support execution of mlvm testing with test thread factory Reviewed-by: cjplummer --- .../vm/mlvm/share/jdi/JDIBreakpointTest.java | 17 +++++++++++-- .../test/lib/thread/TestThreadFactory.java | 25 ++++++++++++++++--- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java index 29980ac2117..2b3f5a479b6 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/jdi/JDIBreakpointTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, 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 @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import jdk.test.lib.thread.TestThreadFactory; import nsk.share.jdi.Binder; import nsk.share.jdi.Debugee; import vm.mlvm.share.Env; @@ -437,10 +438,22 @@ public abstract class JDIBreakpointTest extends MlvmTest { for (StackFrame f : frames) { Location l = f.location(); + String sourcePath; + try { + sourcePath = l.sourcePath(); + } catch (AbsentInformationException aie) { + // Test Thread Factory support has generated methods in MainWrapper class. + if (TestThreadFactory.isTestThreadFactorySet()) { + sourcePath = "unknown"; + } else { + throw aie; + } + } + buf.append(String.format("#%-4d", frameNum)) .append(l.method()) .append("\n source: ") - .append(l.sourcePath()) + .append(sourcePath) .append(":") .append(l.lineNumber()) .append("; bci=") diff --git a/test/lib/jdk/test/lib/thread/TestThreadFactory.java b/test/lib/jdk/test/lib/thread/TestThreadFactory.java index ac5a6b74909..043c96cf284 100644 --- a/test/lib/jdk/test/lib/thread/TestThreadFactory.java +++ b/test/lib/jdk/test/lib/thread/TestThreadFactory.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 @@ -32,8 +32,27 @@ import java.util.concurrent.ThreadFactory; public class TestThreadFactory { - private static ThreadFactory threadFactory = "Virtual".equals(System.getProperty("test.thread.factory")) - ? virtualThreadFactory() : platformThreadFactory(); + public enum TestThreadFactoryType { + NONE, VIRTUAL + } + + private final static TestThreadFactoryType testThreadFactoryType = + "Virtual".equals(System.getProperty("test.thread.factory")) + ? TestThreadFactoryType.VIRTUAL + : TestThreadFactoryType.NONE; + + private final static ThreadFactory threadFactory = + testThreadFactoryType == TestThreadFactoryType.VIRTUAL + ? virtualThreadFactory() + : platformThreadFactory(); + + public static TestThreadFactoryType testThreadFactoryType() { + return testThreadFactoryType; + } + + public static boolean isTestThreadFactorySet() { + return !testThreadFactoryType.equals(TestThreadFactoryType.NONE); + } public static Thread newThread(Runnable task) { return threadFactory.newThread(task); From b0f59f6021a00dc569e08810b34db21553a5b68d Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Sat, 6 Dec 2025 00:02:51 +0000 Subject: [PATCH 086/141] 8373127: Update nsk/monitoring tests to support virtual thread factory testing Reviewed-by: kevinw, amenkov --- .../from/from001/TestDescription.java | 3 +- .../from_c/from_c001/TestDescription.java | 3 +- .../getlockname001/TestDescription.java | 3 +- .../getlockownername001/TestDescription.java | 3 +- .../isinnative001/TestDescription.java | 3 +- .../BaseBehaviorTest.java | 70 +++++++++++++------ .../GetThreadCpuTime/BaseBehaviorTest.java | 42 +++++++---- 7 files changed, 87 insertions(+), 40 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java index a066b636bb3..083e91243e8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryUsage/from/from001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ * 5014783 Move ThreadState class from java.lang.management to java.lang * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.MemoryUsage.from.from001 -testMode=server diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java index 9ff6e066fe1..6483673deef 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/from_c/from_c001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,6 +43,7 @@ * 5014783 Move ThreadState class from java.lang.management to java.lang * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.from_c.from_c001 -testMode=server -MBeanServer=custom diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java index 571f121beac..8e956e98929 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockName/getlockname001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,7 @@ * Updated according to: * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.getLockName.getlockname001 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java index 1b2e7d90eb2..0cc78a6ad97 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/getLockOwnerName/getlockownername001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,7 @@ * Updated according to: * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.getLockOwnerName.getlockownername001 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java index a411958c852..3cce37baa4d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadInfo/isInNative/isinnative001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,7 @@ * Updated according to: * 5024531 Fix MBeans design flaw that restricts to use JMX CompositeData * + * @requires test.thread.factory != "Virtual" * @library /vmTestbase * /test/lib * @run main/othervm nsk.monitoring.ThreadInfo.isInNative.isinnative001 diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java index bc0af5ae1cd..c338d392416 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadAllocatedBytes/BaseBehaviorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, 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 @@ -59,16 +59,30 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { + "return -1 if ThreadAllocatedMemoryEnabled is set to false. " + "Received : " + result); threadMXBean.setThreadAllocatedMemoryEnabled(true); - // Expect >= 0 value for current thread + // Expect >= 0 value for current platform thread. result = threadMXBean.getCurrentThreadAllocatedBytes(); - if (result < 0) - throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should " - + "return >= 0 value for current thread. Received : " + result); - // Expect >= 0 value for current thread from getThreadAllocatedBytes(id) + if (Thread.currentThread().isVirtual()) { + if (result != -1) + throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should " + + "return -1 for virtual thread. " + + "Received : " + result); + } else { + if (result < 0) + throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should " + + "return >= 0 value for current thread. Received : " + result); + } + // Expect >= 0 value for current iplatform thread from getThreadAllocatedBytes(id). result = threadMXBean.getThreadAllocatedBytes(Thread.currentThread().getId()); - if (result < 0) - throw new TestFailure("Failure! getThreadAllocatedBytes(id) should " - + "return >= 0 value for current thread. Received : " + result); + if (Thread.currentThread().isVirtual()) { + if (result != -1) + throw new TestFailure("Failure! getThreadAllocatedBytes(id) should " + + "return -1 for virtual thread. " + + "Received : " + result); + } else { + if (result < 0) + throw new TestFailure("Failure! getThreadAllocatedBytes(id) should " + + "return >= 0 value for current thread. Received : " + result); + } MXBeanTestThread thread = new MXBeanTestThread(); long id = thread.getId(); @@ -79,11 +93,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { result = threadMXBean.getThreadAllocatedBytes(id); if (result != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " - + "return -1 for not started threads. Recieved : " + result); + + "return -1 for not started threads. Received : " + result); resultArr = threadMXBean.getThreadAllocatedBytes(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " - + "return -1 for not started threads. Recieved : " + resultArr[0]); + + "return -1 for not started threads. Received : " + resultArr[0]); BarrierHandler handler = startThreads(thread); try { handler.proceed(); @@ -93,23 +107,37 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { if (result != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " + "return -1 if ThreadAllocatedMemoryEnabled is set to false. " - + "Recieved : " + result); + + "Received : " + result); resultArr = threadMXBean.getThreadAllocatedBytes(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " + "return -1 if ThreadAllocatedMemoryEnabled is set to false. " - + "Recieved : " + resultArr[0]); + + "Received : " + resultArr[0]); threadMXBean.setThreadAllocatedMemoryEnabled(true); // Expect >= 0 value for running threads result = threadMXBean.getThreadAllocatedBytes(id); - if (result < 0) - throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " - + "return > 0 value for RUNNING thread. Recieved : " + result); + if (thread.isVirtual()) { + if (result != -1) + throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " + + "return -1 for virtual thread. " + + "Received : " + result); + } else { + if (result < 0) + throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " + + "return > 0 value for RUNNING thread. Received : " + result); + } resultArr = threadMXBean.getThreadAllocatedBytes(idArr); - if (resultArr[0] < 0) - throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " - + "return > 0 value for RUNNING thread. Recieved : " + resultArr[0]); + if (thread.isVirtual()) { + if (resultArr[0] != -1) + throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " + + "return -1 for virtual thread. " + + "Received : " + resultArr[0]); + } else { + if (resultArr[0] < 0) + throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " + + "return > 0 value for RUNNING thread. Received : " + resultArr[0]); + } } finally { // Let thread finish handler.finish(); @@ -121,11 +149,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { result = threadMXBean.getThreadAllocatedBytes(id); if (result != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " - + "return -1 for finished threads. Recieved : " + result); + + "return -1 for finished threads. Received : " + result); resultArr = threadMXBean.getThreadAllocatedBytes(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadAllocatedBytes(long[] ids) should " - + "return -1 for finished threads. Recieved : " + resultArr[0]); + + "return -1 for finished threads. Received : " + resultArr[0]); log.info("BaseBehaviorTest passed."); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java index 5a16a1ba815..d639ba8b825 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/ThreadMXBean/GetThreadCpuTime/BaseBehaviorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, 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 @@ -57,11 +57,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { resultArr = threadMXBean.getThreadCpuTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " - + "return -1 for not started threads. Recieved : " + resultArr[0]); + + "return -1 for not started threads. Received : " + resultArr[0]); resultArr = threadMXBean.getThreadUserTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " - + "return -1 for not started threads. Recieved : " + resultArr[0]); + + "return -1 for not started threads. Received : " + resultArr[0]); BarrierHandler handler = startThreads(thread); try { handler.proceed(); @@ -71,22 +71,36 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " + "return -1 if threadCpuTimeEnabled is set to false. " - + "Recieved : " + resultArr[0]); + + "Received : " + resultArr[0]); resultArr = threadMXBean.getThreadUserTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " + "return -1 if threadCpuTimeEnabled is set to false. " - + "Recieved : " + resultArr[0]); + + "Received : " + resultArr[0]); threadMXBean.setThreadCpuTimeEnabled(true); - // Expect > 0 value for running threads + // Expect > 0 value for running platform threads and -1 for virtual threads. resultArr = threadMXBean.getThreadCpuTime(idArr); - if (resultArr[0] < 0) - throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " - + "return > 0 value for RUNNING thread. Recieved : " + resultArr[0]); + if (thread.isVirtual()) { + if (resultArr[0] != -1) + throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " + + "return -1 for virtual threads." + + "Received : " + resultArr[0]); + } else { + if (resultArr[0] < 0) + throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " + + "return > 0 value for RUNNING thread. Received : " + resultArr[0]); + } resultArr = threadMXBean.getThreadUserTime(idArr); - if (resultArr[0] < 0) - throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " - + "return > 0 value for RUNNING thread. Recieved : " + resultArr[0]); + if (thread.isVirtual()) { + if (resultArr[0] != -1) + throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " + + "return -1 for virtual threads." + + "Received : " + resultArr[0]); + } else { + if (resultArr[0] < 0) + throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " + + "return > 0 value for RUNNING thread. Received : " + resultArr[0]); + } } finally { // Let thread finish handler.finish(); @@ -98,11 +112,11 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase { resultArr = threadMXBean.getThreadCpuTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadCpuTime(long[] ids) should " - + "return -1 for finished threads. Recieved : " + resultArr[0]); + + "return -1 for finished threads. Received : " + resultArr[0]); resultArr = threadMXBean.getThreadUserTime(idArr); if (resultArr[0] != -1) throw new TestFailure("Failure! getThreadUserTime(long[] ids) should " - + "return -1 for finished threads. Recieved : " + resultArr[0]); + + "return -1 for finished threads. Received : " + resultArr[0]); log.info("BaseBehaviorTest passed."); } From 5f083abafc7abfaa46ddd053668cdfbfd2ad8a87 Mon Sep 17 00:00:00 2001 From: Patrick Strawderman Date: Sat, 6 Dec 2025 15:34:14 +0000 Subject: [PATCH 087/141] 8179918: EnumSet spliterator should report SORTED, ORDERED, NONNULL Reviewed-by: vklang --- .../share/classes/java/util/EnumSet.java | 8 +- .../util/EnumSet/EnumSetSpliteratorTest.java | 97 +++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/util/EnumSet/EnumSetSpliteratorTest.java diff --git a/src/java.base/share/classes/java/util/EnumSet.java b/src/java.base/share/classes/java/util/EnumSet.java index 55219c98469..e8dee28fa33 100644 --- a/src/java.base/share/classes/java/util/EnumSet.java +++ b/src/java.base/share/classes/java/util/EnumSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, 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 @@ -501,4 +501,10 @@ public abstract sealed class EnumSet> extends AbstractSet throws java.io.InvalidObjectException { throw new java.io.InvalidObjectException("Proxy required"); } + + @Override + public Spliterator spliterator() { + return Spliterators.spliterator(this, + Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED | Spliterator.NONNULL); + } } diff --git a/test/jdk/java/util/EnumSet/EnumSetSpliteratorTest.java b/test/jdk/java/util/EnumSet/EnumSetSpliteratorTest.java new file mode 100644 index 00000000000..eee38846683 --- /dev/null +++ b/test/jdk/java/util/EnumSet/EnumSetSpliteratorTest.java @@ -0,0 +1,97 @@ +/* + * 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 + * @run junit EnumSetSpliteratorTest + * @bug 8179918 + * @summary EnumSet spliterator should report SORTED, ORDERED, NONNULL + */ + +import java.util.EnumSet; +import java.util.List; +import java.util.Spliterator; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class EnumSetSpliteratorTest { + + private enum Empty {} + + private enum Small { + a, b, c, d + } + + private enum Large { + e00, e01, e02, e03, e04, e05, e06, e07, + e08, e09, e0A, e0B, e0C, e0D, e0E, e0F, + e10, e11, e12, e13, e14, e15, e16, e17, + e18, e19, e1A, e1B, e1C, e1D, e1E, e1F, + e20, e21, e22, e23, e24, e25, e26, e27, + e28, e29, e2A, e2B, e2C, e2D, e2E, e2F, + e30, e31, e32, e33, e34, e35, e36, e37, + e38, e39, e3A, e3B, e3C, e3D, e3E, e3F, + e40, e41, e42, e43, e44, e45, e46, e47, + e48, e49, e4A, e4B, e4C, e4D, e4E, e4F + } + + @Test + public void testSpliteratorCharacteristics() { + assertSpliteratorCharacteristics(EnumSet.allOf(Empty.class)); + assertSpliteratorCharacteristics(EnumSet.allOf(Small.class)); + assertSpliteratorCharacteristics(EnumSet.allOf(Large.class)); + assertSpliteratorCharacteristics(EnumSet.noneOf(Empty.class)); + assertSpliteratorCharacteristics(EnumSet.noneOf(Small.class)); + assertSpliteratorCharacteristics(EnumSet.noneOf(Large.class)); + assertSpliteratorCharacteristics(EnumSet.of(Small.a, Small.d)); + assertSpliteratorCharacteristics(EnumSet.range(Small.a, Small.c)); + assertSpliteratorCharacteristics(EnumSet.range(Large.e02, Large.e4D)); + assertSpliteratorCharacteristics(EnumSet.complementOf(EnumSet.of(Small.c))); + assertSpliteratorCharacteristics(EnumSet.complementOf(EnumSet.of(Large.e00, Large.e4F))); + } + + @Test + public void testEncounterOrder() { + assertEquals(List.of(Small.values()), EnumSet.allOf(Small.class).stream().toList()); + assertEquals(List.of(Large.values()), EnumSet.allOf(Large.class).stream().toList()); + } + + private static final int EXPECTED_CHARACTERISTICS = ( + Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED | + Spliterator.NONNULL | Spliterator.SIZED | Spliterator.SUBSIZED); + + private static void assertSpliteratorCharacteristics(EnumSet enumSet) { + Spliterator spliterator = enumSet.spliterator(); + assertTrue(spliterator.hasCharacteristics(Spliterator.DISTINCT), "Missing DISTINCT"); + assertTrue(spliterator.hasCharacteristics(Spliterator.SORTED), "Missing SORTED"); + assertTrue(spliterator.hasCharacteristics(Spliterator.ORDERED), "Missing ORDERED"); + assertTrue(spliterator.hasCharacteristics(Spliterator.NONNULL), "Missing NONNULL"); + assertTrue(spliterator.hasCharacteristics(Spliterator.SIZED), "Missing SIZED"); + assertTrue(spliterator.hasCharacteristics(Spliterator.SUBSIZED), "Missing SUBSIZED"); + assertEquals(EXPECTED_CHARACTERISTICS, spliterator.characteristics(), "Unexpected characteristics"); + } +} \ No newline at end of file From 7da91533aaf2033cedee6e2a56fb693f26909df5 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Mon, 8 Dec 2025 09:06:21 +0000 Subject: [PATCH 088/141] 8369950: TLS connection to IPv6 address fails with BCJSSE due to IllegalArgumentException Co-authored-by: Mikhail Yankelevich Reviewed-by: djelinski, vyazici, dfuchs, myankelevich --- .../net/www/protocol/https/HttpsClient.java | 11 +- .../HttpsURLConnection/SubjectAltNameIP.java | 379 ++++++++++++++++++ 2 files changed, 388 insertions(+), 2 deletions(-) create mode 100644 test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java 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 2f011f5805b..9f1d7b07021 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,6 +44,7 @@ import java.util.Objects; import java.util.StringTokenizer; import javax.net.ssl.*; +import sun.net.util.IPAddressUtil; import sun.net.www.http.HttpClient; import sun.net.www.protocol.http.AuthCacheImpl; import sun.net.www.protocol.http.HttpURLConnection; @@ -471,7 +472,13 @@ final class HttpsClient extends HttpClient SSLParameters parameters = s.getSSLParameters(); parameters.setEndpointIdentificationAlgorithm("HTTPS"); // host has been set previously for SSLSocketImpl - if (!(s instanceof SSLSocketImpl)) { + if (!(s instanceof SSLSocketImpl) && + !IPAddressUtil.isIPv4LiteralAddress(host) && + !(host.charAt(0) == '[' && host.charAt(host.length() - 1) == ']' && + IPAddressUtil.isIPv6LiteralAddress(host.substring(1, host.length() - 1)) + )) { + // Fully qualified DNS hostname of the server, as per section 3, RFC 6066 + // Literal IPv4 and IPv6 addresses are not permitted in "HostName". parameters.setServerNames(List.of(new SNIHostName(host))); } s.setSSLParameters(parameters); diff --git a/test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java b/test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java new file mode 100644 index 00000000000..2def2f69d6e --- /dev/null +++ b/test/jdk/javax/net/ssl/HttpsURLConnection/SubjectAltNameIP.java @@ -0,0 +1,379 @@ +/* + * 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 8369950 + * @summary Test that the HttpsURLConnection does not set IP address literals for + * SNI hostname during TLS handshake + * @library /test/lib + * @modules java.base/sun.net.util + * @comment Insert -Djavax.net.debug=all into the following lines to enable SSL debugging + * @run main/othervm SubjectAltNameIP 127.0.0.1 + * @run main/othervm SubjectAltNameIP [::1] + */ + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.function.Consumer; + +import jdk.test.lib.Asserts; +import jdk.test.lib.net.IPSupport; +import jdk.test.lib.net.SimpleSSLContext; +import jtreg.SkippedException; +import sun.net.util.IPAddressUtil; + +public class SubjectAltNameIP { + + // Is the server ready to serve? + private final CountDownLatch serverReady = new CountDownLatch(1); + + // Use any free port by default. + volatile int serverPort = 0; + + // Stores an exception thrown by server in a separate thread. + volatile Exception serverException = null; + + // SSLSocket object created by HttpsClient internally. + SSLSocket clientSSLSocket = null; + + // The hostname the server socket is bound to. + String hostName; + + static final byte[] requestEnd = new byte[] {'\r', '\n', '\r', '\n' }; + + // Read until the end of the request. + void readOneRequest(InputStream is) throws IOException { + int requestEndCount = 0, r; + while ((r = is.read()) != -1) { + if (r == requestEnd[requestEndCount]) { + requestEndCount++; + if (requestEndCount == 4) { + break; + } + } else { + requestEndCount = 0; + } + } + } + + /* + * Define the server side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + void doServerSide() throws Exception { + SSLServerSocketFactory sslssf = + new SimpleSSLContext().get().getServerSocketFactory(); + SSLServerSocket sslServerSocket = + (SSLServerSocket) sslssf.createServerSocket( + serverPort, 0, + InetAddress.getByName(hostName)); + sslServerSocket.setEnabledProtocols(new String[]{"TLSv1.3"}); + serverPort = sslServerSocket.getLocalPort(); + + /* + * Signal the client, the server is ready to accept connection. + */ + serverReady.countDown(); + + SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); + OutputStream sslOS = sslSocket.getOutputStream(); + BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(sslOS)); + bw.write("HTTP/1.1 200 OK\r\n\r\n"); + bw.flush(); + readOneRequest(sslSocket.getInputStream()); + sslSocket.close(); + } + + /* + * Define the client side of the test. + * + * If the server prematurely exits, serverReady will be set to true + * to avoid infinite hangs. + */ + void doClientSide() throws Exception { + + /* + * Wait for server to get started. + */ + serverReady.await(); + if (serverException != null) { + throw new RuntimeException("Server failed to start.", serverException); + } + + SSLSocketFactory sf = new SimpleSSLContext().get().getSocketFactory(); + URI uri = new URI("https://" + hostName + ":" + serverPort + "/index.html"); + HttpsURLConnection conn = (HttpsURLConnection)uri.toURL().openConnection(); + + /* + * Simulate an external JSSE implementation and store the client SSLSocket + * used internally. + */ + conn.setSSLSocketFactory(wrapSocketFactory(sf, + sslSocket -> { + Asserts.assertEquals(null, clientSSLSocket, "clientSSLSocket is"); + clientSSLSocket = sslSocket; + })); + conn.getInputStream(); + + var sniSN = clientSSLSocket.getSSLParameters().getServerNames(); + if (sniSN != null && !sniSN.isEmpty()) { + throw new RuntimeException("SNI server name '" + + sniSN.getFirst() + "' must not be set."); + } + + if (conn.getResponseCode() == -1) { + throw new RuntimeException("getResponseCode() returns -1"); + } + } + + public static void main(String[] args) throws Exception { + + if (IPAddressUtil.isIPv6LiteralAddress(args[0]) && !IPSupport.hasIPv6()) { + throw new SkippedException("Skipping test - IPv6 is not supported"); + } + /* + * Start the tests. + */ + new SubjectAltNameIP(args[0]); + } + + Thread serverThread = null; + + /* + * Primary constructor, used to drive remainder of the test. + * + * Fork off the other side, then do your work. + */ + SubjectAltNameIP(String host) throws Exception { + hostName = host; + startServer(); + doClientSide(); + + /* + * Wait for other side to close down. + */ + serverThread.join(); + + if (serverException != null) + throw serverException; + } + + void startServer() { + serverThread = new Thread(() -> { + try { + doServerSide(); + } catch (Exception e) { + /* + * Our server thread just died. + * + * Store the exception and release the client. + */ + serverException = e; + serverReady.countDown(); + } + }); + serverThread.start(); + } + + /* + * Wraps SSLSocketImpl to simulate a different JSSE implementation + */ + private static SSLSocketFactory wrapSocketFactory(final SSLSocketFactory wrap, final Consumer store) { + return new SSLSocketFactory() { + @Override + public String[] getDefaultCipherSuites() { + return wrap.getDefaultCipherSuites(); + } + @Override + public String[] getSupportedCipherSuites() { + return wrap.getSupportedCipherSuites(); + } + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) + throws IOException { + final SSLSocket so = + (SSLSocket) wrap.createSocket(s, host, port, autoClose); + + // store the underlying SSLSocket for later use + store.accept(so); + + return new SSLSocket() { + @Override + public void connect(SocketAddress endpoint, + int timeout) throws IOException { + so.connect(endpoint, timeout); + } + @Override + public String[] getSupportedCipherSuites() { + return so.getSupportedCipherSuites(); + } + @Override + public String[] getEnabledCipherSuites() { + return so.getEnabledCipherSuites(); + } + @Override + public void setEnabledCipherSuites(String[] suites) { + so.setEnabledCipherSuites(suites); + } + @Override + public String[] getSupportedProtocols() { + return so.getSupportedProtocols(); + } + @Override + public String[] getEnabledProtocols() { + return so.getEnabledProtocols(); + } + @Override + public void setEnabledProtocols(String[] protocols) { + so.setEnabledProtocols(protocols); + } + @Override + public SSLSession getSession() { + return so.getSession(); + } + @Override + public SSLSession getHandshakeSession() { + return so.getHandshakeSession(); + } + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener listener) { + so.addHandshakeCompletedListener(listener); + } + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) { + so.removeHandshakeCompletedListener(listener); + } + @Override + public void startHandshake() throws IOException { + so.startHandshake(); + } + @Override + public void setUseClientMode(boolean mode) { + so.setUseClientMode(mode); + } + @Override + public boolean getUseClientMode() { + return so.getUseClientMode(); + } + @Override + public void setNeedClientAuth(boolean need) { + } + @Override + public boolean getNeedClientAuth() { + return false; + } + @Override + public void setWantClientAuth(boolean want) { + } + @Override + public boolean getWantClientAuth() { + return false; + } + @Override + public void setEnableSessionCreation(boolean flag) { + so.setEnableSessionCreation(flag); + } + @Override + public boolean getEnableSessionCreation() { + return so.getEnableSessionCreation(); + } + @Override + public void close() throws IOException { + so.close(); + } + @Override + public boolean isClosed() { + return so.isClosed(); + } + @Override + public void shutdownInput() throws IOException { + so.shutdownInput(); + } + @Override + public boolean isInputShutdown() { + return so.isInputShutdown(); + } + @Override + public void shutdownOutput() throws IOException { + so.shutdownOutput(); + } + @Override + public boolean isOutputShutdown() { + return so.isOutputShutdown(); + } + @Override + public InputStream getInputStream() throws IOException { + return so.getInputStream(); + } + @Override + public OutputStream getOutputStream() throws IOException { + return so.getOutputStream(); + } + @Override + public SSLParameters getSSLParameters() { + return so.getSSLParameters(); + } + @Override + public void setSSLParameters(SSLParameters params) { + so.setSSLParameters(params); + } + }; + } + @Override + public Socket createSocket(String h, int p) { + return null; + } + @Override + public Socket createSocket(String h, int p, InetAddress ipa, int lp) { + return null; + } + @Override + public Socket createSocket(InetAddress h, int p) { + return null; + } + @Override + public Socket createSocket(InetAddress a, int p, InetAddress l, int lp) { + return null; + } + }; + } +} From 350015088281eb9e6e9e3a9811f38adac5f7a975 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 8 Dec 2025 10:04:44 +0000 Subject: [PATCH 089/141] 8373094: javac may fail because of unattributed break in a loop Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 16 +- .../tools/javac/recovery/AttrRecovery.java | 158 +++++++++++++++++- 2 files changed, 167 insertions(+), 7 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 3f72ada94e8..cc21113882f 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 @@ -5634,12 +5634,16 @@ public class Attr extends JCTree.Visitor { chk.validateRepeatable(c, repeatable, cbPos); } } else { - // Check that all extended classes and interfaces - // are compatible (i.e. no two define methods with same arguments - // yet different return types). (JLS 8.4.8.3) - chk.checkCompatibleSupertypes(tree.pos(), c.type); - chk.checkDefaultMethodClashes(tree.pos(), c.type); - chk.checkPotentiallyAmbiguousOverloads(tree, c.type); + try { + // Check that all extended classes and interfaces + // are compatible (i.e. no two define methods with same arguments + // yet different return types). (JLS 8.4.8.3) + chk.checkCompatibleSupertypes(tree.pos(), c.type); + chk.checkDefaultMethodClashes(tree.pos(), c.type); + chk.checkPotentiallyAmbiguousOverloads(tree, c.type); + } catch (CompletionFailure cf) { + chk.completionError(tree.pos(), cf); + } } // Check that class does not import the same parameterized interface diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index 9a37ce60654..ac1455e71d7 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 + * @bug 8301580 8322159 8333107 8332230 8338678 8351260 8366196 8372336 8373094 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -32,8 +32,11 @@ * @run main AttrRecovery */ +import com.sun.source.tree.IdentifierTree; import com.sun.source.tree.MemberReferenceTree; +import com.sun.source.tree.MemberSelectTree; import com.sun.source.tree.MethodInvocationTree; +import com.sun.source.tree.MethodTree; import com.sun.source.tree.VariableTree; import com.sun.source.util.TaskEvent; import com.sun.source.util.TaskListener; @@ -41,11 +44,13 @@ import com.sun.source.util.TreePathScanner; import com.sun.source.util.Trees; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.lang.model.element.Element; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; @@ -495,4 +500,155 @@ public class AttrRecovery extends TestRunner { } } } + + @Test //JDK-8373094 + public void testSensibleAttribution() throws Exception { + Path curPath = Path.of("."); + Path lib = curPath.resolve("lib"); + Path classes = lib.resolve("classes"); + Files.createDirectories(classes); + new JavacTask(tb) + .outdir(classes) + .sources(""" + package test; + public class Intermediate extends Base {} + """, + """ + package test; + public class Base { + public void t(Missing m) {} + } + """, + """ + package test; + public class Missing { + } + """) + .run() + .writeAll(); + + Files.delete(classes.resolve("test").resolve("Missing.class")); + + record TestCase(String code, List options, String... expectedErrors) {} + TestCase[] testCases = new TestCase[] { + new TestCase(""" + package test; + public class Test extends Intermediate { + private void test() { + int i = 0; + System.err.println(i); + while (true) { + break; + } + } + } + """, + List.of(), + "Test.java:2:8: compiler.err.cant.access: test.Missing, (compiler.misc.class.file.not.found: test.Missing)", + "1 error"), + new TestCase(""" + package test; + public class Test extends Intermediate { + private void test() { + int i = 0; + System.err.println(i); + while (true) { + break; + } + } + } + """, + List.of("-XDshould-stop.at=FLOW"), + "Test.java:2:8: compiler.err.cant.access: test.Missing, (compiler.misc.class.file.not.found: test.Missing)", + "1 error"), + }; + + for (TestCase tc : testCases) { + List attributes = new ArrayList<>(); + List actual = new JavacTask(tb) + .options(Stream.concat(List.of("-XDrawDiagnostics", "-XDdev").stream(), + tc.options.stream()).toList()) + .classpath(classes) + .sources(tc.code()) + .outdir(curPath) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + if (e.getKind() != TaskEvent.Kind.ANALYZE) { + return ; + } + Trees trees = Trees.instance(task); + new TreePathScanner() { + boolean check; + + @Override + public Void visitMethod(MethodTree node, Void p) { + if (node.getName().contentEquals("test")) { + check = true; + try { + return super.visitMethod(node, p); + } finally { + check = false; + } + } + + return super.visitMethod(node, p); + } + + @Override + public Void visitMethodInvocation(MethodInvocationTree node, Void p) { + if (!node.toString().contains("super")) { + verifyElement(); + } + return super.visitMethodInvocation(node, p); + } + + @Override + public Void visitIdentifier(IdentifierTree node, Void p) { + verifyElement(); + return super.visitIdentifier(node, p); + } + + @Override + public Void visitMemberSelect(MemberSelectTree node, Void p) { + verifyElement(); + return super.visitMemberSelect(node, p); + } + + private void verifyElement() { + if (!check) { + return ; + } + + Element el = trees.getElement(getCurrentPath()); + if (el == null) { + error("Unattributed tree: " + getCurrentPath().getLeaf()); + } else { + attributes.add(el.toString()); + } + } + }.scan(e.getCompilationUnit(), null); + } + }); + }) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expectedErrors = List.of(tc.expectedErrors); + + if (!Objects.equals(actual, expectedErrors)) { + error("Expected: " + expectedErrors + ", but got: " + actual); + } + + List expectedAttributes = + List.of("println(int)", "println(int)", "err", "java.lang.System", "i"); + + if (!Objects.equals(attributes, expectedAttributes)) { + error("Expected: " + expectedAttributes + ", but got: " + attributes); + } + } + } + } From a6594794839807d56434d6f28fe3d581fb1e36c0 Mon Sep 17 00:00:00 2001 From: Francesco Andreuzzi Date: Mon, 8 Dec 2025 11:45:53 +0000 Subject: [PATCH 090/141] 8367541: Parallel: Make young and old generation fields nonstatic in ParallelScavengeHeap Reviewed-by: ayang --- src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp | 2 -- src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp | 8 ++++---- src/hotspot/share/gc/parallel/psScavenge.hpp | 2 +- src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp | 4 ++-- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index 9df3deedf89..b85b16f58b5 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -58,8 +58,6 @@ #include "utilities/macros.hpp" #include "utilities/vmError.hpp" -PSYoungGen* ParallelScavengeHeap::_young_gen = nullptr; -PSOldGen* ParallelScavengeHeap::_old_gen = nullptr; PSAdaptiveSizePolicy* ParallelScavengeHeap::_size_policy = nullptr; GCPolicyCounters* ParallelScavengeHeap::_gc_policy_counters = nullptr; size_t ParallelScavengeHeap::_desired_page_size = 0; diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index 5d8ddbcaaed..588ddfa3f0c 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -69,8 +69,8 @@ class ReservedSpace; class ParallelScavengeHeap : public CollectedHeap { friend class VMStructs; private: - static PSYoungGen* _young_gen; - static PSOldGen* _old_gen; + PSYoungGen* _young_gen; + PSOldGen* _old_gen; // Sizing policy for entire heap static PSAdaptiveSizePolicy* _size_policy; @@ -160,8 +160,8 @@ public: GrowableArray memory_managers() override; GrowableArray memory_pools() override; - static PSYoungGen* young_gen() { return _young_gen; } - static PSOldGen* old_gen() { return _old_gen; } + PSYoungGen* young_gen() const { return _young_gen; } + PSOldGen* old_gen() const { return _old_gen; } PSAdaptiveSizePolicy* size_policy() { return _size_policy; } diff --git a/src/hotspot/share/gc/parallel/psScavenge.hpp b/src/hotspot/share/gc/parallel/psScavenge.hpp index af9b91f74bc..df97a1c1ede 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp @@ -115,7 +115,7 @@ class PSScavenge: AllStatic { } static bool is_obj_in_to_space(oop o) { - return ParallelScavengeHeap::young_gen()->to_space()->contains(o); + return ParallelScavengeHeap::heap()->young_gen()->to_space()->contains(o); } }; diff --git a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp index f5e7375fca1..e45bd45400c 100644 --- a/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp +++ b/src/hotspot/share/gc/parallel/vmStructs_parallelgc.hpp @@ -64,8 +64,8 @@ nonstatic_field(PSOldGen, _max_gen_size, const size_t) \ \ \ - static_field(ParallelScavengeHeap, _young_gen, PSYoungGen*) \ - static_field(ParallelScavengeHeap, _old_gen, PSOldGen*) \ + nonstatic_field(ParallelScavengeHeap, _young_gen, PSYoungGen*) \ + nonstatic_field(ParallelScavengeHeap, _old_gen, PSOldGen*) \ \ #define VM_TYPES_PARALLELGC(declare_type, \ From b83bf0717eb8926efcf85a32be08f33a41bb48dd Mon Sep 17 00:00:00 2001 From: Qizheng Xing Date: Mon, 8 Dec 2025 13:16:39 +0000 Subject: [PATCH 091/141] 8360192: C2: Make the type of count leading/trailing zero nodes more precise Reviewed-by: qamai, epeter, jbhateja --- src/hotspot/share/opto/countbitsnode.cpp | 149 +++-- .../compiler/c2/gvn/TestCountBitsRange.java | 570 ++++++++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 20 + .../bench/vm/compiler/CountLeadingZeros.java | 74 +++ 4 files changed, 747 insertions(+), 66 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/gvn/TestCountBitsRange.java create mode 100644 test/micro/org/openjdk/bench/vm/compiler/CountLeadingZeros.java diff --git a/src/hotspot/share/opto/countbitsnode.cpp b/src/hotspot/share/opto/countbitsnode.cpp index aac874e94b1..1601b33ea2b 100644 --- a/src/hotspot/share/opto/countbitsnode.cpp +++ b/src/hotspot/share/opto/countbitsnode.cpp @@ -26,97 +26,114 @@ #include "opto/opcodes.hpp" #include "opto/phaseX.hpp" #include "opto/type.hpp" +#include "utilities/count_leading_zeros.hpp" +#include "utilities/count_trailing_zeros.hpp" #include "utilities/population_count.hpp" +static int count_leading_zeros_int(jint i) { + return i == 0 ? BitsPerInt : count_leading_zeros(i); +} + +static int count_leading_zeros_long(jlong l) { + return l == 0 ? BitsPerLong : count_leading_zeros(l); +} + +static int count_trailing_zeros_int(jint i) { + return i == 0 ? BitsPerInt : count_trailing_zeros(i); +} + +static int count_trailing_zeros_long(jlong l) { + return l == 0 ? BitsPerLong : count_trailing_zeros(l); +} + //------------------------------Value------------------------------------------ const Type* CountLeadingZerosINode::Value(PhaseGVN* phase) const { const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeInt* ti = t->isa_int(); - if (ti && ti->is_con()) { - jint i = ti->get_con(); - // HD, Figure 5-6 - if (i == 0) - return TypeInt::make(BitsPerInt); - int n = 1; - unsigned int x = i; - if (x >> 16 == 0) { n += 16; x <<= 16; } - if (x >> 24 == 0) { n += 8; x <<= 8; } - if (x >> 28 == 0) { n += 4; x <<= 4; } - if (x >> 30 == 0) { n += 2; x <<= 2; } - n -= x >> 31; - return TypeInt::make(n); + if (t == Type::TOP) { + return Type::TOP; } - return TypeInt::INT; + + // To minimize `count_leading_zeros(x)`, we should make the highest 1 bit in x + // as far to the left as possible. A bit in x can be 1 iff this bit is not + // forced to be 0, i.e. the corresponding bit in `x._bits._zeros` is 0. Thus: + // min(clz(x)) = number of bits to the left of the highest 0 bit in x._bits._zeros + // = count_leading_ones(x._bits._zeros) = clz(~x._bits._zeros) + // + // To maximize `count_leading_zeros(x)`, we should make the leading zeros as + // many as possible. A bit in x can be 0 iff this bit is not forced to be 1, + // i.e. the corresponding bit in `x._bits._ones` is 0. Thus: + // max(clz(x)) = clz(x._bits._ones) + // + // Therefore, the range of `count_leading_zeros(x)` is: + // [clz(~x._bits._zeros), clz(x._bits._ones)] + // + // A more detailed proof using Z3 can be found at: + // https://github.com/openjdk/jdk/pull/25928#discussion_r2256750507 + const TypeInt* ti = t->is_int(); + return TypeInt::make(count_leading_zeros_int(~ti->_bits._zeros), + count_leading_zeros_int(ti->_bits._ones), + ti->_widen); } //------------------------------Value------------------------------------------ const Type* CountLeadingZerosLNode::Value(PhaseGVN* phase) const { const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeLong* tl = t->isa_long(); - if (tl && tl->is_con()) { - jlong l = tl->get_con(); - // HD, Figure 5-6 - if (l == 0) - return TypeInt::make(BitsPerLong); - int n = 1; - unsigned int x = (((julong) l) >> 32); - if (x == 0) { n += 32; x = (int) l; } - if (x >> 16 == 0) { n += 16; x <<= 16; } - if (x >> 24 == 0) { n += 8; x <<= 8; } - if (x >> 28 == 0) { n += 4; x <<= 4; } - if (x >> 30 == 0) { n += 2; x <<= 2; } - n -= x >> 31; - return TypeInt::make(n); + if (t == Type::TOP) { + return Type::TOP; } - return TypeInt::INT; + + // The proof of correctness is same as the above comments + // in `CountLeadingZerosINode::Value`. + const TypeLong* tl = t->is_long(); + return TypeInt::make(count_leading_zeros_long(~tl->_bits._zeros), + count_leading_zeros_long(tl->_bits._ones), + tl->_widen); } //------------------------------Value------------------------------------------ const Type* CountTrailingZerosINode::Value(PhaseGVN* phase) const { const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeInt* ti = t->isa_int(); - if (ti && ti->is_con()) { - jint i = ti->get_con(); - // HD, Figure 5-14 - int y; - if (i == 0) - return TypeInt::make(BitsPerInt); - int n = 31; - y = i << 16; if (y != 0) { n = n - 16; i = y; } - y = i << 8; if (y != 0) { n = n - 8; i = y; } - y = i << 4; if (y != 0) { n = n - 4; i = y; } - y = i << 2; if (y != 0) { n = n - 2; i = y; } - y = i << 1; if (y != 0) { n = n - 1; } - return TypeInt::make(n); + if (t == Type::TOP) { + return Type::TOP; } - return TypeInt::INT; + + // To minimize `count_trailing_zeros(x)`, we should make the lowest 1 bit in x + // as far to the right as possible. A bit in x can be 1 iff this bit is not + // forced to be 0, i.e. the corresponding bit in `x._bits._zeros` is 0. Thus: + // min(ctz(x)) = number of bits to the right of the lowest 0 bit in x._bits._zeros + // = count_trailing_ones(x._bits._zeros) = ctz(~x._bits._zeros) + // + // To maximize `count_trailing_zeros(x)`, we should make the trailing zeros as + // many as possible. A bit in x can be 0 iff this bit is not forced to be 1, + // i.e. the corresponding bit in `x._bits._ones` is 0. Thus: + // max(ctz(x)) = ctz(x._bits._ones) + // + // Therefore, the range of `count_trailing_zeros(x)` is: + // [ctz(~x._bits._zeros), ctz(x._bits._ones)] + // + // A more detailed proof using Z3 can be found at: + // https://github.com/openjdk/jdk/pull/25928#discussion_r2256750507 + const TypeInt* ti = t->is_int(); + return TypeInt::make(count_trailing_zeros_int(~ti->_bits._zeros), + count_trailing_zeros_int(ti->_bits._ones), + ti->_widen); } //------------------------------Value------------------------------------------ const Type* CountTrailingZerosLNode::Value(PhaseGVN* phase) const { const Type* t = phase->type(in(1)); - if (t == Type::TOP) return Type::TOP; - const TypeLong* tl = t->isa_long(); - if (tl && tl->is_con()) { - jlong l = tl->get_con(); - // HD, Figure 5-14 - int x, y; - if (l == 0) - return TypeInt::make(BitsPerLong); - int n = 63; - y = (int) l; if (y != 0) { n = n - 32; x = y; } else x = (((julong) l) >> 32); - y = x << 16; if (y != 0) { n = n - 16; x = y; } - y = x << 8; if (y != 0) { n = n - 8; x = y; } - y = x << 4; if (y != 0) { n = n - 4; x = y; } - y = x << 2; if (y != 0) { n = n - 2; x = y; } - y = x << 1; if (y != 0) { n = n - 1; } - return TypeInt::make(n); + if (t == Type::TOP) { + return Type::TOP; } - return TypeInt::INT; + + // The proof of correctness is same as the above comments + // in `CountTrailingZerosINode::Value`. + const TypeLong* tl = t->is_long(); + return TypeInt::make(count_trailing_zeros_long(~tl->_bits._zeros), + count_trailing_zeros_long(tl->_bits._ones), + tl->_widen); } + // We use the KnownBits information from the integer types to derive how many one bits // we have at least and at most. // From the definition of KnownBits, we know: diff --git a/test/hotspot/jtreg/compiler/c2/gvn/TestCountBitsRange.java b/test/hotspot/jtreg/compiler/c2/gvn/TestCountBitsRange.java new file mode 100644 index 00000000000..00aa466e822 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/gvn/TestCountBitsRange.java @@ -0,0 +1,570 @@ +/* + * Copyright (c) 2025 Alibaba Group Holding Limited. All Rights Reserved. + * 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.Generator; +import compiler.lib.generators.Generators; +import compiler.lib.generators.RestrictableGenerator; +import compiler.lib.ir_framework.*; +import java.util.function.Function; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8360192 + * @summary Tests that count bits nodes are handled correctly. + * @library /test/lib / + * @run driver compiler.c2.gvn.TestCountBitsRange + */ +public class TestCountBitsRange { + private static final Generator INTS = Generators.G.ints(); + private static final Generator LONGS = Generators.G.longs(); + + private static final RestrictableGenerator INTS_32 = Generators.G.ints().restricted(0, 32); + private static final RestrictableGenerator INTS_64 = Generators.G.ints().restricted(0, 64); + + private static final int LIMITS_32_0 = INTS_32.next(); + private static final int LIMITS_32_1 = INTS_32.next(); + private static final int LIMITS_32_2 = INTS_32.next(); + private static final int LIMITS_32_3 = INTS_32.next(); + private static final int LIMITS_32_4 = INTS_32.next(); + private static final int LIMITS_32_5 = INTS_32.next(); + private static final int LIMITS_32_6 = INTS_32.next(); + private static final int LIMITS_32_7 = INTS_32.next(); + + private static final int LIMITS_64_0 = INTS_64.next(); + private static final int LIMITS_64_1 = INTS_64.next(); + private static final int LIMITS_64_2 = INTS_64.next(); + private static final int LIMITS_64_3 = INTS_64.next(); + private static final int LIMITS_64_4 = INTS_64.next(); + private static final int LIMITS_64_5 = INTS_64.next(); + private static final int LIMITS_64_6 = INTS_64.next(); + private static final int LIMITS_64_7 = INTS_64.next(); + + private static final IntRange RANGE_INT = IntRange.generate(INTS); + private static final LongRange RANGE_LONG = LongRange.generate(LONGS); + + public static void main(String[] args) { + TestFramework.run(); + } + + @Run(test = { + "clzConstInts", "clzCompareInt", "clzDiv8Int", "clzRandLimitInt", + "clzConstLongs", "clzCompareLong", "clzDiv8Long", "clzRandLimitLong", + "ctzConstInts", "ctzCompareInt", "ctzDiv8Int", "ctzRandLimitInt", + "ctzConstLongs", "ctzCompareLong", "ctzDiv8Long", "ctzRandLimitLong", + }) + public void runTest() { + int randInt = INTS.next(); + long randLong = LONGS.next(); + assertResult(randInt, randLong); + } + + @DontCompile + public void assertResult(int randInt, long randLong) { + checkConstResults(clzConstInts(), x -> Integer.numberOfLeadingZeros(x.intValue())); + Asserts.assertEQ(Integer.numberOfLeadingZeros(randInt) < 0 + || Integer.numberOfLeadingZeros(randInt) > 32, + clzCompareInt(randInt)); + Asserts.assertEQ(Integer.numberOfLeadingZeros(randInt) / 8, + clzDiv8Int(randInt)); + Asserts.assertEQ(clzRandLimitInterpretedInt(randInt), clzRandLimitInt(randInt)); + + checkConstResults(clzConstLongs(), x -> Long.numberOfLeadingZeros(x.longValue())); + Asserts.assertEQ(Long.numberOfLeadingZeros(randLong) < 0 + || Long.numberOfLeadingZeros(randLong) > 64, + clzCompareLong(randLong)); + Asserts.assertEQ(Long.numberOfLeadingZeros(randLong) / 8, + clzDiv8Long(randLong)); + Asserts.assertEQ(clzRandLimitInterpretedLong(randLong), clzRandLimitLong(randLong)); + + checkConstResults(ctzConstInts(), x -> Integer.numberOfTrailingZeros(x.intValue())); + Asserts.assertEQ(Integer.numberOfTrailingZeros(randInt) < 0 + || Integer.numberOfTrailingZeros(randInt) > 32, + ctzCompareInt(randInt)); + Asserts.assertEQ(Integer.numberOfTrailingZeros(randInt) / 8, + ctzDiv8Int(randInt)); + Asserts.assertEQ(ctzRandLimitInterpretedInt(randInt), ctzRandLimitInt(randInt)); + + checkConstResults(ctzConstLongs(), x -> Long.numberOfTrailingZeros(x.longValue())); + Asserts.assertEQ(Long.numberOfTrailingZeros(randLong) < 0 + || Long.numberOfTrailingZeros(randLong) > 64, + ctzCompareLong(randLong)); + Asserts.assertEQ(Long.numberOfTrailingZeros(randLong) / 8, + ctzDiv8Long(randLong)); + Asserts.assertEQ(ctzRandLimitInterpretedLong(randLong), ctzRandLimitLong(randLong)); + } + + @DontCompile + public void checkConstResults(int[] results, Function op) { + Asserts.assertEQ(op.apply(Long.valueOf(0)), results[0]); + for (int i = 0; i < results.length - 1; ++i) { + Asserts.assertEQ(op.apply(Long.valueOf(1l << i)), results[i + 1]); + } + } + + // Test CLZ with constant integer inputs. + // All CLZs in this test are expected to be optimized away. + @Test + @IR(failOn = IRNode.COUNT_LEADING_ZEROS_I) + public int[] clzConstInts() { + return new int[] { + Integer.numberOfLeadingZeros(0), + Integer.numberOfLeadingZeros(1 << 0), + Integer.numberOfLeadingZeros(1 << 1), + Integer.numberOfLeadingZeros(1 << 2), + Integer.numberOfLeadingZeros(1 << 3), + Integer.numberOfLeadingZeros(1 << 4), + Integer.numberOfLeadingZeros(1 << 5), + Integer.numberOfLeadingZeros(1 << 6), + Integer.numberOfLeadingZeros(1 << 7), + Integer.numberOfLeadingZeros(1 << 8), + Integer.numberOfLeadingZeros(1 << 9), + Integer.numberOfLeadingZeros(1 << 10), + Integer.numberOfLeadingZeros(1 << 11), + Integer.numberOfLeadingZeros(1 << 12), + Integer.numberOfLeadingZeros(1 << 13), + Integer.numberOfLeadingZeros(1 << 14), + Integer.numberOfLeadingZeros(1 << 15), + Integer.numberOfLeadingZeros(1 << 16), + Integer.numberOfLeadingZeros(1 << 17), + Integer.numberOfLeadingZeros(1 << 18), + Integer.numberOfLeadingZeros(1 << 19), + Integer.numberOfLeadingZeros(1 << 20), + Integer.numberOfLeadingZeros(1 << 21), + Integer.numberOfLeadingZeros(1 << 22), + Integer.numberOfLeadingZeros(1 << 23), + Integer.numberOfLeadingZeros(1 << 24), + Integer.numberOfLeadingZeros(1 << 25), + Integer.numberOfLeadingZeros(1 << 26), + Integer.numberOfLeadingZeros(1 << 27), + Integer.numberOfLeadingZeros(1 << 28), + Integer.numberOfLeadingZeros(1 << 29), + Integer.numberOfLeadingZeros(1 << 30), + Integer.numberOfLeadingZeros(1 << 31), + }; + } + + // Test the range of CLZ with random integer input. + // The result of CLZ should be in range [0, 32], so CLZs in this test are + // expected to be optimized away, and the test should always return false. + @Test + @IR(failOn = IRNode.COUNT_LEADING_ZEROS_I) + public boolean clzCompareInt(int randInt) { + return Integer.numberOfLeadingZeros(randInt) < 0 + || Integer.numberOfLeadingZeros(randInt) > 32; + } + + // Test the combination of CLZ and division by 8. + // The result of CLZ should be positive, so the division by 8 should be + // optimized to a simple right shift without rounding. + @Test + @IR(counts = {IRNode.COUNT_LEADING_ZEROS_I, "1", + IRNode.RSHIFT_I, "1", + IRNode.URSHIFT_I, "0", + IRNode.ADD_I, "0"}) + public int clzDiv8Int(int randInt) { + return Integer.numberOfLeadingZeros(randInt) / 8; + } + + // Test the output range of CLZ with random input range. + @Test + public int clzRandLimitInt(int randInt) { + randInt = RANGE_INT.clamp(randInt); + int result = Integer.numberOfLeadingZeros(randInt); + return getResultChecksum32(result); + } + + @DontCompile + public int clzRandLimitInterpretedInt(int randInt) { + randInt = RANGE_INT.clamp(randInt); + int result = Integer.numberOfLeadingZeros(randInt); + return getResultChecksum32(result); + } + + // Test CLZ with constant long inputs. + // All CLZs in this test are expected to be optimized away. + @Test + @IR(failOn = IRNode.COUNT_LEADING_ZEROS_L) + public int[] clzConstLongs() { + return new int[] { + Long.numberOfLeadingZeros(0), + Long.numberOfLeadingZeros(1l << 0), + Long.numberOfLeadingZeros(1l << 1), + Long.numberOfLeadingZeros(1l << 2), + Long.numberOfLeadingZeros(1l << 3), + Long.numberOfLeadingZeros(1l << 4), + Long.numberOfLeadingZeros(1l << 5), + Long.numberOfLeadingZeros(1l << 6), + Long.numberOfLeadingZeros(1l << 7), + Long.numberOfLeadingZeros(1l << 8), + Long.numberOfLeadingZeros(1l << 9), + Long.numberOfLeadingZeros(1l << 10), + Long.numberOfLeadingZeros(1l << 11), + Long.numberOfLeadingZeros(1l << 12), + Long.numberOfLeadingZeros(1l << 13), + Long.numberOfLeadingZeros(1l << 14), + Long.numberOfLeadingZeros(1l << 15), + Long.numberOfLeadingZeros(1l << 16), + Long.numberOfLeadingZeros(1l << 17), + Long.numberOfLeadingZeros(1l << 18), + Long.numberOfLeadingZeros(1l << 19), + Long.numberOfLeadingZeros(1l << 20), + Long.numberOfLeadingZeros(1l << 21), + Long.numberOfLeadingZeros(1l << 22), + Long.numberOfLeadingZeros(1l << 23), + Long.numberOfLeadingZeros(1l << 24), + Long.numberOfLeadingZeros(1l << 25), + Long.numberOfLeadingZeros(1l << 26), + Long.numberOfLeadingZeros(1l << 27), + Long.numberOfLeadingZeros(1l << 28), + Long.numberOfLeadingZeros(1l << 29), + Long.numberOfLeadingZeros(1l << 30), + Long.numberOfLeadingZeros(1l << 31), + Long.numberOfLeadingZeros(1l << 32), + Long.numberOfLeadingZeros(1l << 33), + Long.numberOfLeadingZeros(1l << 34), + Long.numberOfLeadingZeros(1l << 35), + Long.numberOfLeadingZeros(1l << 36), + Long.numberOfLeadingZeros(1l << 37), + Long.numberOfLeadingZeros(1l << 38), + Long.numberOfLeadingZeros(1l << 39), + Long.numberOfLeadingZeros(1l << 40), + Long.numberOfLeadingZeros(1l << 41), + Long.numberOfLeadingZeros(1l << 42), + Long.numberOfLeadingZeros(1l << 43), + Long.numberOfLeadingZeros(1l << 44), + Long.numberOfLeadingZeros(1l << 45), + Long.numberOfLeadingZeros(1l << 46), + Long.numberOfLeadingZeros(1l << 47), + Long.numberOfLeadingZeros(1l << 48), + Long.numberOfLeadingZeros(1l << 49), + Long.numberOfLeadingZeros(1l << 50), + Long.numberOfLeadingZeros(1l << 51), + Long.numberOfLeadingZeros(1l << 52), + Long.numberOfLeadingZeros(1l << 53), + Long.numberOfLeadingZeros(1l << 54), + Long.numberOfLeadingZeros(1l << 55), + Long.numberOfLeadingZeros(1l << 56), + Long.numberOfLeadingZeros(1l << 57), + Long.numberOfLeadingZeros(1l << 58), + Long.numberOfLeadingZeros(1l << 59), + Long.numberOfLeadingZeros(1l << 60), + Long.numberOfLeadingZeros(1l << 61), + Long.numberOfLeadingZeros(1l << 62), + Long.numberOfLeadingZeros(1l << 63), + }; + } + + // Test the range of CLZ with random long input. + // The result of CLZ should be in range [0, 64], so CLZs in this test are + // expected to be optimized away, and the test should always return false. + @Test + @IR(failOn = IRNode.COUNT_LEADING_ZEROS_L) + public boolean clzCompareLong(long randLong) { + return Long.numberOfLeadingZeros(randLong) < 0 + || Long.numberOfLeadingZeros(randLong) > 64; + } + + // Test the combination of CLZ and division by 8. + // The result of CLZ should be positive, so the division by 8 should be + // optimized to a simple right shift without rounding. + @Test + @IR(counts = {IRNode.COUNT_LEADING_ZEROS_L, "1", + IRNode.RSHIFT_I, "1", + IRNode.URSHIFT_I, "0", + IRNode.ADD_I, "0"}) + public int clzDiv8Long(long randLong) { + return Long.numberOfLeadingZeros(randLong) / 8; + } + + // Test the output range of CLZ with random input range. + @Test + public int clzRandLimitLong(long randLong) { + randLong = RANGE_LONG.clamp(randLong); + int result = Long.numberOfLeadingZeros(randLong); + return getResultChecksum64(result); + } + + @DontCompile + public int clzRandLimitInterpretedLong(long randLong) { + randLong = RANGE_LONG.clamp(randLong); + int result = Long.numberOfLeadingZeros(randLong); + return getResultChecksum64(result); + } + + // Test CTZ with constant integer inputs. + // All CTZs in this test are expected to be optimized away. + @Test + @IR(failOn = IRNode.COUNT_TRAILING_ZEROS_I) + public int[] ctzConstInts() { + return new int[] { + Integer.numberOfTrailingZeros(0), + Integer.numberOfTrailingZeros(1 << 0), + Integer.numberOfTrailingZeros(1 << 1), + Integer.numberOfTrailingZeros(1 << 2), + Integer.numberOfTrailingZeros(1 << 3), + Integer.numberOfTrailingZeros(1 << 4), + Integer.numberOfTrailingZeros(1 << 5), + Integer.numberOfTrailingZeros(1 << 6), + Integer.numberOfTrailingZeros(1 << 7), + Integer.numberOfTrailingZeros(1 << 8), + Integer.numberOfTrailingZeros(1 << 9), + Integer.numberOfTrailingZeros(1 << 10), + Integer.numberOfTrailingZeros(1 << 11), + Integer.numberOfTrailingZeros(1 << 12), + Integer.numberOfTrailingZeros(1 << 13), + Integer.numberOfTrailingZeros(1 << 14), + Integer.numberOfTrailingZeros(1 << 15), + Integer.numberOfTrailingZeros(1 << 16), + Integer.numberOfTrailingZeros(1 << 17), + Integer.numberOfTrailingZeros(1 << 18), + Integer.numberOfTrailingZeros(1 << 19), + Integer.numberOfTrailingZeros(1 << 20), + Integer.numberOfTrailingZeros(1 << 21), + Integer.numberOfTrailingZeros(1 << 22), + Integer.numberOfTrailingZeros(1 << 23), + Integer.numberOfTrailingZeros(1 << 24), + Integer.numberOfTrailingZeros(1 << 25), + Integer.numberOfTrailingZeros(1 << 26), + Integer.numberOfTrailingZeros(1 << 27), + Integer.numberOfTrailingZeros(1 << 28), + Integer.numberOfTrailingZeros(1 << 29), + Integer.numberOfTrailingZeros(1 << 30), + Integer.numberOfTrailingZeros(1 << 31), + }; + } + + // Test the range of CTZ with random integer input. + // The result of CTZ should be in range [0, 32], so CTZs in this test are + // expected to be optimized away, and the test should always return false. + @Test + @IR(failOn = IRNode.COUNT_TRAILING_ZEROS_I) + public boolean ctzCompareInt(int randInt) { + return Integer.numberOfTrailingZeros(randInt) < 0 + || Integer.numberOfTrailingZeros(randInt) > 32; + } + + // Test the combination of CTZ and division by 8. + // The result of CTZ should be positive, so the division by 8 should be + // optimized to a simple right shift without rounding. + @Test + @IR(counts = {IRNode.COUNT_TRAILING_ZEROS_I, "1", + IRNode.RSHIFT_I, "1", + IRNode.URSHIFT_I, "0", + IRNode.ADD_I, "0"}) + public int ctzDiv8Int(int randInt) { + return Integer.numberOfTrailingZeros(randInt) / 8; + } + + // Test the output range of CTZ with random input range. + @Test + public int ctzRandLimitInt(int randInt) { + randInt = RANGE_INT.clamp(randInt); + int result = Integer.numberOfTrailingZeros(randInt); + return getResultChecksum32(result); + } + + @DontCompile + public int ctzRandLimitInterpretedInt(int randInt) { + randInt = RANGE_INT.clamp(randInt); + int result = Integer.numberOfTrailingZeros(randInt); + return getResultChecksum32(result); + } + + // Test CTZ with constant long inputs. + // All CTZs in this test are expected to be optimized away. + @Test + @IR(failOn = IRNode.COUNT_TRAILING_ZEROS_L) + public int[] ctzConstLongs() { + return new int[] { + Long.numberOfTrailingZeros(0), + Long.numberOfTrailingZeros(1l << 0), + Long.numberOfTrailingZeros(1l << 1), + Long.numberOfTrailingZeros(1l << 2), + Long.numberOfTrailingZeros(1l << 3), + Long.numberOfTrailingZeros(1l << 4), + Long.numberOfTrailingZeros(1l << 5), + Long.numberOfTrailingZeros(1l << 6), + Long.numberOfTrailingZeros(1l << 7), + Long.numberOfTrailingZeros(1l << 8), + Long.numberOfTrailingZeros(1l << 9), + Long.numberOfTrailingZeros(1l << 10), + Long.numberOfTrailingZeros(1l << 11), + Long.numberOfTrailingZeros(1l << 12), + Long.numberOfTrailingZeros(1l << 13), + Long.numberOfTrailingZeros(1l << 14), + Long.numberOfTrailingZeros(1l << 15), + Long.numberOfTrailingZeros(1l << 16), + Long.numberOfTrailingZeros(1l << 17), + Long.numberOfTrailingZeros(1l << 18), + Long.numberOfTrailingZeros(1l << 19), + Long.numberOfTrailingZeros(1l << 20), + Long.numberOfTrailingZeros(1l << 21), + Long.numberOfTrailingZeros(1l << 22), + Long.numberOfTrailingZeros(1l << 23), + Long.numberOfTrailingZeros(1l << 24), + Long.numberOfTrailingZeros(1l << 25), + Long.numberOfTrailingZeros(1l << 26), + Long.numberOfTrailingZeros(1l << 27), + Long.numberOfTrailingZeros(1l << 28), + Long.numberOfTrailingZeros(1l << 29), + Long.numberOfTrailingZeros(1l << 30), + Long.numberOfTrailingZeros(1l << 31), + Long.numberOfTrailingZeros(1l << 32), + Long.numberOfTrailingZeros(1l << 33), + Long.numberOfTrailingZeros(1l << 34), + Long.numberOfTrailingZeros(1l << 35), + Long.numberOfTrailingZeros(1l << 36), + Long.numberOfTrailingZeros(1l << 37), + Long.numberOfTrailingZeros(1l << 38), + Long.numberOfTrailingZeros(1l << 39), + Long.numberOfTrailingZeros(1l << 40), + Long.numberOfTrailingZeros(1l << 41), + Long.numberOfTrailingZeros(1l << 42), + Long.numberOfTrailingZeros(1l << 43), + Long.numberOfTrailingZeros(1l << 44), + Long.numberOfTrailingZeros(1l << 45), + Long.numberOfTrailingZeros(1l << 46), + Long.numberOfTrailingZeros(1l << 47), + Long.numberOfTrailingZeros(1l << 48), + Long.numberOfTrailingZeros(1l << 49), + Long.numberOfTrailingZeros(1l << 50), + Long.numberOfTrailingZeros(1l << 51), + Long.numberOfTrailingZeros(1l << 52), + Long.numberOfTrailingZeros(1l << 53), + Long.numberOfTrailingZeros(1l << 54), + Long.numberOfTrailingZeros(1l << 55), + Long.numberOfTrailingZeros(1l << 56), + Long.numberOfTrailingZeros(1l << 57), + Long.numberOfTrailingZeros(1l << 58), + Long.numberOfTrailingZeros(1l << 59), + Long.numberOfTrailingZeros(1l << 60), + Long.numberOfTrailingZeros(1l << 61), + Long.numberOfTrailingZeros(1l << 62), + Long.numberOfTrailingZeros(1l << 63), + }; + } + + // Test the range of CTZ with random long input. + // The result of CTZ should be in range [0, 64], so CTZs in this test are + // expected to be optimized away, and the test should always return false. + @Test + @IR(failOn = IRNode.COUNT_TRAILING_ZEROS_L) + public boolean ctzCompareLong(long randLong) { + return Long.numberOfTrailingZeros(randLong) < 0 + || Long.numberOfTrailingZeros(randLong) > 64; + } + + // Test the combination of CTZ and division by 8. + // The result of CTZ should be positive, so the division by 8 should be + // optimized to a simple right shift without rounding. + @Test + @IR(counts = {IRNode.COUNT_TRAILING_ZEROS_L, "1", + IRNode.RSHIFT_I, "1", + IRNode.URSHIFT_I, "0", + IRNode.ADD_I, "0"}) + public int ctzDiv8Long(long randLong) { + return Long.numberOfTrailingZeros(randLong) / 8; + } + + // Test the output range of CTZ with random input range. + @Test + public int ctzRandLimitLong(long randLong) { + randLong = RANGE_LONG.clamp(randLong); + int result = Long.numberOfLeadingZeros(randLong); + return getResultChecksum64(result); + } + + @DontCompile + public int ctzRandLimitInterpretedLong(long randLong) { + randLong = RANGE_LONG.clamp(randLong); + int result = Long.numberOfLeadingZeros(randLong); + return getResultChecksum64(result); + } + + record IntRange(int lo, int hi) { + IntRange { + if (lo > hi) { + throw new IllegalArgumentException("lo > hi"); + } + } + + @ForceInline + int clamp(int v) { + return v < lo ? lo : v > hi ? hi : v; + } + + static IntRange generate(Generator g) { + int a = g.next(), b = g.next(); + return a < b ? new IntRange(a, b) : new IntRange(b, a); + } + } + + record LongRange(long lo, long hi) { + LongRange { + if (lo > hi) { + throw new IllegalArgumentException("lo > hi"); + } + } + + @ForceInline + long clamp(long v) { + return v < lo ? lo : v > hi ? hi : v; + } + + static LongRange generate(Generator g) { + long a = g.next(), b = g.next(); + return a < b ? new LongRange(a, b) : new LongRange(b, a); + } + } + + @ForceInline + int getResultChecksum32(int result) { + int sum = 0; + if (result < LIMITS_32_0) sum += 1; + if (result < LIMITS_32_1) sum += 2; + if (result < LIMITS_32_2) sum += 4; + if (result < LIMITS_32_3) sum += 8; + if (result > LIMITS_32_4) sum += 16; + if (result > LIMITS_32_5) sum += 32; + if (result > LIMITS_32_6) sum += 64; + if (result > LIMITS_32_7) sum += 128; + return sum; + } + + @ForceInline + int getResultChecksum64(int result) { + int sum = 0; + if (result < LIMITS_64_0) sum += 1; + if (result < LIMITS_64_1) sum += 2; + if (result < LIMITS_64_2) sum += 4; + if (result < LIMITS_64_3) sum += 8; + if (result > LIMITS_64_4) sum += 16; + if (result > LIMITS_64_5) sum += 32; + if (result > LIMITS_64_6) sum += 64; + if (result > LIMITS_64_7) sum += 128; + return sum; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 85595b9b632..1648135434a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1661,6 +1661,16 @@ public class IRNode { vectorNode(POPCOUNT_VL, "PopCountVL", TYPE_LONG); } + public static final String COUNT_TRAILING_ZEROS_I = PREFIX + "COUNT_TRAILING_ZEROS_I" + POSTFIX; + static { + beforeMatchingNameRegex(COUNT_TRAILING_ZEROS_I, "CountTrailingZerosI"); + } + + public static final String COUNT_TRAILING_ZEROS_L = PREFIX + "COUNT_TRAILING_ZEROS_L" + POSTFIX; + static { + beforeMatchingNameRegex(COUNT_TRAILING_ZEROS_L, "CountTrailingZerosL"); + } + public static final String COUNT_TRAILING_ZEROS_VL = VECTOR_PREFIX + "COUNT_TRAILING_ZEROS_VL" + POSTFIX; static { vectorNode(COUNT_TRAILING_ZEROS_VL, "CountTrailingZerosV", TYPE_LONG); @@ -1671,6 +1681,16 @@ public class IRNode { vectorNode(COUNT_TRAILING_ZEROS_VI, "CountTrailingZerosV", TYPE_INT); } + public static final String COUNT_LEADING_ZEROS_I = PREFIX + "COUNT_LEADING_ZEROS_I" + POSTFIX; + static { + beforeMatchingNameRegex(COUNT_LEADING_ZEROS_I, "CountLeadingZerosI"); + } + + public static final String COUNT_LEADING_ZEROS_L = PREFIX + "COUNT_LEADING_ZEROS_L" + POSTFIX; + static { + beforeMatchingNameRegex(COUNT_LEADING_ZEROS_L, "CountLeadingZerosL"); + } + public static final String COUNT_LEADING_ZEROS_VL = VECTOR_PREFIX + "COUNT_LEADING_ZEROS_VL" + POSTFIX; static { vectorNode(COUNT_LEADING_ZEROS_VL, "CountLeadingZerosV", TYPE_LONG); diff --git a/test/micro/org/openjdk/bench/vm/compiler/CountLeadingZeros.java b/test/micro/org/openjdk/bench/vm/compiler/CountLeadingZeros.java new file mode 100644 index 00000000000..dc06e3ae764 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/CountLeadingZeros.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025 Alibaba Group Holding Limited. All Rights Reserved. + * 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 org.openjdk.jmh.annotations.*; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.ThreadLocalRandom; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 3) +@Warmup(iterations = 10, time = 1) +@Measurement(iterations = 5, time = 1) +@State(Scope.Thread) +public class CountLeadingZeros { + private long[] longArray = new long[1000]; + + @Setup + public void setup() { + for (int i = 0; i < longArray.length; i++) { + longArray[i] = ThreadLocalRandom.current().nextLong(); + } + } + + @Benchmark + public int benchNumberOfNibbles() { + int sum = 0; + for (long l : longArray) { + sum += numberOfNibbles((int) l); + } + return sum; + } + + public static int numberOfNibbles(int i) { + int mag = Integer.SIZE - Integer.numberOfLeadingZeros(i); + return Math.max((mag + 3) / 4, 1); + } + + @Benchmark + public int benchClzLongConstrained() { + int sum = 0; + for (long l : longArray) { + sum += clzLongConstrained(l); + } + return sum; + } + + public static int clzLongConstrained(long param) { + long constrainedParam = Math.min(175, Math.max(param, 160)); + return Long.numberOfLeadingZeros(constrainedParam); + } +} From 6700baa5052046f53eb1b04ed3205bbd8e9e9070 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Mon, 8 Dec 2025 13:38:22 +0000 Subject: [PATCH 092/141] 8357551: RISC-V: support CMoveF/D vectorization Reviewed-by: fyang, luhenry --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 77 ++ .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 7 + .../cpu/riscv/macroAssembler_riscv.cpp | 256 +++- .../cpu/riscv/macroAssembler_riscv.hpp | 18 + src/hotspot/cpu/riscv/riscv.ad | 282 +++- ...onalMove.java => TestConditionalMove.java} | 731 ++++++++++- .../c2/irTests/TestFPComparison2.java | 1140 ++++++++++++++++- .../TestScalarConditionalMoveCmpObj.java | 357 ++++++ .../compiler/lib/ir_framework/IRNode.java | 30 + .../bench/java/lang/ClassComparison.java | 45 +- .../openjdk/bench/java/lang/FPComparison.java | 176 ++- .../bench/java/lang/IntegerComparison.java | 292 ++++- .../bench/java/lang/LongComparison.java | 291 ++++- .../bench/java/lang/PointerComparison.java | 45 +- 14 files changed, 3604 insertions(+), 143 deletions(-) rename test/hotspot/jtreg/compiler/c2/irTests/{TestVectorConditionalMove.java => TestConditionalMove.java} (76%) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index abbd7eedbba..dcf20752a21 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2067,6 +2067,83 @@ void C2_MacroAssembler::enc_cmove_cmp_fp(int cmpFlag, FloatRegister op1, FloatRe } } +void C2_MacroAssembler::enc_cmove_fp_cmp(int cmpFlag, Register op1, Register op2, + FloatRegister dst, FloatRegister src, bool is_single) { + bool is_unsigned = (cmpFlag & unsigned_branch_mask) == unsigned_branch_mask; + int op_select = cmpFlag & (~unsigned_branch_mask); + + switch (op_select) { + case BoolTest::eq: + cmov_fp_eq(op1, op2, dst, src, is_single); + break; + case BoolTest::ne: + cmov_fp_ne(op1, op2, dst, src, is_single); + break; + case BoolTest::le: + if (is_unsigned) { + cmov_fp_leu(op1, op2, dst, src, is_single); + } else { + cmov_fp_le(op1, op2, dst, src, is_single); + } + break; + case BoolTest::ge: + if (is_unsigned) { + cmov_fp_geu(op1, op2, dst, src, is_single); + } else { + cmov_fp_ge(op1, op2, dst, src, is_single); + } + break; + case BoolTest::lt: + if (is_unsigned) { + cmov_fp_ltu(op1, op2, dst, src, is_single); + } else { + cmov_fp_lt(op1, op2, dst, src, is_single); + } + break; + case BoolTest::gt: + if (is_unsigned) { + cmov_fp_gtu(op1, op2, dst, src, is_single); + } else { + cmov_fp_gt(op1, op2, dst, src, is_single); + } + break; + default: + assert(false, "unsupported compare condition"); + ShouldNotReachHere(); + } +} + +void C2_MacroAssembler::enc_cmove_fp_cmp_fp(int cmpFlag, + FloatRegister op1, FloatRegister op2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + int op_select = cmpFlag & (~unsigned_branch_mask); + + switch (op_select) { + case BoolTest::eq: + cmov_fp_cmp_fp_eq(op1, op2, dst, src, cmp_single, cmov_single); + break; + case BoolTest::ne: + cmov_fp_cmp_fp_ne(op1, op2, dst, src, cmp_single, cmov_single); + break; + case BoolTest::le: + cmov_fp_cmp_fp_le(op1, op2, dst, src, cmp_single, cmov_single); + break; + case BoolTest::ge: + cmov_fp_cmp_fp_ge(op1, op2, dst, src, cmp_single, cmov_single); + break; + case BoolTest::lt: + cmov_fp_cmp_fp_lt(op1, op2, dst, src, cmp_single, cmov_single); + break; + case BoolTest::gt: + cmov_fp_cmp_fp_gt(op1, op2, dst, src, cmp_single, cmov_single); + break; + default: + assert(false, "unsupported compare condition"); + ShouldNotReachHere(); + } +} + // Set dst to NaN if any NaN input. void C2_MacroAssembler::minmax_fp(FloatRegister dst, FloatRegister src1, FloatRegister src2, FLOAT_TYPE ft, bool is_min) { diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index f08e5e27c87..fa87ceba295 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -132,6 +132,13 @@ FloatRegister op1, FloatRegister op2, Register dst, Register src, bool is_single); + void enc_cmove_fp_cmp(int cmpFlag, Register op1, Register op2, + FloatRegister dst, FloatRegister src, bool is_single); + + void enc_cmove_fp_cmp_fp(int cmpFlag, FloatRegister op1, FloatRegister op2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single); + void spill(Register r, bool is64, int offset) { is64 ? sd(r, Address(sp, offset)) : sw(r, Address(sp, offset)); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 7a8496ae42b..a14a051fd3b 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1233,7 +1233,119 @@ void MacroAssembler::cmov_gtu(Register cmp1, Register cmp2, Register dst, Regist bind(no_set); } -// ----------- cmove, compare float ----------- +// ----------- cmove float/double ----------- + +void MacroAssembler::cmov_fp_eq(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bne(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_ne(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + beq(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_le(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bgt(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_leu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bgtu(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_ge(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + blt(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_geu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bltu(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_lt(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bge(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_ltu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bgeu(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_gt(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + ble(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_gtu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single) { + Label no_set; + bleu(cmp1, cmp2, no_set); + if (is_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +// ----------- cmove, compare float/double ----------- // // For CmpF/D + CMoveI/L, ordered ones are quite straight and simple, // so, just list behaviour of unordered ones as follow. @@ -1391,6 +1503,148 @@ void MacroAssembler::cmov_cmp_fp_gt(FloatRegister cmp1, FloatRegister cmp2, Regi bind(no_set); } +// ----------- cmove float/double, compare float/double ----------- + +// Move src to dst only if cmp1 == cmp2, +// otherwise leave dst unchanged, including the case where one of them is NaN. +// Clarification: +// java code : cmp1 != cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 eq cmp2), dst, src +void MacroAssembler::cmov_fp_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 != cmp2, including the case of NaN + // not jump (i.e. move src to dst) if cmp1 == cmp2 + float_bne(cmp1, cmp2, no_set); + } else { + double_bne(cmp1, cmp2, no_set); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +// Keep dst unchanged only if cmp1 == cmp2, +// otherwise move src to dst, including the case where one of them is NaN. +// Clarification: +// java code : cmp1 == cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 ne cmp2), dst, src +void MacroAssembler::cmov_fp_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 == cmp2 + // not jump (i.e. move src to dst) if cmp1 != cmp2, including the case of NaN + float_beq(cmp1, cmp2, no_set); + } else { + double_beq(cmp1, cmp2, no_set); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +// When cmp1 <= cmp2 or any of them is NaN then dst = src, otherwise, dst = dst +// Clarification +// scenario 1: +// java code : cmp2 < cmp1 ? dst : src +// transformed to : CMove dst, (cmp1 le cmp2), dst, src +// scenario 2: +// java code : cmp1 > cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 le cmp2), dst, src +void MacroAssembler::cmov_fp_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 > cmp2 + // not jump (i.e. move src to dst) if cmp1 <= cmp2 or either is NaN + float_bgt(cmp1, cmp2, no_set); + } else { + double_bgt(cmp1, cmp2, no_set); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_cmp_fp_ge(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 < cmp2 or either is NaN + // not jump (i.e. move src to dst) if cmp1 >= cmp2 + float_blt(cmp1, cmp2, no_set, false, true); + } else { + double_blt(cmp1, cmp2, no_set, false, true); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +// When cmp1 < cmp2 or any of them is NaN then dst = src, otherwise, dst = dst +// Clarification +// scenario 1: +// java code : cmp2 <= cmp1 ? dst : src +// transformed to : CMove dst, (cmp1 lt cmp2), dst, src +// scenario 2: +// java code : cmp1 >= cmp2 ? dst : src +// transformed to : CMove dst, (cmp1 lt cmp2), dst, src +void MacroAssembler::cmov_fp_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 >= cmp2 + // not jump (i.e. move src to dst) if cmp1 < cmp2 or either is NaN + float_bge(cmp1, cmp2, no_set); + } else { + double_bge(cmp1, cmp2, no_set); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + +void MacroAssembler::cmov_fp_cmp_fp_gt(FloatRegister cmp1, FloatRegister cmp2, + FloatRegister dst, FloatRegister src, + bool cmp_single, bool cmov_single) { + Label no_set; + if (cmp_single) { + // jump if cmp1 <= cmp2 or either is NaN + // not jump (i.e. move src to dst) if cmp1 > cmp2 + float_ble(cmp1, cmp2, no_set, false, true); + } else { + double_ble(cmp1, cmp2, no_set, false, true); + } + if (cmov_single) { + fmv_s(dst, src); + } else { + fmv_d(dst, src); + } + bind(no_set); +} + // Float compare branch instructions #define INSN(NAME, FLOATCMP, BRANCH) \ diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 1908b9a9605..3b021388fa5 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -665,6 +665,24 @@ class MacroAssembler: public Assembler { void cmov_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); void cmov_cmp_fp_gt(FloatRegister cmp1, FloatRegister cmp2, Register dst, Register src, bool is_single); + void cmov_fp_eq(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_ne(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_le(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_leu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_ge(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_geu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_lt(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_ltu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_gt(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + void cmov_fp_gtu(Register cmp1, Register cmp2, FloatRegister dst, FloatRegister src, bool is_single); + + void cmov_fp_cmp_fp_eq(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + void cmov_fp_cmp_fp_ne(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + void cmov_fp_cmp_fp_le(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + void cmov_fp_cmp_fp_ge(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + void cmov_fp_cmp_fp_lt(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + void cmov_fp_cmp_fp_gt(FloatRegister cmp1, FloatRegister cmp2, FloatRegister dst, FloatRegister src, bool cmp_single, bool cmov_single); + public: // We try to follow risc-v asm menomics. // But as we don't layout a reachable GOT, diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 3f5dd4ad0ee..96984ba9a42 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1924,8 +1924,6 @@ bool Matcher::match_rule_supported(int opcode) { case Op_SubHF: return UseZfh; - case Op_CMoveF: - case Op_CMoveD: case Op_CMoveP: case Op_CMoveN: return false; @@ -10466,6 +10464,286 @@ instruct cmovL_cmpP(iRegLNoSp dst, iRegL src, iRegP op1, iRegP op2, cmpOpU cop) ins_pipe(pipe_class_compare); %} +// --------- CMoveF --------- + +instruct cmovF_cmpI(fRegF dst, fRegF src, iRegI op1, iRegI op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpI op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpI\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpU(fRegF dst, fRegF src, iRegI op1, iRegI op2, cmpOpU cop) %{ + match(Set dst (CMoveF (Binary cop (CmpU op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpU\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpL(fRegF dst, fRegF src, iRegL op1, iRegL op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpL\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpUL(fRegF dst, fRegF src, iRegL op1, iRegL op2, cmpOpU cop) %{ + match(Set dst (CMoveF (Binary cop (CmpUL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpUL\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpF(fRegF dst, fRegF src, fRegF op1, fRegF op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpF op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpF\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp_fp($cop$$cmpcode, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + true /* cmp_single */, true /* cmov_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpD(fRegF dst, fRegF src, fRegD op1, fRegD op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpD op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpD\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp_fp($cop$$cmpcode | C2_MacroAssembler::double_branch_mask, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + false /* cmp_single */, true /* cmov_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpN(fRegF dst, fRegF src, iRegN op1, iRegN op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpN op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpN\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovF_cmpP(fRegF dst, fRegF src, iRegP op1, iRegP op2, cmpOp cop) %{ + match(Set dst (CMoveF (Binary cop (CmpP op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveF $dst, ($op1 $cop $op2), $dst, $src\t#@cmovF_cmpP\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), true /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +// --------- CMoveD --------- + +instruct cmovD_cmpI(fRegD dst, fRegD src, iRegI op1, iRegI op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpI op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpI\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpU(fRegD dst, fRegD src, iRegI op1, iRegI op2, cmpOpU cop) %{ + match(Set dst (CMoveD (Binary cop (CmpU op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpU\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpL(fRegD dst, fRegD src, iRegL op1, iRegL op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpL\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpUL(fRegD dst, fRegD src, iRegL op1, iRegL op2, cmpOpU cop) %{ + match(Set dst (CMoveD (Binary cop (CmpUL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpUL\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpF(fRegD dst, fRegD src, fRegF op1, fRegF op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpF op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpF\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp_fp($cop$$cmpcode, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + true /* cmp_single */, false /* cmov_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpD(fRegD dst, fRegD src, fRegD op1, fRegD op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpD op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpD\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp_fp($cop$$cmpcode | C2_MacroAssembler::double_branch_mask, + as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + false /* cmp_single */, false /* cmov_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpN(fRegD dst, fRegD src, iRegN op1, iRegN op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpN op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpN\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct cmovD_cmpP(fRegD dst, fRegD src, iRegP op1, iRegP op2, cmpOp cop) %{ + match(Set dst (CMoveD (Binary cop (CmpP op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "CMoveD $dst, ($op1 $cop $op2), $dst, $src\t#@cmovD_cmpP\n\t" + %} + + ins_encode %{ + __ enc_cmove_fp_cmp($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), false /* is_single */); + %} + + ins_pipe(pipe_class_compare); +%} + // ============================================================================ // Procedure Call/Return Instructions diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorConditionalMove.java b/test/hotspot/jtreg/compiler/c2/irTests/TestConditionalMove.java similarity index 76% rename from test/hotspot/jtreg/compiler/c2/irTests/TestVectorConditionalMove.java rename to test/hotspot/jtreg/compiler/c2/irTests/TestConditionalMove.java index 4759add94e9..c531f73b71d 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorConditionalMove.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestConditionalMove.java @@ -1,6 +1,7 @@ /* - * Copyright (c) 2022, Arm Limited. All rights reserved. - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Arm Limited. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, Rivos Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,14 +36,15 @@ import jdk.test.lib.Utils; * @key randomness * @summary Auto-vectorization enhancement to support vector conditional move. * @library /test/lib / - * @run driver compiler.c2.irTests.TestVectorConditionalMove + * @run driver compiler.c2.irTests.TestConditionalMove */ -public class TestVectorConditionalMove { +public class TestConditionalMove { final private static int SIZE = 1024; private static final Random RANDOM = Utils.getRandomInstance(); public static void main(String[] args) { + // Vectorizaion: +UseCMoveUnconditionally, +UseVectorCmov // Cross-product: +-AlignVector and +-UseCompactObjectHeaders TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov", "-XX:-UseCompactObjectHeaders", "-XX:-AlignVector"); @@ -52,6 +54,12 @@ public class TestVectorConditionalMove { "-XX:+UseCompactObjectHeaders", "-XX:-AlignVector"); TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:+UseVectorCmov", "-XX:+UseCompactObjectHeaders", "-XX:+AlignVector"); + + // Scalar: +UseCMoveUnconditionally, -UseVectorCmov + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders"); + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders"); } // Compare 2 values, and pick one of them @@ -564,6 +572,7 @@ public class TestVectorConditionalMove { return (a > b) ? c : d; } + // Double comparison private int cmoveDGTforI(double a, double b, int c, int d) { return (a > b) ? c : d; } @@ -586,7 +595,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVFGT(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] > b[i]) ? a[i] : b[i]; @@ -598,7 +613,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVFGTSwap(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] > a[i]) ? a[i] : b[i]; @@ -610,7 +631,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVFLT(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] < b[i]) ? a[i] : b[i]; @@ -622,7 +649,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVFLTSwap(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] < a[i]) ? a[i] : b[i]; @@ -634,7 +667,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVFEQ(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] == b[i]) ? a[i] : b[i]; @@ -646,7 +685,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVDLE(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] <= b[i]) ? a[i] : b[i]; @@ -658,7 +703,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVDLESwap(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] <= a[i]) ? a[i] : b[i]; @@ -670,7 +721,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVDGE(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] >= b[i]) ? a[i] : b[i]; @@ -682,7 +739,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVDGESwap(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (b[i] >= a[i]) ? a[i] : b[i]; @@ -694,7 +757,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveVDNE(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] != b[i]) ? a[i] : b[i]; @@ -707,7 +776,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] > b[i]) ? 0.1f : -0.1f; @@ -719,7 +794,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGEforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] >= b[i]) ? 0.1f : -0.1f; @@ -731,7 +812,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFLTforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] < b[i]) ? 0.1f : -0.1f; @@ -743,7 +830,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFLEforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] <= b[i]) ? 0.1f : -0.1f; @@ -755,7 +848,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFEQforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] == b[i]) ? 0.1f : -0.1f; @@ -767,7 +866,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFNEQforFConst(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] != b[i]) ? 0.1f : -0.1f; @@ -779,8 +884,19 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfOr = {"UseCompactObjectHeaders", "false", "AlignVector", "false"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfAnd = {"UseCompactObjectHeaders", "false", "UseVectorCmov", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_F, ">0", + IRNode.VECTOR_MASK_CMP_F, ">0", + IRNode.VECTOR_BLEND_F, ">0", + IRNode.STORE_VECTOR, ">0"}, + applyIfAnd = {"AlignVector", "false", "UseVectorCmov", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFLTforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1f : -0.1f; @@ -797,8 +913,19 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfOr = {"UseCompactObjectHeaders", "false", "AlignVector", "false"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfAnd = {"UseCompactObjectHeaders", "false", "UseVectorCmov", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) + @IR(counts = {IRNode.LOAD_VECTOR_F, ">0", + IRNode.VECTOR_MASK_CMP_F, ">0", + IRNode.VECTOR_BLEND_F, ">0", + IRNode.STORE_VECTOR, ">0"}, + applyIfAnd = {"AlignVector", "false", "UseVectorCmov", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFLEforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1f : -0.1f; @@ -815,7 +942,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, "=0", IRNode.VECTOR_BLEND_F, "=0", IRNode.STORE_VECTOR, "=0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFYYforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1f : -0.1f; @@ -828,7 +961,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, "=0", IRNode.VECTOR_BLEND_F, "=0", IRNode.STORE_VECTOR, "=0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFXXforFConstH2(float[] a, float[] b, float[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1f : -0.1f; @@ -841,7 +980,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGTforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] > b[i]) ? 0.1 : -0.1; @@ -853,7 +998,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGEforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] >= b[i]) ? 0.1 : -0.1; @@ -865,7 +1016,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDLTforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] < b[i]) ? 0.1 : -0.1; @@ -877,7 +1034,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDLEforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] <= b[i]) ? 0.1 : -0.1; @@ -889,7 +1052,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDEQforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] == b[i]) ? 0.1 : -0.1; @@ -901,7 +1070,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDNEQforDConst(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i++) { c[i] = (a[i] != b[i]) ? 0.1 : -0.1; @@ -913,7 +1088,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDLTforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1 : -0.1; @@ -926,7 +1107,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDLEforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1 : -0.1; @@ -939,7 +1126,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, "=0", IRNode.VECTOR_BLEND_D, "=0", IRNode.STORE_VECTOR, "=0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDYYforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] <= b[i+0]) ? 0.1 : -0.1; @@ -952,7 +1145,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, "=0", IRNode.VECTOR_BLEND_D, "=0", IRNode.STORE_VECTOR, "=0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDXXforDConstH2(double[] a, double[] b, double[] c) { for (int i = 0; i < a.length; i+=2) { c[i+0] = (a[i+0] < b[i+0]) ? 0.1 : -0.1; @@ -966,10 +1165,15 @@ public class TestVectorConditionalMove { // do not float down into the branches, I compute a value, and store it to r2 (same as r, except that the // compilation does not know that). // So far, vectorization only works for CMoveF/D, with same data-width comparison (F/I for F, D/L for D). + // TODO: enable CMOVE_I/L verification when it's guaranteed to generate CMOVE_I/L, JDK-8371984. + // // Signed comparison: I/L // I fo I @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIEQforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -981,6 +1185,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveINEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -992,6 +1199,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGTforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1003,6 +1213,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1014,6 +1227,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILTforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1025,6 +1241,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1037,6 +1256,9 @@ public class TestVectorConditionalMove { // I fo L @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIEQforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1048,6 +1270,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveINEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1059,6 +1284,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGTforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1070,6 +1298,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1081,6 +1312,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILTforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1092,6 +1326,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_I, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1108,7 +1345,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIEQforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1124,7 +1367,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveINEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1140,7 +1389,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1156,7 +1411,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1172,7 +1433,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1188,7 +1455,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1201,6 +1474,9 @@ public class TestVectorConditionalMove { // I fo D @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIEQforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1212,6 +1488,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveINEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1223,6 +1502,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1234,6 +1516,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveIGEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1245,6 +1530,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1256,6 +1544,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_I, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveILEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1268,6 +1559,9 @@ public class TestVectorConditionalMove { // L fo I @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLEQforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1279,6 +1573,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLNEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1290,6 +1587,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGTforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1301,6 +1601,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1312,6 +1615,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLTforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1323,6 +1629,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1335,6 +1644,9 @@ public class TestVectorConditionalMove { // L fo L @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLEQforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1346,6 +1658,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLNEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1357,6 +1672,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGTforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1368,6 +1686,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1379,6 +1700,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLTforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1390,6 +1714,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_L, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1402,6 +1729,9 @@ public class TestVectorConditionalMove { // L fo F @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLEQforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1413,6 +1743,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLNEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1424,6 +1757,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1435,6 +1771,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLGEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1446,6 +1785,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1457,6 +1799,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveLLEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1473,7 +1818,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLEQforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1490,7 +1841,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLNEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1507,7 +1864,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLGTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1524,7 +1887,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLGEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1541,7 +1910,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLLTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1558,7 +1933,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_L, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveLLEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -1573,6 +1954,9 @@ public class TestVectorConditionalMove { // I fo I @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIEQforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1584,6 +1968,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUINEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1595,6 +1982,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGTforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1606,6 +1996,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1617,6 +2010,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILTforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1628,6 +2024,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILEforI(int[] a, int[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1640,6 +2039,9 @@ public class TestVectorConditionalMove { // I fo L @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIEQforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1651,6 +2053,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUINEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1662,6 +2067,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGTforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1673,6 +2081,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1684,6 +2095,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILTforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1695,6 +2109,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_U, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILEforL(int[] a, int[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1711,7 +2128,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIEQforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1727,7 +2150,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUINEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1743,7 +2172,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1759,7 +2194,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1775,7 +2216,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILTforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1791,7 +2238,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_I, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.VECTOR_BLEND_F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILEforF(int[] a, int[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -1804,6 +2257,9 @@ public class TestVectorConditionalMove { // I fo D @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIEQforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1815,6 +2271,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUINEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1826,6 +2285,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1837,6 +2299,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUIGEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1848,6 +2313,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILTforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1859,6 +2327,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_U, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveUILEforD(int[] a, int[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -1871,6 +2342,9 @@ public class TestVectorConditionalMove { // L fo I @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULEQforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1882,6 +2356,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULNEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1893,6 +2370,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGTforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1904,6 +2384,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1915,6 +2398,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLTforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1926,6 +2412,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLEforI(long[] a, long[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -1938,6 +2427,9 @@ public class TestVectorConditionalMove { // L fo L @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULEQforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1949,6 +2441,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULNEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1960,6 +2455,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGTforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1971,6 +2469,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1982,6 +2483,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLTforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -1993,6 +2497,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_UL, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLEforL(long[] a, long[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -2005,6 +2512,9 @@ public class TestVectorConditionalMove { // L fo F @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULEQforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2016,6 +2526,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULNEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2027,6 +2540,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2038,6 +2554,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULGEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2049,6 +2568,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLTforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2060,6 +2582,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveULLEforF(long[] a, long[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2076,7 +2601,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULEQforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2093,7 +2624,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULNEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2110,7 +2647,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULGTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2127,7 +2670,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULGEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2144,7 +2693,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULLTforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2161,7 +2716,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_L, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.VECTOR_BLEND_D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_UL, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) // Requires avx2, else L is restricted to 16 byte, and D has 32. That leads to a vector elements mismatch of 2 to 4. private static void testCMoveULLEforD(long[] a, long[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { @@ -2174,6 +2735,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_F, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforI(float[] a, float[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -2185,6 +2749,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_F, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforL(float[] a, float[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -2199,7 +2766,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforF(float[] a, float[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2211,6 +2784,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforD(float[] a, float[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2222,6 +2798,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_D, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGTforI(double[] a, double[] b, int[] c, int[] d, int[] r, int[] r2) { for (int i = 0; i < a.length; i++) { int cc = c[i]; @@ -2233,6 +2812,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_D, ">0"}, + // applyIf = {"UseVectorCmov", "false"}, + // applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGTforL(double[] a, double[] b, long[] c, long[] d, long[] r, long[] r2) { for (int i = 0; i < a.length; i++) { long cc = c[i]; @@ -2244,6 +2826,9 @@ public class TestVectorConditionalMove { @Test @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGTforF(double[] a, double[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; @@ -2258,7 +2843,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_D, ">0", IRNode.VECTOR_BLEND_D, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_D, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveDGTforD(double[] a, double[] b, double[] c, double[] d, double[] r, double[] r2) { for (int i = 0; i < a.length; i++) { double cc = c[i]; @@ -2274,7 +2865,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforFCmpCon1(float a, float[] b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < b.length; i++) { float cc = c[i]; @@ -2289,7 +2886,13 @@ public class TestVectorConditionalMove { IRNode.VECTOR_MASK_CMP_F, ">0", IRNode.VECTOR_BLEND_F, ">0", IRNode.STORE_VECTOR, ">0"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, + applyIf = {"UseVectorCmov", "true"}) + @IR(failOn = {IRNode.STORE_VECTOR}, + applyIf = {"UseVectorCmov", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_F, ">0"}, + applyIf = {"UseVectorCmov", "false"}, + applyIfPlatform = {"riscv64", "true"}) private static void testCMoveFGTforFCmpCon2(float[] a, float b, float[] c, float[] d, float[] r, float[] r2) { for (int i = 0; i < a.length; i++) { float cc = c[i]; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java index 59c70b6873f..8cf3f728666 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestFPComparison2.java @@ -28,7 +28,7 @@ import java.util.List; /* * @test - * @bug 8358892 + * @bug 8358892 8357551 * @summary The test is to trigger code path of BoolTest::ge/gt in C2_MacroAssembler::enc_cmove_cmp_fp * @requires os.arch == "riscv64" * @requires vm.debug @@ -77,18 +77,33 @@ public class TestFPComparison2 { public static void main(String[] args) { List options = List.of("-XX:-TieredCompilation", "-Xlog:jit+compilation=trace"); // Booltest::ge - TestFramework framework = new TestFramework(Test_ge_1.class); + TestFramework + framework = new TestFramework(Test_ge_1.class); + framework.addFlags(options.toArray(new String[0])).start(); + framework = new TestFramework(Test_ge_cmove_fp_1.class); framework.addFlags(options.toArray(new String[0])).start(); framework = new TestFramework(Test_ge_2.class); framework.addFlags(options.toArray(new String[0])).start(); + framework = new TestFramework(Test_ge_cmove_fp_2.class); + framework.addFlags(options.toArray(new String[0])).start(); // Booltest::gt framework = new TestFramework(Test_gt_1.class); framework.addFlags(options.toArray(new String[0])).start(); + framework = new TestFramework(Test_gt_cmove_fp_1.class); + framework.addFlags(options.toArray(new String[0])).start(); framework = new TestFramework(Test_gt_2.class); framework.addFlags(options.toArray(new String[0])).start(); + framework = new TestFramework(Test_gt_cmove_fp_2.class); + framework.addFlags(options.toArray(new String[0])).start(); + + // BoolTest::ge/gt in C2_MacroAssembler::enc_cmove_fp_cmp_fp + framework = new TestFramework(Test_cmov_fp_cmp_fp_ge_3.class); + framework.addFlags(options.toArray(new String[0])).start(); + framework = new TestFramework(Test_cmov_fp_cmp_fp_ge_4.class); + framework.addFlags(options.toArray(new String[0])).start(); } } @@ -320,6 +335,235 @@ class Test_ge_1 { } } + +class Test_ge_cmove_fp_1 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_1_0(float x, float y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x > y + // return 0 + // when neither is NaN, and x <= y + return !(x <= y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_1_0(float x, float y) { + return !(x <= y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_1_0(double x, double y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x > y + // return 0 + // when neither is NaN, and x <= y + return !(x <= y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_1_0(double x, double y) { + return !(x <= y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_0_1(float x, float y) { + return !(x <= y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_0_1(float x, float y) { + return !(x <= y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_0_1(double x, double y) { + return !(x <= y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_0_1(double x, double y) { + return !(x <= y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_10_20(float x, float y) { + return !(x <= y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_10_20(float x, float y) { + return !(x <= y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_10_20(double x, double y) { + return !(x <= y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_10_20(double x, double y) { + return !(x <= y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_variable_results(float x, float y, float a, float b) { + return !(x <= y) ? a : b; + } + @DontCompile + public static float golden_float_BoolTest_ge_variable_results(float x, float y, float a, float b) { + return !(x <= y) ? a : b; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_variable_results(double x, double y, float a, float b) { + return !(x <= y) ? a : b; + } + @DontCompile + public static float golden_double_BoolTest_ge_variable_results(double x, double y, float a, float b) { + return !(x <= y) ? a : b; + } + + @Run(test = {"test_float_BoolTest_ge_fixed_1_0", "test_double_BoolTest_ge_fixed_1_0", + "test_float_BoolTest_ge_fixed_0_1", "test_double_BoolTest_ge_fixed_0_1", + "test_float_BoolTest_ge_fixed_10_20", "test_double_BoolTest_ge_fixed_10_20", + "test_float_BoolTest_ge_variable_results", "test_double_BoolTest_ge_variable_results"}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_1_0(x, y); + float expected = golden_float_BoolTest_ge_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Float failed (ge, 1, 0), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_1_0(x, y); + float expected = golden_double_BoolTest_ge_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Double failed (ge, 1, 0), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_0_1(x, y); + float expected = golden_float_BoolTest_ge_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Float failed (ge, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_0_1(x, y); + float expected = golden_double_BoolTest_ge_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Double failed (ge, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_10_20(x, y); + float expected = golden_float_BoolTest_ge_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Float failed (ge, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_10_20(x, y); + float expected = golden_double_BoolTest_ge_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Double failed (ge, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_float_BoolTest_ge_variable_results(x, y, a, b); + float expected = golden_float_BoolTest_ge_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (ge), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_double_BoolTest_ge_variable_results(x, y, a, b); + float expected = golden_double_BoolTest_ge_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Double failed (ge), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} + class Test_ge_2 { @Test @IR(counts = {IRNode.CMOVE_I, "1"}) @@ -548,6 +792,234 @@ class Test_ge_2 { } } +class Test_ge_cmove_fp_2 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_1_0(float x, float y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x < y + // return 0 + // when neither is NaN, and x >= y + return !(x >= y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_1_0(float x, float y) { + return !(x >= y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_1_0(double x, double y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x < y + // return 0 + // when neither is NaN, and x >= y + return !(x >= y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_1_0(double x, double y) { + return !(x >= y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_0_1(float x, float y) { + return !(x >= y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_0_1(float x, float y) { + return !(x >= y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_0_1(double x, double y) { + return !(x >= y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_0_1(double x, double y) { + return !(x >= y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_fixed_10_20(float x, float y) { + return !(x >= y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_float_BoolTest_ge_fixed_10_20(float x, float y) { + return !(x >= y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_fixed_10_20(double x, double y) { + return !(x >= y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_double_BoolTest_ge_fixed_10_20(double x, double y) { + return !(x >= y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_variable_results(float x, float y, float a, float b) { + return !(x >= y) ? a : b; + } + @DontCompile + public static float golden_float_BoolTest_ge_variable_results(float x, float y, float a, float b) { + return !(x >= y) ? a : b; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_ge_variable_results(double x, double y, float a, float b) { + return !(x >= y) ? a : b; + } + @DontCompile + public static float golden_double_BoolTest_ge_variable_results(double x, double y, float a, float b) { + return !(x >= y) ? a : b; + } + + @Run(test = {"test_float_BoolTest_ge_fixed_1_0", "test_double_BoolTest_ge_fixed_1_0", + "test_float_BoolTest_ge_fixed_0_1", "test_double_BoolTest_ge_fixed_0_1", + "test_float_BoolTest_ge_fixed_10_20", "test_double_BoolTest_ge_fixed_10_20", + "test_float_BoolTest_ge_variable_results", "test_double_BoolTest_ge_variable_results"}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_1_0(x, y); + float expected = golden_float_BoolTest_ge_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Float failed (ge), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_1_0(x, y); + float expected = golden_double_BoolTest_ge_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Double failed (ge), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_0_1(x, y); + float expected = golden_float_BoolTest_ge_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Float failed (ge, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_0_1(x, y); + float expected = golden_double_BoolTest_ge_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Double failed (ge, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_ge_fixed_10_20(x, y); + float expected = golden_float_BoolTest_ge_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Float failed (ge, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_ge_fixed_10_20(x, y); + float expected = golden_double_BoolTest_ge_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Double failed (ge, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_float_BoolTest_ge_variable_results(x, y, a, b); + float expected = golden_float_BoolTest_ge_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (ge), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_double_BoolTest_ge_variable_results(x, y, a, b); + float expected = golden_double_BoolTest_ge_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Double failed (ge), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} + class Test_gt_1 { @Test @IR(counts = {IRNode.CMOVE_I, "1"}) @@ -776,6 +1248,234 @@ class Test_gt_1 { } } +class Test_gt_cmove_fp_1 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_1_0(float x, float y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x >= y + // return 0 + // when neither is NaN, and x < y + return !(x < y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_1_0(float x, float y) { + return !(x < y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_1_0(double x, double y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x >= y + // return 0 + // when neither is NaN, and x < y + return !(x < y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_1_0(double x, double y) { + return !(x < y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_0_1(float x, float y) { + return !(x < y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_0_1(float x, float y) { + return !(x < y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_0_1(double x, double y) { + return !(x < y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_0_1(double x, double y) { + return !(x < y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_10_20(float x, float y) { + return !(x < y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_10_20(float x, float y) { + return !(x < y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_10_20(double x, double y) { + return !(x < y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_10_20(double x, double y) { + return !(x < y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_variable_results(float x, float y, float a, float b) { + return !(x < y) ? a : b; + } + @DontCompile + public static float golden_float_BoolTest_gt_variable_results(float x, float y, float a, float b) { + return !(x < y) ? a : b; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_variable_results(double x, double y, float a, float b) { + return !(x < y) ? a : b; + } + @DontCompile + public static float golden_double_BoolTest_gt_variable_results(double x, double y, float a, float b) { + return !(x < y) ? a : b; + } + + @Run(test = {"test_float_BoolTest_gt_fixed_1_0", "test_double_BoolTest_gt_fixed_1_0", + "test_float_BoolTest_gt_fixed_0_1", "test_double_BoolTest_gt_fixed_0_1", + "test_float_BoolTest_gt_fixed_10_20", "test_double_BoolTest_gt_fixed_10_20", + "test_float_BoolTest_gt_variable_results", "test_double_BoolTest_gt_variable_results"}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_1_0(x, y); + float expected = golden_float_BoolTest_gt_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Float failed (gt), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_1_0(x, y); + float expected = golden_double_BoolTest_gt_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Double failed (gt), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_0_1(x, y); + float expected = golden_float_BoolTest_gt_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Float failed (gt, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_0_1(x, y); + float expected = golden_double_BoolTest_gt_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Double failed (gt, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_10_20(x, y); + float expected = golden_float_BoolTest_gt_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Float failed (gt, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_10_20(x, y); + float expected = golden_double_BoolTest_gt_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Double failed (gt, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_float_BoolTest_gt_variable_results(x, y, a, b); + float expected = golden_float_BoolTest_gt_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (gt), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_double_BoolTest_gt_variable_results(x, y, a, b); + float expected = golden_double_BoolTest_gt_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Double failed (gt), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} + class Test_gt_2 { @Test @IR(counts = {IRNode.CMOVE_I, "1"}) @@ -1003,3 +1703,439 @@ class Test_gt_2 { } } } + +class Test_gt_cmove_fp_2 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_1_0(float x, float y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x <= y + // return 0 + // when neither is NaN, and x > y + return !(x > y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_1_0(float x, float y) { + return !(x > y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_1_0(double x, double y) { + // return 1 + // when either x or y is NaN + // when neither is NaN, and x <= y + // return 0 + // when neither is NaN, and x > y + return !(x > y) ? 1.0f : 0.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_1_0(double x, double y) { + return !(x > y) ? 1.0f : 0.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_0_1(float x, float y) { + return !(x > y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_0_1(float x, float y) { + return !(x > y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_0_1(double x, double y) { + return !(x > y) ? 0.0f : 1.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_0_1(double x, double y) { + return !(x > y) ? 0.0f : 1.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_fixed_10_20(float x, float y) { + return !(x > y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_float_BoolTest_gt_fixed_10_20(float x, float y) { + return !(x > y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_fixed_10_20(double x, double y) { + return !(x > y) ? 10.0f : 20.0f; + } + @DontCompile + public static float golden_double_BoolTest_gt_fixed_10_20(double x, double y) { + return !(x > y) ? 10.0f : 20.0f; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_variable_results(float x, float y, float a, float b) { + return !(x > y) ? a : b; + } + @DontCompile + public static float golden_float_BoolTest_gt_variable_results(float x, float y, float a, float b) { + return !(x > y) ? a : b; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_double_BoolTest_gt_variable_results(double x, double y, float a, float b) { + return !(x > y) ? a : b; + } + @DontCompile + public static float golden_double_BoolTest_gt_variable_results(double x, double y, float a, float b) { + return !(x > y) ? a : b; + } + + @Run(test = {"test_float_BoolTest_gt_fixed_1_0", "test_double_BoolTest_gt_fixed_1_0", + "test_float_BoolTest_gt_fixed_0_1", "test_double_BoolTest_gt_fixed_0_1", + "test_float_BoolTest_gt_fixed_10_20", "test_double_BoolTest_gt_fixed_10_20", + "test_float_BoolTest_gt_variable_results", "test_double_BoolTest_gt_variable_results"}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_1_0(x, y); + float expected = golden_float_BoolTest_gt_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Float failed (gt), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_1_0(x, y); + float expected = golden_double_BoolTest_gt_fixed_1_0(x, y); + if (actual != expected) { + System.out.println("Double failed (gt), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_0_1(x, y); + float expected = golden_float_BoolTest_gt_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Float failed (gt, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_0_1(x, y); + float expected = golden_double_BoolTest_gt_fixed_0_1(x, y); + if (actual != expected) { + System.out.println("Double failed (gt, 0, 1), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + float actual = test_float_BoolTest_gt_fixed_10_20(x, y); + float expected = golden_float_BoolTest_gt_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Float failed (gt, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + float actual = test_double_BoolTest_gt_fixed_10_20(x, y); + float expected = golden_double_BoolTest_gt_fixed_10_20(x, y); + if (actual != expected) { + System.out.println("Double failed (gt, 10, 20), x: " + x + ", y: " + y + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float y = TestFPComparison2.FLOATS[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_float_BoolTest_gt_variable_results(x, y, a, b); + float expected = golden_float_BoolTest_gt_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (gt), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + for (int i = 0; i < TestFPComparison2.DOUBLES.length; i++) { + for (int j = 0; j < TestFPComparison2.DOUBLES.length; j++) { + double x = TestFPComparison2.DOUBLES[i]; + double y = TestFPComparison2.DOUBLES[j]; + for (int m = 0; m < TestFPComparison2.FLOATS.length; m++) { + for (int n = 0; n < TestFPComparison2.FLOATS.length; n++) { + float a = TestFPComparison2.FLOATS[m]; + float b = TestFPComparison2.FLOATS[n]; + float actual = test_double_BoolTest_gt_variable_results(x, y, a, b); + float expected = golden_double_BoolTest_gt_variable_results(x, y, a, b); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Double failed (gt), x: " + x + ", y: " + y + ", a: " + a + ", b: " + b + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} + +class Test_cmov_fp_cmp_fp_ge_3 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_x_lt_0(float x) { + return x < 0 ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_gt_x_lt_0(float x) { + return x < 0 ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_x_gt_0(float x) { + return x > 0 ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_gt_x_gt_0(float x) { + return x > 0 ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_neg_x_lt_0(float x) { + return !(x < 0) ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_gt_neg_x_lt_0(float x) { + return !(x < 0) ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_gt_neg_x_gt_0(float x) { + return !(x > 0) ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_gt_neg_x_gt_0(float x) { + return !(x > 0) ? 0 : x; + } + + @Run(test = {"test_float_BoolTest_gt_x_lt_0", "test_float_BoolTest_gt_x_gt_0", + "test_float_BoolTest_gt_neg_x_lt_0", "test_float_BoolTest_gt_neg_x_gt_0",}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_gt_x_lt_0(x); + float expected = golden_float_BoolTest_gt_x_lt_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (lt, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_gt_x_gt_0(x); + float expected = golden_float_BoolTest_gt_x_gt_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (gt, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_gt_neg_x_lt_0(x); + float expected = golden_float_BoolTest_gt_neg_x_lt_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (neg lt, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_gt_neg_x_gt_0(x); + float expected = golden_float_BoolTest_gt_neg_x_gt_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (neg gt, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} + +class Test_cmov_fp_cmp_fp_ge_4 { + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_x_le_0(float x) { + return x <= 0 ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_ge_x_le_0(float x) { + return x <= 0 ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_x_ge_0(float x) { + return x >= 0 ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_ge_x_ge_0(float x) { + return x >= 0 ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_neg_x_le_0(float x) { + return !(x <= 0) ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_ge_neg_x_le_0(float x) { + return !(x <= 0) ? 0 : x; + } + + @Test + @IR(counts = {IRNode.CMOVE_F, "1"}) + public static float test_float_BoolTest_ge_neg_x_ge_0(float x) { + return !(x >= 0) ? 0 : x; + } + @DontCompile + public static float golden_float_BoolTest_ge_neg_x_ge_0(float x) { + return !(x >= 0) ? 0 : x; + } + + @Run(test = {"test_float_BoolTest_ge_x_le_0", "test_float_BoolTest_ge_x_ge_0", + "test_float_BoolTest_ge_neg_x_le_0", "test_float_BoolTest_ge_neg_x_ge_0",}) + public void runTests() { + int err = 0; + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_ge_x_le_0(x); + float expected = golden_float_BoolTest_ge_x_le_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (le, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_ge_x_ge_0(x); + float expected = golden_float_BoolTest_ge_x_ge_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (ge, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_ge_neg_x_le_0(x); + float expected = golden_float_BoolTest_ge_neg_x_le_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (neg le, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + for (int i = 0; i < TestFPComparison2.FLOATS.length; i++) { + for (int j = 0; j < TestFPComparison2.FLOATS.length; j++) { + float x = TestFPComparison2.FLOATS[i]; + float actual = test_float_BoolTest_ge_neg_x_ge_0(x); + float expected = golden_float_BoolTest_ge_neg_x_ge_0(x); + if (actual != expected && (!Float.isNaN(actual) || !Float.isNaN(expected))) { + System.out.println("Float failed (neg ge, x, 0), x: " + x + + ", actual: " + actual + ", expected: " + expected); + err++; + } + } + } + + if (err != 0) { + throw new RuntimeException("Some tests failed"); + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java b/test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java new file mode 100644 index 00000000000..e332ac9e293 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestScalarConditionalMoveCmpObj.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2025, Rivos Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import java.util.Random; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +/* + * @test + * @summary Test conditional move + compare object. + * @requires vm.simpleArch == "riscv64" + * @library /test/lib / + * @run driver compiler.c2.irTests.TestScalarConditionalMoveCmpObj + */ + +public class TestScalarConditionalMoveCmpObj { + final private static int SIZE = 1024; + private static final Random RANDOM = Utils.getRandomInstance(); + + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:+UseCompressedOops"); + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:-UseCompactObjectHeaders", "-XX:-UseCompressedOops"); + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:+UseCompressedOops"); + TestFramework.runWithFlags("-XX:+UseCMoveUnconditionally", "-XX:-UseVectorCmov", + "-XX:+UnlockExperimentalVMOptions", "-XX:+UseCompactObjectHeaders", "-XX:-UseCompressedOops"); + } + + // Object comparison + // O for I + private int cmoveOEQforI(Object a, Object b, int c, int d) { + return (a == b) ? c : d; + } + + private int cmoveONEforI(Object a, Object b, int c, int d) { + return (a != b) ? c : d; + } + + // O for L + private long cmoveOEQforL(Object a, Object b, long c, long d) { + return (a == b) ? c : d; + } + + private long cmoveONEforL(Object a, Object b, long c, long d) { + return (a != b) ? c : d; + } + + // O for F + private float cmoveOEQforF(Object a, Object b, float c, float d) { + return (a == b) ? c : d; + } + + private float cmoveONEforF(Object a, Object b, float c, float d) { + return (a != b) ? c : d; + } + + // O for D + private double cmoveOEQforD(Object a, Object b, double c, double d) { + return (a == b) ? c : d; + } + + private double cmoveONEforD(Object a, Object b, double c, double d) { + return (a != b) ? c : d; + } + + // Tests shows CMoveI is generated, so let @IR verify CMOVE_I. + // + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveOEQforI(Object[] a, Object[] b, int[] c, int[] d, int[] r, int[] r2) { + for (int i = 0; i < a.length; i++) { + int cc = c[i]; + int dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] == b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_I, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveONEforI(Object[] a, Object[] b, int[] c, int[] d, int[] r, int[] r2) { + for (int i = 0; i < a.length; i++) { + int cc = c[i]; + int dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] != b[i]) ? cc : dd; + } + } + + // So far, CMoveL is not guaranteed to be generated, so @IR not verify CMOVE_L. + // TODO: enable CMOVE_L verification when it's guaranteed to generate CMOVE_L. + // + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_P, ">0"}, + // applyIf = {"UseCompressedOops", "false"}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_N, ">0"}, + // applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveOEQforL(Object[] a, Object[] b, long[] c, long[] d, long[] r, long[] r2) { + for (int i = 0; i < a.length; i++) { + long cc = c[i]; + long dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] == b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_P, ">0"}, + // applyIf = {"UseCompressedOops", "false"}) + // @IR(counts = {IRNode.CMOVE_L, ">0", IRNode.CMP_N, ">0"}, + // applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveONEforL(Object[] a, Object[] b, long[] c, long[] d, long[] r, long[] r2) { + for (int i = 0; i < a.length; i++) { + long cc = c[i]; + long dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] != b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveOEQforF(Object[] a, Object[] b, float[] c, float[] d, float[] r, float[] r2) { + for (int i = 0; i < a.length; i++) { + float cc = c[i]; + float dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] == b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_F, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveONEforF(Object[] a, Object[] b, float[] c, float[] d, float[] r, float[] r2) { + for (int i = 0; i < a.length; i++) { + float cc = c[i]; + float dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] != b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveOEQforD(Object[] a, Object[] b, double[] c, double[] d, double[] r, double[] r2) { + for (int i = 0; i < a.length; i++) { + double cc = c[i]; + double dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] == b[i]) ? cc : dd; + } + } + + @Test + @IR(failOn = {IRNode.STORE_VECTOR}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_P, ">0"}, + applyIf = {"UseCompressedOops", "false"}) + @IR(counts = {IRNode.CMOVE_D, ">0", IRNode.CMP_N, ">0"}, + applyIf = {"UseCompressedOops", "true"}) + private static void testCMoveONEforD(Object[] a, Object[] b, double[] c, double[] d, double[] r, double[] r2) { + for (int i = 0; i < a.length; i++) { + double cc = c[i]; + double dd = d[i]; + r2[i] = cc + dd; + r[i] = (a[i] != b[i]) ? cc : dd; + } + } + + @Warmup(0) + @Run(test = {// Object + "testCMoveOEQforI", + "testCMoveONEforI", + "testCMoveOEQforL", + "testCMoveONEforL", + "testCMoveOEQforF", + "testCMoveONEforF", + "testCMoveOEQforD", + "testCMoveONEforD", + }) + private void testCMove_runner_two() { + Object[] aO = new Object[SIZE]; + Object[] bO = new Object[SIZE]; + int[] cI = new int[SIZE]; + int[] dI = new int[SIZE]; + int[] rI = new int[SIZE]; + long[] cL = new long[SIZE]; + long[] dL = new long[SIZE]; + long[] rL = new long[SIZE]; + float[] cF = new float[SIZE]; + float[] dF = new float[SIZE]; + float[] rF = new float[SIZE]; + double[] cD = new double[SIZE]; + double[] dD = new double[SIZE]; + double[] rD = new double[SIZE]; + + init(aO); + shuffle(aO, bO); + init(cL); + init(dL); + init(cF); + init(dF); + init(cD); + init(dD); + + testCMoveOEQforI(aO, bO, cI, dI, rI, rI); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rI[i], cmoveOEQforI(aO[i], bO[i], cI[i], dI[i])); + } + + testCMoveONEforI(aO, bO, cI, dI, rI, rI); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rI[i], cmoveONEforI(aO[i], bO[i], cI[i], dI[i])); + } + + testCMoveOEQforL(aO, bO, cL, dL, rL, rL); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rL[i], cmoveOEQforL(aO[i], bO[i], cL[i], dL[i])); + } + + testCMoveONEforL(aO, bO, cL, dL, rL, rL); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rL[i], cmoveONEforL(aO[i], bO[i], cL[i], dL[i])); + } + + testCMoveOEQforF(aO, bO, cF, dF, rF, rF); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rF[i], cmoveOEQforF(aO[i], bO[i], cF[i], dF[i])); + } + + testCMoveONEforF(aO, bO, cF, dF, rF, rF); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rF[i], cmoveONEforF(aO[i], bO[i], cF[i], dF[i])); + } + + testCMoveOEQforD(aO, bO, cD, dD, rD, rD); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rD[i], cmoveOEQforD(aO[i], bO[i], cD[i], dD[i])); + } + + testCMoveONEforD(aO, bO, cD, dD, rD, rD); + for (int i = 0; i < SIZE; i++) { + Asserts.assertEquals(rD[i], cmoveONEforD(aO[i], bO[i], cD[i], dD[i])); + } + + } + + private static void init(Object[] a) { + for (int i = 0; i < SIZE; i++) { + a[i] = new Object(); + } + } + + private static void shuffle(Object[] a, Object[] b) { + for (int i = 0; i < a.length; i++) { + b[i] = a[i]; + } + Random rand = new Random(); + for (int i = 0; i < SIZE; i++) { + if (rand.nextInt(5) == 0) { + Object t = b[i]; + b[i] = b[SIZE-1-i]; + b[SIZE-1-i] = t; + } + } + } + + private static void init(int[] a) { + for (int i = 0; i < SIZE; i++) { + a[i] = RANDOM.nextInt(); + } + } + + private static void init(long[] a) { + for (int i = 0; i < SIZE; i++) { + a[i] = RANDOM.nextLong(); + } + } + + private static void init(float[] a) { + for (int i = 0; i < SIZE; i++) { + a[i] = switch(RANDOM.nextInt() % 20) { + case 0 -> Float.NaN; + case 1 -> 0; + case 2 -> 1; + case 3 -> Float.POSITIVE_INFINITY; + case 4 -> Float.NEGATIVE_INFINITY; + case 5 -> Float.MAX_VALUE; + case 6 -> Float.MIN_VALUE; + case 7, 8, 9 -> RANDOM.nextFloat(); + default -> Float.intBitsToFloat(RANDOM.nextInt()); + }; + } + } + + private static void init(double[] a) { + for (int i = 0; i < SIZE; i++) { + a[i] = switch(RANDOM.nextInt() % 20) { + case 0 -> Double.NaN; + case 1 -> 0; + case 2 -> 1; + case 3 -> Double.POSITIVE_INFINITY; + case 4 -> Double.NEGATIVE_INFINITY; + case 5 -> Double.MAX_VALUE; + case 6 -> Double.MIN_VALUE; + case 7, 8, 9 -> RANDOM.nextDouble(); + default -> Double.longBitsToDouble(RANDOM.nextLong()); + }; + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 1648135434a..41f185f3686 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -545,11 +545,36 @@ public class IRNode { trapNodes(CLASS_CHECK_TRAP, "class_check"); } + public static final String CMOVE_F = PREFIX + "CMOVE_F" + POSTFIX; + static { + beforeMatchingNameRegex(CMOVE_F, "CMoveF"); + } + + public static final String CMOVE_D = PREFIX + "CMOVE_D" + POSTFIX; + static { + beforeMatchingNameRegex(CMOVE_D, "CMoveD"); + } + public static final String CMOVE_I = PREFIX + "CMOVE_I" + POSTFIX; static { beforeMatchingNameRegex(CMOVE_I, "CMoveI"); } + public static final String CMOVE_L = PREFIX + "CMOVE_L" + POSTFIX; + static { + beforeMatchingNameRegex(CMOVE_L, "CMoveL"); + } + + public static final String CMP_F = PREFIX + "CMP_F" + POSTFIX; + static { + beforeMatchingNameRegex(CMP_F, "CmpF"); + } + + public static final String CMP_D = PREFIX + "CMP_D" + POSTFIX; + static { + beforeMatchingNameRegex(CMP_D, "CmpD"); + } + public static final String CMP_I = PREFIX + "CMP_I" + POSTFIX; static { beforeMatchingNameRegex(CMP_I, "CmpI"); @@ -585,6 +610,11 @@ public class IRNode { beforeMatchingNameRegex(CMP_P, "CmpP"); } + public static final String CMP_N = PREFIX + "CMP_N" + POSTFIX; + static { + beforeMatchingNameRegex(CMP_N, "CmpN"); + } + public static final String CMP_LT_MASK = PREFIX + "CMP_LT_MASK" + POSTFIX; static { beforeMatchingNameRegex(CMP_LT_MASK, "CmpLTMask"); diff --git a/test/micro/org/openjdk/bench/java/lang/ClassComparison.java b/test/micro/org/openjdk/bench/java/lang/ClassComparison.java index 2a768f243e2..15e631bb7fc 100644 --- a/test/micro/org/openjdk/bench/java/lang/ClassComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/ClassComparison.java @@ -44,12 +44,8 @@ public class ClassComparison { Class[] c2; int[] res; long[] resLong; - Object[] resObject; - Object ro1; - Object ro2; - Object[] resClass; - Class rc1; - Class rc2; + float[] resFloat; + double[] resDouble; @Setup public void setup() { @@ -58,12 +54,8 @@ public class ClassComparison { c2 = new Class[INVOCATIONS]; res = new int[INVOCATIONS]; resLong = new long[INVOCATIONS]; - resObject = new Object[INVOCATIONS]; - ro1 = new Object(); - ro2 = new Object(); - resClass = new Class[INVOCATIONS]; - rc1 = Float.class; - rc2 = Double.class; + resFloat = new float[INVOCATIONS]; + resDouble = new double[INVOCATIONS]; for (int i = 0; i < INVOCATIONS; i++) { c1[i] = random.nextBoolean() ? Float.class : Double.class; } @@ -86,6 +78,7 @@ public class ClassComparison { } } + @Benchmark public void equalClassResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (c1[i] == c2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -98,4 +91,32 @@ public class ClassComparison { resLong[i] = (c1[i] != c2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } + + @Benchmark + public void equalClassResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (c1[i] == c2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualClassResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (c1[i] != c2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void equalClassResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (c1[i] == c2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualClassResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (c1[i] != c2[i]) ? 0.1 : 0.2; + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/FPComparison.java b/test/micro/org/openjdk/bench/java/lang/FPComparison.java index 8074ada3257..18b2b79c7bd 100644 --- a/test/micro/org/openjdk/bench/java/lang/FPComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/FPComparison.java @@ -37,34 +37,18 @@ import java.util.random.RandomGenerator; public class FPComparison { static final int INVOCATIONS = 1024; - float[] f1; - double[] d1; - float[] f2; - double[] d2; - int[] res; - long[] resLong; - Object[] resObject; - Object ro1; - Object ro2; - Class[] resClass; - Class rc1; - Class rc2; + static final float[] f1 = new float[INVOCATIONS]; + static final double[] d1 = new double[INVOCATIONS]; + static final float[] f2 = new float[INVOCATIONS]; + static final double[] d2 = new double[INVOCATIONS]; + static final int[] res = new int[INVOCATIONS];; + static final long[] resLong = new long[INVOCATIONS]; + static final float[] resFloat = new float[INVOCATIONS]; + static final double[] resDouble = new double[INVOCATIONS]; @Setup public void setup() { var random = RandomGenerator.getDefault(); - f1 = new float[INVOCATIONS]; - d1 = new double[INVOCATIONS]; - f2 = new float[INVOCATIONS]; - d2 = new double[INVOCATIONS]; - res = new int[INVOCATIONS]; - resLong = new long[INVOCATIONS]; - resObject = new Object[INVOCATIONS]; - ro1 = new Object(); - ro2 = new Object(); - resClass = new Class[INVOCATIONS]; - rc1 = Float.class; - rc2 = Double.class; for (int i = 0; i < INVOCATIONS; i++) { int type = random.nextInt(5); if (type == 1) { @@ -274,4 +258,148 @@ public class FPComparison { resLong[i] = (d1[i] >= d2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } + + // --------- result: float --------- + + @Benchmark + public void equalFloatResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (f1[i] == f2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void equalDoubleResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (d1[i] == d2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessFloatResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (f1[i] < f2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessDoubleResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (d1[i] < d2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualFloatResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (f1[i] <= f2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualDoubleResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (d1[i] <= d2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterFloatResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (f1[i] > f2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterDoubleResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (d1[i] > d2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualFloatResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (f1[i] >= f2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualDoubleResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (d1[i] >= d2[i]) ? 0.1f : 0.2f; + } + } + + // --------- result: double --------- + + @Benchmark + public void equalFloatResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (f1[i] == f2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void equalDoubleResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (d1[i] == d2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessFloatResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (f1[i] < f2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessDoubleResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (d1[i] < d2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualFloatResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (f1[i] <= f2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualDoubleResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (d1[i] <= d2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterFloatResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (f1[i] > f2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterDoubleResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (d1[i] > d2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualFloatResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (f1[i] >= f2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualDoubleResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (d1[i] >= d2[i]) ? 0.1 : 0.2; + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java b/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java index 1853be8497d..832d398fc3d 100644 --- a/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/IntegerComparison.java @@ -42,12 +42,8 @@ public class IntegerComparison { int[] i2; int[] res; long[] resLong; - Object[] resObject; - Object ro1; - Object ro2; - Object[] resClass; - Class rc1; - Class rc2; + float[] resFloat; + double[] resDouble; @Setup public void setup() { @@ -56,18 +52,17 @@ public class IntegerComparison { i2 = new int[INVOCATIONS]; res = new int[INVOCATIONS]; resLong = new long[INVOCATIONS]; - resObject = new Object[INVOCATIONS]; - ro1 = new Object(); - ro2 = new Object(); - resClass = new Class[INVOCATIONS]; - rc1 = Float.class; - rc2 = Double.class; + resFloat = new float[INVOCATIONS]; + resDouble = new double[INVOCATIONS]; for (int i = 0; i < INVOCATIONS; i++) { i1[i] = random.nextInt(INVOCATIONS); i2[i] = random.nextInt(INVOCATIONS); } } + // --------- result: int --------- + // Signed comparison + @Benchmark public void equalInteger() { for (int i = 0; i < INVOCATIONS; i++) { @@ -110,8 +105,55 @@ public class IntegerComparison { } } - // --------- result: long --------- + // Unsigned comparison + @Benchmark + public void equalIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) == 0 ? 1 : 2; + } + } + + @Benchmark + public void notEqualIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) != 0 ? 1 : 2; + } + } + + @Benchmark + public void lessIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) < 0 ? 1 : 2; + } + } + + @Benchmark + public void lessEqualIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) <= 0 ? 1 : 2; + } + } + + @Benchmark + public void greaterIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) > 0 ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualIntegerUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Integer.compareUnsigned(i1[i], i2[i]) >= 0 ? 1 : 2; + } + } + + + // --------- result: long --------- + // Signed comparison + + @Benchmark public void equalIntegerResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (i1[i] == i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -125,6 +167,7 @@ public class IntegerComparison { } } + @Benchmark public void lessIntegerResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (i1[i] < i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -138,6 +181,7 @@ public class IntegerComparison { } } + @Benchmark public void greaterIntegerResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (i1[i] > i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -150,4 +194,226 @@ public class IntegerComparison { resLong[i] = (i1[i] >= i2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } + + // Unsigned comparison + + @Benchmark + public void equalIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) == 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) != 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) < 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) <= 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) > 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualIntegerUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Integer.compareUnsigned(i1[i], i2[i]) >= 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + // --------- result: float --------- + // Signed comparison + + @Benchmark + public void equalIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] == i2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] != i2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] < i2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] <= i2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] > i2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualIntegerResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (i1[i] >= i2[i]) ? 0.1f : 0.2f; + } + } + + // Unsigned comparison + + @Benchmark + public void equalIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) == 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) != 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) < 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) <= 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) > 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualIntegerUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Integer.compareUnsigned(i1[i], i2[i]) >= 0 ? 0.1f : 0.2f; + } + } + + // --------- result: double --------- + // Signed comparison + + @Benchmark + public void equalIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] == i2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] != i2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] < i2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] <= i2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] > i2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualIntegerResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (i1[i] >= i2[i]) ? 0.1 : 0.2; + } + } + + // Unsigned comparison + + @Benchmark + public void equalIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) == 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) != 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) < 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) <= 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) > 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualIntegerUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Integer.compareUnsigned(i1[i], i2[i]) >= 0 ? 0.1 : 0.2; + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/LongComparison.java b/test/micro/org/openjdk/bench/java/lang/LongComparison.java index bed5ee245b2..a7317244c6f 100644 --- a/test/micro/org/openjdk/bench/java/lang/LongComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/LongComparison.java @@ -41,12 +41,8 @@ public class LongComparison { long[] l2; int[] res; long[] resLong; - Object[] resObject; - Object ro1; - Object ro2; - Object[] resClass; - Class rc1; - Class rc2; + float[] resFloat; + double[] resDouble; @Setup public void setup() { @@ -55,18 +51,17 @@ public class LongComparison { l2 = new long[INVOCATIONS]; res = new int[INVOCATIONS]; resLong = new long[INVOCATIONS]; - resObject = new Object[INVOCATIONS]; - ro1 = new Object(); - ro2 = new Object(); - resClass = new Class[INVOCATIONS]; - rc1 = Float.class; - rc2 = Double.class; + resFloat = new float[INVOCATIONS]; + resDouble = new double[INVOCATIONS]; for (int i = 0; i < INVOCATIONS; i++) { l1[i] = random.nextLong(INVOCATIONS); l2[i] = random.nextLong(INVOCATIONS); } } + // --------- result: int --------- + // Signed comparison + @Benchmark public void equalLong() { for (int i = 0; i < INVOCATIONS; i++) { @@ -109,8 +104,54 @@ public class LongComparison { } } - // --------- result: long --------- + // Unsigned comparison + @Benchmark + public void equalLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) == 0 ? 1 : 2; + } + } + + @Benchmark + public void notEqualLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) != 0 ? 1 : 2; + } + } + + @Benchmark + public void lessLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) < 0 ? 1 : 2; + } + } + + @Benchmark + public void lessEqualLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) <= 0 ? 1 : 2; + } + } + + @Benchmark + public void greaterLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) > 0 ? 1 : 2; + } + } + + @Benchmark + public void greaterEqualLongUnsigned() { + for (int i = 0; i < INVOCATIONS; i++) { + res[i] = Long.compareUnsigned(l1[i], l2[i]) >= 0 ? 1 : 2; + } + } + + // --------- result: long --------- + // Signed comparison + + @Benchmark public void equalLongResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (l1[i] == l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -124,6 +165,7 @@ public class LongComparison { } } + @Benchmark public void lessLongResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (l1[i] < l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -137,6 +179,7 @@ public class LongComparison { } } + @Benchmark public void greaterLongResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (l1[i] > l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -149,4 +192,226 @@ public class LongComparison { resLong[i] = (l1[i] >= l2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } + + // Unsigned comparison + + @Benchmark + public void equalLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) == 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void notEqualLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) != 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) < 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void lessEqualLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) <= 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) > 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + @Benchmark + public void greaterEqualLongUnsignedResLong() { + for (int i = 0; i < INVOCATIONS; i++) { + resLong[i] = Long.compareUnsigned(l1[i], l2[i]) >= 0 ? Long.MAX_VALUE : Long.MIN_VALUE; + } + } + + // --------- result: float --------- + // Signed comparison + + @Benchmark + public void equalLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] == l2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] != l2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] < l2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] <= l2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] > l2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualLongResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (l1[i] >= l2[i]) ? 0.1f : 0.2f; + } + } + + // Unsigned comparison + + @Benchmark + public void equalLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) == 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) != 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) < 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void lessEqualLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) <= 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) > 0 ? 0.1f : 0.2f; + } + } + + @Benchmark + public void greaterEqualLongUnsignedResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = Long.compareUnsigned(l1[i], l2[i]) >= 0 ? 0.1f : 0.2f; + } + } + + // --------- result: double --------- + // Signed comparison + + @Benchmark + public void equalLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] == l2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] != l2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] < l2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] <= l2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] > l2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualLongResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (l1[i] >= l2[i]) ? 0.1 : 0.2; + } + } + + // Unsigned comparison + + @Benchmark + public void equalLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) == 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) != 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) < 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void lessEqualLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) <= 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) > 0 ? 0.1 : 0.2; + } + } + + @Benchmark + public void greaterEqualLongUnsignedResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = Long.compareUnsigned(l1[i], l2[i]) >= 0 ? 0.1 : 0.2; + } + } } diff --git a/test/micro/org/openjdk/bench/java/lang/PointerComparison.java b/test/micro/org/openjdk/bench/java/lang/PointerComparison.java index b6bcf008619..fc2fd95b1c0 100644 --- a/test/micro/org/openjdk/bench/java/lang/PointerComparison.java +++ b/test/micro/org/openjdk/bench/java/lang/PointerComparison.java @@ -44,12 +44,8 @@ public class PointerComparison { Object[] o2; int[] res; long[] resLong; - Object[] resObject; - Object ro1; - Object ro2; - Object[] resClass; - Class rc1; - Class rc2; + float[] resFloat; + double[] resDouble; @Setup public void setup() { @@ -58,12 +54,8 @@ public class PointerComparison { o2 = new Object[INVOCATIONS]; res = new int[INVOCATIONS]; resLong = new long[INVOCATIONS]; - resObject = new Object[INVOCATIONS]; - ro1 = new Object(); - ro2 = new Object(); - resClass = new Class[INVOCATIONS]; - rc1 = Float.class; - rc2 = Double.class; + resFloat = new float[INVOCATIONS]; + resDouble = new double[INVOCATIONS]; for (int i = 0; i < INVOCATIONS; i++) { o1[i] = new Object(); } @@ -86,6 +78,7 @@ public class PointerComparison { } } + @Benchmark public void equalObjectResLong() { for (int i = 0; i < INVOCATIONS; i++) { resLong[i] = (o1[i] == o2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; @@ -98,4 +91,32 @@ public class PointerComparison { resLong[i] = (o1[i] != o2[i]) ? Long.MAX_VALUE : Long.MIN_VALUE; } } + + @Benchmark + public void equalObjecResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (o1[i] == o2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void notEqualObjecResFloat() { + for (int i = 0; i < INVOCATIONS; i++) { + resFloat[i] = (o1[i] != o2[i]) ? 0.1f : 0.2f; + } + } + + @Benchmark + public void equalObjecResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (o1[i] == o2[i]) ? 0.1 : 0.2; + } + } + + @Benchmark + public void notEqualObjecResDouble() { + for (int i = 0; i < INVOCATIONS; i++) { + resDouble[i] = (o1[i] != o2[i]) ? 0.1 : 0.2; + } + } } From ed5fc9ad2defb75ea5a68fe6427a591376ce6d6b Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Dec 2025 14:21:40 +0000 Subject: [PATCH 093/141] 8373087: Parallel: Rename PSGenerationPool to PSOldGenerationPool Reviewed-by: tschatzl, jsikstro, iwalulya --- src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp | 6 +++--- src/hotspot/share/gc/parallel/psMemoryPool.cpp | 8 ++++---- src/hotspot/share/gc/parallel/psMemoryPool.hpp | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index b85b16f58b5..cff53e84059 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -141,9 +141,9 @@ void ParallelScavengeHeap::initialize_serviceability() { "PS Survivor Space", false /* support_usage_threshold */); - _old_pool = new PSGenerationPool(_old_gen, - "PS Old Gen", - true /* support_usage_threshold */); + _old_pool = new PSOldGenerationPool(_old_gen, + "PS Old Gen", + true /* support_usage_threshold */); _young_manager = new GCMemoryManager("PS Scavenge"); _old_manager = new GCMemoryManager("PS MarkSweep"); diff --git a/src/hotspot/share/gc/parallel/psMemoryPool.cpp b/src/hotspot/share/gc/parallel/psMemoryPool.cpp index c120664600b..81c7b17a1ef 100644 --- a/src/hotspot/share/gc/parallel/psMemoryPool.cpp +++ b/src/hotspot/share/gc/parallel/psMemoryPool.cpp @@ -24,14 +24,14 @@ #include "gc/parallel/psMemoryPool.hpp" -PSGenerationPool::PSGenerationPool(PSOldGen* old_gen, - const char* name, - bool support_usage_threshold) : +PSOldGenerationPool::PSOldGenerationPool(PSOldGen* old_gen, + const char* name, + bool support_usage_threshold) : CollectedMemoryPool(name, old_gen->capacity_in_bytes(), old_gen->reserved().byte_size(), support_usage_threshold), _old_gen(old_gen) { } -MemoryUsage PSGenerationPool::get_memory_usage() { +MemoryUsage PSOldGenerationPool::get_memory_usage() { size_t maxSize = (available_for_allocation() ? max_size() : 0); size_t used = used_in_bytes(); size_t committed = _old_gen->capacity_in_bytes(); diff --git a/src/hotspot/share/gc/parallel/psMemoryPool.hpp b/src/hotspot/share/gc/parallel/psMemoryPool.hpp index 58f39cdc79f..0da47e5a8ef 100644 --- a/src/hotspot/share/gc/parallel/psMemoryPool.hpp +++ b/src/hotspot/share/gc/parallel/psMemoryPool.hpp @@ -31,12 +31,12 @@ #include "services/memoryPool.hpp" #include "services/memoryUsage.hpp" -class PSGenerationPool : public CollectedMemoryPool { +class PSOldGenerationPool : public CollectedMemoryPool { private: PSOldGen* _old_gen; public: - PSGenerationPool(PSOldGen* pool, const char* name, bool support_usage_threshold); + PSOldGenerationPool(PSOldGen* pool, const char* name, bool support_usage_threshold); MemoryUsage get_memory_usage(); size_t used_in_bytes() { return _old_gen->used_in_bytes(); } From ac81ce51fa4ed04b6dbcc28cb2dd8eabcfe52ad7 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 8 Dec 2025 15:38:35 +0000 Subject: [PATCH 094/141] 8372555: Test com/sun/jdi/ExceptionEvents.java failed: ObjectCollectedException Reviewed-by: amenkov, dholmes --- test/jdk/com/sun/jdi/ExceptionEvents.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/jdk/com/sun/jdi/ExceptionEvents.java b/test/jdk/com/sun/jdi/ExceptionEvents.java index de5f51c4aa2..ee9e91b4dd9 100644 --- a/test/jdk/com/sun/jdi/ExceptionEvents.java +++ b/test/jdk/com/sun/jdi/ExceptionEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -355,7 +355,16 @@ public class ExceptionEvents extends TestScaffold { if (event.request() == request) { try { System.out.print("ExceptionEvent: "); - System.out.print("" + event.exception().referenceType().name()); + try { + System.out.print("" + event.exception().referenceType().name()); + } catch (ObjectCollectedException e) { + if (event.request().suspendPolicy() == EventRequest.SUSPEND_NONE) { + // Since the thread was not suspended, the exception object can be collected. + System.out.print(""); + } else { + throw e; + } + } Location loc = event.location(); System.out.print(" @ " + loc.method().name()); System.out.print(":" + loc.lineNumber()); From 355755d35de5c3155d1ea8d1afdd0debe5296a13 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Mon, 8 Dec 2025 16:07:01 +0000 Subject: [PATCH 095/141] 8366671: Refactor Thread::SpinAcquire and Thread::SpinRelease Co-authored-by: Axel Boldt-Christmas Reviewed-by: coleenp, kbarrett, dholmes, aboldtch --- .../recorder/service/jfrEventThrottler.cpp | 4 +- .../share/jfr/support/jfrAdaptiveSampler.cpp | 4 +- .../share/jfr/support/jfrThreadLocal.cpp | 1 - .../share/jfr/utilities/jfrSpinlockHelper.hpp | 44 ------------ src/hotspot/share/runtime/objectMonitor.cpp | 24 +++---- src/hotspot/share/runtime/park.cpp | 7 +- .../share/runtime/safepointVerifiers.cpp | 4 +- src/hotspot/share/runtime/thread.cpp | 46 ------------- src/hotspot/share/runtime/thread.hpp | 5 -- .../share/utilities/spinCriticalSection.cpp | 69 +++++++++++++++++++ .../share/utilities/spinCriticalSection.hpp | 63 +++++++++++++++++ .../gtest/jfr/test_adaptiveSampler.cpp | 3 +- 12 files changed, 155 insertions(+), 119 deletions(-) delete mode 100644 src/hotspot/share/jfr/utilities/jfrSpinlockHelper.hpp create mode 100644 src/hotspot/share/utilities/spinCriticalSection.cpp create mode 100644 src/hotspot/share/utilities/spinCriticalSection.hpp diff --git a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp index 787b2d7456b..e5420d29d94 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrEventThrottler.cpp @@ -24,11 +24,11 @@ */ #include "jfr/recorder/service/jfrEventThrottler.hpp" -#include "jfr/utilities/jfrSpinlockHelper.hpp" #include "jfrfiles/jfrEventIds.hpp" #include "logging/log.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/spinCriticalSection.hpp" constexpr static const JfrSamplerParams _disabled_params = { 0, // sample points per window @@ -128,7 +128,7 @@ JfrEventThrottler* JfrEventThrottler::create_throttler(JfrEventId id) { * - period_ms time period expressed in milliseconds */ void JfrEventThrottler::configure(int64_t sample_size, int64_t period_ms) { - JfrSpinlockHelper mutex(&_lock); + SpinCriticalSection scs(&_lock); _sample_size = sample_size; _period_ms = period_ms; _update = true; diff --git a/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp b/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp index 22399f42bbb..571b5656576 100644 --- a/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp +++ b/src/hotspot/share/jfr/support/jfrAdaptiveSampler.cpp @@ -25,13 +25,13 @@ #include "jfr/support/jfrAdaptiveSampler.hpp" #include "jfr/utilities/jfrRandom.inline.hpp" -#include "jfr/utilities/jfrSpinlockHelper.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTimeConverter.hpp" #include "jfr/utilities/jfrTryLock.hpp" #include "logging/log.hpp" #include "runtime/atomicAccess.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/spinCriticalSection.hpp" #include @@ -342,7 +342,7 @@ JfrGTestFixedRateSampler::JfrGTestFixedRateSampler(size_t sample_points_per_wind bool JfrGTestFixedRateSampler::initialize() { const bool result = JfrAdaptiveSampler::initialize(); - JfrSpinlockHelper mutex(&_lock); + SpinCriticalSection scs(&_lock); reconfigure(); return result; } diff --git a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp index 5fe5546e0a9..39b0eb3656c 100644 --- a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp +++ b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp @@ -36,7 +36,6 @@ #include "jfr/recorder/storage/jfrStorage.hpp" #include "jfr/support/jfrThreadId.inline.hpp" #include "jfr/support/jfrThreadLocal.hpp" -#include "jfr/utilities/jfrSpinlockHelper.hpp" #include "jfr/writers/jfrJavaEventWriter.hpp" #include "logging/log.hpp" #include "memory/allocation.inline.hpp" diff --git a/src/hotspot/share/jfr/utilities/jfrSpinlockHelper.hpp b/src/hotspot/share/jfr/utilities/jfrSpinlockHelper.hpp deleted file mode 100644 index 4b5ca80470e..00000000000 --- a/src/hotspot/share/jfr/utilities/jfrSpinlockHelper.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 - * 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_JFR_UTILITIES_JFRSPINLOCKHELPER_HPP -#define SHARE_JFR_UTILITIES_JFRSPINLOCKHELPER_HPP - -#include "runtime/javaThread.hpp" - -class JfrSpinlockHelper { - private: - volatile int* const _lock; - - public: - JfrSpinlockHelper(volatile int* lock) : _lock(lock) { - Thread::SpinAcquire(_lock); - } - - ~JfrSpinlockHelper() { - Thread::SpinRelease(_lock); - } -}; - -#endif // SHARE_JFR_UTILITIES_JFRSPINLOCKHELPER_HPP diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index ee7629ec6f5..785ee2af592 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -59,6 +59,7 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "utilities/preserveException.hpp" +#include "utilities/spinCriticalSection.hpp" #if INCLUDE_JFR #include "jfr/support/jfrFlush.hpp" #endif @@ -1863,9 +1864,10 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // returns because of a timeout of interrupt. Contention is exceptionally rare // so we use a simple spin-lock instead of a heavier-weight blocking lock. - Thread::SpinAcquire(&_wait_set_lock); - add_waiter(&node); - Thread::SpinRelease(&_wait_set_lock); + { + SpinCriticalSection scs(&_wait_set_lock); + add_waiter(&node); + } intx save = _recursions; // record the old recursion count _waiters++; // increment the number of waiters @@ -1922,12 +1924,11 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { // That is, we fail toward safety. if (node.TState == ObjectWaiter::TS_WAIT) { - Thread::SpinAcquire(&_wait_set_lock); + SpinCriticalSection scs(&_wait_set_lock); if (node.TState == ObjectWaiter::TS_WAIT) { dequeue_specific_waiter(&node); // unlink from wait_set node.TState = ObjectWaiter::TS_RUN; } - Thread::SpinRelease(&_wait_set_lock); } // The thread is now either on off-list (TS_RUN), @@ -2036,7 +2037,7 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { bool ObjectMonitor::notify_internal(JavaThread* current) { bool did_notify = false; - Thread::SpinAcquire(&_wait_set_lock); + SpinCriticalSection scs(&_wait_set_lock); ObjectWaiter* iterator = dequeue_waiter(); if (iterator != nullptr) { guarantee(iterator->TState == ObjectWaiter::TS_WAIT, "invariant"); @@ -2095,7 +2096,6 @@ bool ObjectMonitor::notify_internal(JavaThread* current) { } } } - Thread::SpinRelease(&_wait_set_lock); return did_notify; } @@ -2198,9 +2198,10 @@ void ObjectMonitor::vthread_wait(JavaThread* current, jlong millis, bool interru // returns because of a timeout or interrupt. Contention is exceptionally rare // so we use a simple spin-lock instead of a heavier-weight blocking lock. - Thread::SpinAcquire(&_wait_set_lock); - add_waiter(node); - Thread::SpinRelease(&_wait_set_lock); + { + SpinCriticalSection scs(&_wait_set_lock); + add_waiter(node); + } node->_recursions = _recursions; // record the old recursion count _recursions = 0; // set the recursion level to be 0 @@ -2221,12 +2222,11 @@ bool ObjectMonitor::vthread_wait_reenter(JavaThread* current, ObjectWaiter* node // need to check if we were interrupted or the wait timed-out, and // in that case remove ourselves from the _wait_set queue. if (node->TState == ObjectWaiter::TS_WAIT) { - Thread::SpinAcquire(&_wait_set_lock); + SpinCriticalSection scs(&_wait_set_lock); if (node->TState == ObjectWaiter::TS_WAIT) { dequeue_specific_waiter(node); // unlink from wait_set node->TState = ObjectWaiter::TS_RUN; } - Thread::SpinRelease(&_wait_set_lock); } // If this was an interrupted case, set the _interrupted boolean so that diff --git a/src/hotspot/share/runtime/park.cpp b/src/hotspot/share/runtime/park.cpp index 37dfe6fcc3d..338a01bbfb9 100644 --- a/src/hotspot/share/runtime/park.cpp +++ b/src/hotspot/share/runtime/park.cpp @@ -25,6 +25,7 @@ #include "memory/allocation.inline.hpp" #include "nmt/memTracker.hpp" #include "runtime/javaThread.hpp" +#include "utilities/spinCriticalSection.hpp" // Lifecycle management for TSM ParkEvents. // ParkEvents are type-stable (TSM). @@ -60,14 +61,13 @@ ParkEvent * ParkEvent::Allocate (Thread * t) { // Using a spin lock since we are part of the mutex impl. // 8028280: using concurrent free list without memory management can leak // pretty badly it turns out. - Thread::SpinAcquire(&ListLock); { + SpinCriticalSection scs(&ListLock); ev = FreeList; if (ev != nullptr) { FreeList = ev->FreeNext; } } - Thread::SpinRelease(&ListLock); if (ev != nullptr) { guarantee (ev->AssociatedWith == nullptr, "invariant") ; @@ -88,12 +88,11 @@ void ParkEvent::Release (ParkEvent * ev) { ev->AssociatedWith = nullptr ; // Note that if we didn't have the TSM/immortal constraint, then // when reattaching we could trim the list. - Thread::SpinAcquire(&ListLock); { + SpinCriticalSection scs(&ListLock); ev->FreeNext = FreeList; FreeList = ev; } - Thread::SpinRelease(&ListLock); } // Override operator new and delete so we can ensure that the diff --git a/src/hotspot/share/runtime/safepointVerifiers.cpp b/src/hotspot/share/runtime/safepointVerifiers.cpp index 6eb61efe0ca..0c6f2e9add3 100644 --- a/src/hotspot/share/runtime/safepointVerifiers.cpp +++ b/src/hotspot/share/runtime/safepointVerifiers.cpp @@ -30,7 +30,9 @@ #ifdef ASSERT -NoSafepointVerifier::NoSafepointVerifier(bool active) : _thread(Thread::current()), _active(active) { +NoSafepointVerifier::NoSafepointVerifier(bool active) + : _thread(active ? Thread::current() : nullptr), + _active(active) { if (!_active) { return; } diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index d018c8a1a3a..f3c08ae62f7 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -566,49 +566,3 @@ bool Thread::set_as_starting_thread(JavaThread* jt) { DEBUG_ONLY(_starting_thread = jt;) return os::create_main_thread(jt); } - -// Ad-hoc mutual exclusion primitive: spin lock -// -// We employ a spin lock _only for low-contention, fixed-length -// short-duration critical sections where we're concerned -// about native mutex_t or HotSpot Mutex:: latency. - -void Thread::SpinAcquire(volatile int * adr) { - if (AtomicAccess::cmpxchg(adr, 0, 1) == 0) { - return; // normal fast-path return - } - - // Slow-path : We've encountered contention -- Spin/Yield/Block strategy. - int ctr = 0; - int Yields = 0; - for (;;) { - while (*adr != 0) { - ++ctr; - if ((ctr & 0xFFF) == 0 || !os::is_MP()) { - if (Yields > 5) { - os::naked_short_sleep(1); - } else { - os::naked_yield(); - ++Yields; - } - } else { - SpinPause(); - } - } - if (AtomicAccess::cmpxchg(adr, 0, 1) == 0) return; - } -} - -void Thread::SpinRelease(volatile int * adr) { - assert(*adr != 0, "invariant"); - // Roach-motel semantics. - // It's safe if subsequent LDs and STs float "up" into the critical section, - // but prior LDs and STs within the critical section can't be allowed - // to reorder or float past the ST that releases the lock. - // Loads and stores in the critical section - which appear in program - // order before the store that releases the lock - must also appear - // before the store that releases the lock in memory visibility order. - // So we need a #loadstore|#storestore "release" memory barrier before - // the ST of 0 into the lock-word which releases the lock. - AtomicAccess::release_store(adr, 0); -} diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 240821e90bd..181dfc46f87 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -602,11 +602,6 @@ protected: jint _hashStateY; jint _hashStateZ; - // Low-level leaf-lock primitives used to implement synchronization. - // Not for general synchronization use. - static void SpinAcquire(volatile int * Lock); - static void SpinRelease(volatile int * Lock); - #if defined(__APPLE__) && defined(AARCH64) private: DEBUG_ONLY(bool _wx_init); diff --git a/src/hotspot/share/utilities/spinCriticalSection.cpp b/src/hotspot/share/utilities/spinCriticalSection.cpp new file mode 100644 index 00000000000..0bbbc82c12b --- /dev/null +++ b/src/hotspot/share/utilities/spinCriticalSection.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "runtime/atomicAccess.hpp" +#include "utilities/spinCriticalSection.hpp" + +void SpinCriticalSection::spin_acquire(volatile int* adr) { + if (AtomicAccess::cmpxchg(adr, 0, 1) == 0) { + return; // normal fast-path return + } + + // Slow-path : We've encountered contention -- Spin/Yield/Block strategy. + int ctr = 0; + int Yields = 0; + for (;;) { + while (*adr != 0) { + ++ctr; + if ((ctr & 0xFFF) == 0 || !os::is_MP()) { + if (Yields > 5) { + os::naked_short_sleep(1); + } + else { + os::naked_yield(); + ++Yields; + } + } + else { + SpinPause(); + } + } + if (AtomicAccess::cmpxchg(adr, 0, 1) == 0) return; + } +} + +void SpinCriticalSection::spin_release(volatile int* adr) { + assert(*adr != 0, "invariant"); + // Roach-motel semantics. + // It's safe if subsequent LDs and STs float "up" into the critical section, + // but prior LDs and STs within the critical section can't be allowed + // to reorder or float past the ST that releases the lock. + // Loads and stores in the critical section - which appear in program + // order before the store that releases the lock - must also appear + // before the store that releases the lock in memory visibility order. + // So we need a #loadstore|#storestore "release" memory barrier before + // the ST of 0 into the lock-word which releases the lock. + AtomicAccess::release_store(adr, 0); +} + diff --git a/src/hotspot/share/utilities/spinCriticalSection.hpp b/src/hotspot/share/utilities/spinCriticalSection.hpp new file mode 100644 index 00000000000..0ebdc5de63e --- /dev/null +++ b/src/hotspot/share/utilities/spinCriticalSection.hpp @@ -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. + * + */ + +#ifndef SHARE_UTILITIES_SPINCRITICALSECTION_HPP +#define SHARE_UTILITIES_SPINCRITICALSECTION_HPP + +#include "runtime/javaThread.hpp" +#include "runtime/safepointVerifiers.hpp" +#include "runtime/thread.hpp" +#include "utilities/macros.hpp" + +// Ad-hoc mutual exclusion primitive: spin critical section, +// which employs a spin lock. +// +// We use this critical section only for low-contention code, and +// when it is know that the duration is short. To be used where +// we're concerned about native mutex_t or HotSpot Mutex:: latency. +// This class uses low-level leaf-lock primitives to implement +// synchronization and is not for general synchronization use. +// Should not be used in signal-handling contexts. +class SpinCriticalSection { +private: + // We use int type as 32-bit atomic operation is the most performant + // compared to smaller/larger types. + volatile int* const _lock; + DEBUG_ONLY(NoSafepointVerifier _nsv;) + + static void spin_acquire(volatile int* Lock); + static void spin_release(volatile int* Lock); +public: + NONCOPYABLE(SpinCriticalSection); + SpinCriticalSection(volatile int* lock) + : _lock(lock) + DEBUG_ONLY(COMMA _nsv(Thread::current_or_null() != nullptr)) { + spin_acquire(_lock); + } + ~SpinCriticalSection() { + spin_release(_lock); + } +}; + +#endif // SHARE_UTILITIES_SPINCRITICALSECTION_HPP diff --git a/test/hotspot/gtest/jfr/test_adaptiveSampler.cpp b/test/hotspot/gtest/jfr/test_adaptiveSampler.cpp index 69548b06e51..8625f64099d 100644 --- a/test/hotspot/gtest/jfr/test_adaptiveSampler.cpp +++ b/test/hotspot/gtest/jfr/test_adaptiveSampler.cpp @@ -34,13 +34,12 @@ #include "jfr/utilities/jfrAllocation.hpp" #include "jfr/utilities/jfrRandom.inline.hpp" -#include "jfr/utilities/jfrSpinlockHelper.hpp" #include "jfr/utilities/jfrTime.hpp" #include "jfr/utilities/jfrTimeConverter.hpp" #include "jfr/utilities/jfrTryLock.hpp" #include "logging/log.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/spinCriticalSection.hpp" #include "unittest.hpp" #include From 811591c5c332e6427dc96819451e046841fe635b Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Dec 2025 16:11:28 +0000 Subject: [PATCH 096/141] 8373262: Parallel: gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java fails Reviewed-by: cjplummer --- .../sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java index 76125e33e80..b0d158f409d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/parallel/ParallelScavengeHeap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, 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 @@ -60,11 +60,11 @@ public class ParallelScavengeHeap extends CollectedHeap { // Accessors public PSYoungGen youngGen() { - return VMObjectFactory.newObject(PSYoungGen.class, youngGenField.getValue()); + return VMObjectFactory.newObject(PSYoungGen.class, youngGenField.getValue(addr)); } public PSOldGen oldGen() { - return VMObjectFactory.newObject(PSOldGen.class, oldGenField.getValue()); + return VMObjectFactory.newObject(PSOldGen.class, oldGenField.getValue(addr)); } public long capacity() { From d34ef196c298aa91f8511714cfb04b15ae7fbf0a Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 8 Dec 2025 18:51:34 +0000 Subject: [PATCH 097/141] 8370198: Test gc/arguments/TestShrinkHeapInSteps.java crashed: assert(left >= right) failed: avoid underflow Reviewed-by: stefank, tschatzl --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 1 - src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 1 - src/hotspot/share/gc/serial/serialHeap.cpp | 17 +++++++++++++++++ src/hotspot/share/gc/serial/serialHeap.hpp | 2 ++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index ceedb4f1063..2ccc755be3c 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -5379,7 +5379,6 @@ void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != nullptr, "this assembler needs an OopRecorder"); int index = oop_recorder()->find_index(k); - assert(! Universe::heap()->is_in(k), "should not be an oop"); InstructionMark im(this); RelocationHolder rspec = metadata_Relocation::spec(index); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index a14a051fd3b..43b17a13c20 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -5187,7 +5187,6 @@ void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != nullptr, "this assembler needs an OopRecorder"); int index = oop_recorder()->find_index(k); - assert(!Universe::heap()->is_in(k), "should not be an oop"); narrowKlass nk = CompressedKlassPointers::encode(k); relocate(metadata_Relocation::spec(index), [&] { diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 932c06b8109..104924c1cad 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -630,6 +630,14 @@ bool SerialHeap::requires_barriers(stackChunkOop obj) const { // Returns "TRUE" iff "p" points into the committed areas of the heap. bool SerialHeap::is_in(const void* p) const { + // precondition + verify_not_in_native_if_java_thread(); + + if (!is_in_reserved(p)) { + // If it's not even in reserved. + return false; + } + return _young_gen->is_in(p) || _old_gen->is_in(p); } @@ -797,3 +805,12 @@ void SerialHeap::gc_epilogue(bool full) { MetaspaceCounters::update_performance_counters(); }; + +#ifdef ASSERT +void SerialHeap::verify_not_in_native_if_java_thread() { + if (Thread::current()->is_Java_thread()) { + JavaThread* thread = JavaThread::current(); + assert(thread->thread_state() != _thread_in_native, "precondition"); + } +} +#endif diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index ee016173c2a..f5286179abf 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -111,6 +111,8 @@ private: void print_tracing_info() const override; void stop() override {}; + static void verify_not_in_native_if_java_thread() NOT_DEBUG_RETURN; + public: // Returns JNI_OK on success jint initialize() override; From b118caf6777cbf5bf75b41156fdfaaa15479f924 Mon Sep 17 00:00:00 2001 From: Alexandre Iline Date: Mon, 8 Dec 2025 22:16:28 +0000 Subject: [PATCH 098/141] 8373285: Update JCov for class file version 71 Reviewed-by: erikj --- make/conf/jib-profiles.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 795335d7c3c..93aeebc0dd6 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -1192,8 +1192,8 @@ var getJibProfilesDependencies = function (input, common) { server: "jpg", product: "jcov", version: "3.0", - build_number: "3", - file: "bundles/jcov-3.0+3.zip", + build_number: "5", + file: "bundles/jcov-3.0+5.zip", environment_name: "JCOV_HOME", }, From 8df3f3d3417bc8fdb5a75d986e084441bbf6ebd2 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Mon, 8 Dec 2025 22:45:59 +0000 Subject: [PATCH 099/141] 8373117: Update build doc link in README.md Reviewed-by: ayang, tbell --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3f30676b3c..e939f6a9ca4 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Welcome to the JDK! For build instructions please see the -[online documentation](https://openjdk.org/groups/build/doc/building.html), +[online documentation](https://git.openjdk.org/jdk/blob/master/doc/building.md), or either of these files: - [doc/building.html](doc/building.html) (html version) From b86b2cbc7d9dd57aeaf64f70f248a120ae3cb751 Mon Sep 17 00:00:00 2001 From: Ben Taylor Date: Tue, 9 Dec 2025 00:17:30 +0000 Subject: [PATCH 100/141] 8352914: Shenandoah: Change definition of ShenandoahSharedValue to int32_t to leverage platform atomics Reviewed-by: wkemper, ysr --- .../share/gc/shenandoah/shenandoahSharedVariables.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp index 127882201d7..12c01ad5c90 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSharedVariables.hpp @@ -29,11 +29,7 @@ #include "memory/allocation.hpp" #include "runtime/atomicAccess.hpp" -typedef jbyte ShenandoahSharedValue; - -// Needed for cooperation with generated code. -STATIC_ASSERT(sizeof(ShenandoahSharedValue) == 1); - +typedef int32_t ShenandoahSharedValue; typedef struct ShenandoahSharedFlag { enum { UNSET = 0, From c03d445a8ccfced5a59da680c37587f1024f3eca Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 9 Dec 2025 00:34:58 +0000 Subject: [PATCH 101/141] 6223700: XP L&F: Non-TopLevel JMenu's painting error Reviewed-by: kizune, dnguyen --- .../swing/plaf/windows/WindowsMenuUI.java | 2 +- .../swing/JMenu/TestPaintSpillOverBug.java | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/swing/JMenu/TestPaintSpillOverBug.java diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index 130b09227cc..a7aca0c5ccf 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -301,7 +301,7 @@ public final class WindowsMenuUI extends BasicMenuUI { JMenu menu = (JMenu)evt.getSource(); ButtonModel model = menu.getModel(); - if (menu.isRolloverEnabled()) { + if (menu.isRolloverEnabled() && menu.isTopLevelMenu()) { model.setRollover(false); menuItem.repaint(); } diff --git a/test/jdk/javax/swing/JMenu/TestPaintSpillOverBug.java b/test/jdk/javax/swing/JMenu/TestPaintSpillOverBug.java new file mode 100644 index 00000000000..8452b93cf45 --- /dev/null +++ b/test/jdk/javax/swing/JMenu/TestPaintSpillOverBug.java @@ -0,0 +1,82 @@ +/* + * 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 6223700 + * @requires (os.family == "windows") + * @summary Verifies no painting spillover in Win L&F + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestPaintSpillOverBug + */ + +import javax.swing.JFrame; +import javax.swing.JMenuBar; +import javax.swing.JMenu; +import javax.swing.UIManager; + +public class TestPaintSpillOverBug { + + static final String INSTRUCTIONS = """ + A JMenu "click Me" will be shown. Click on it. + Position the mouse in the "Slowly Move Mouse Out of This" JMenu + so that the popup menu appears to the right. + Slowly move the mouse towards the edge of the item, + one pixel at a time + When the mouse hits the edge, + if the selection background spill over on to the popup + press Fail else press Pass."""; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); + + PassFailJFrame.builder() + .title("TestPaintSpillOverBug Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(TestPaintSpillOverBug::createUI) + .position(PassFailJFrame.Position.TOP_LEFT_CORNER) + .build() + .awaitAndCheck(); + + } + + static JFrame createUI() { + JFrame f = new JFrame("TestPaintSpillOverBug"); + JMenuBar bar = new JMenuBar(); + JMenu clickMe = new JMenu("Click Me"); + JMenu culprit = new JMenu("Slowly Move Mouse Out of This"); + culprit.add("This item gets partially obscured"); + culprit.add(" "); + clickMe.add(" "); + clickMe.addSeparator(); + clickMe.add(culprit); + clickMe.addSeparator(); + clickMe.add(" "); + bar.add(clickMe); + f.setJMenuBar(bar); + f.setSize(600, 200); + return f; + } +} From b1c955018281a228a67695e5077666d751cd87d2 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 9 Dec 2025 01:00:52 +0000 Subject: [PATCH 102/141] 8372554: Test windows-x64-cmp-baseline failed due to differences with splashscreen object file Reviewed-by: dholmes --- make/modules/java.desktop/lib/ClientLibraries.gmk | 1 - 1 file changed, 1 deletion(-) diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index f273065a6df..499d5bef841 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -226,7 +226,6 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) EXCLUDE_FILES := imageioJPEG.c jpegdecoder.c pngtest.c, \ EXCLUDES := $(LIBSPLASHSCREEN_EXCLUDES), \ OPTIMIZATION := SIZE, \ - LINK_TIME_OPTIMIZATION := true, \ CFLAGS := $(LIBSPLASHSCREEN_CFLAGS) \ $(GIFLIB_CFLAGS) $(LIBJPEG_CFLAGS) $(PNG_CFLAGS) $(LIBZ_CFLAGS) \ $(ICONV_CFLAGS), \ From 3ea82b9ff90aebc1a169fdd967c44408dc4a4f51 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Tue, 9 Dec 2025 01:16:48 +0000 Subject: [PATCH 103/141] 8373272: Genshen: ShenandoahOldGenerationTest fails after JDK-8373056 Reviewed-by: wkemper --- .../test_shenandoahOldGeneration.cpp | 29 ++----------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldGeneration.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldGeneration.cpp index b2491226e5c..4167e33b706 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldGeneration.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahOldGeneration.cpp @@ -165,35 +165,12 @@ TEST_VM_F(ShenandoahOldGenerationTest, test_actual_size_exceeds_promotion_reserv EXPECT_FALSE(promotions_enabled()) << "New plab can only be used for evacuations"; } -TEST_VM_F(ShenandoahOldGenerationTest, test_shared_expends_promoted_but_does_not_change_plab) { +TEST_VM_F(ShenandoahOldGenerationTest, test_expend_promoted_should_increase_expended) { SKIP_IF_NOT_SHENANDOAH(); - ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(128, ShenandoahAffiliation::OLD_GENERATION, true); - req.set_actual_size(128); - size_t actual_size = req.actual_size() * HeapWordSize; - size_t expended_before = old->get_promoted_expended(); - old->configure_plab_for_current_thread(req); + old->expend_promoted(128); size_t expended_after = old->get_promoted_expended(); - - EXPECT_EQ(expended_before + actual_size, expended_after) << "Shared promotion still expends promotion"; - EXPECT_EQ(plab_promoted(), INITIAL_PLAB_PROMOTED) << "Shared promotion should not count in plab"; - EXPECT_EQ(plab_size(), INITIAL_PLAB_SIZE) << "Shared promotion should not change size of plab"; - EXPECT_FALSE(promotions_enabled()); -} - -TEST_VM_F(ShenandoahOldGenerationTest, test_shared_evacuation_has_no_side_effects) { - SKIP_IF_NOT_SHENANDOAH(); - ShenandoahAllocRequest req = ShenandoahAllocRequest::for_shared_gc(128, ShenandoahAffiliation::OLD_GENERATION, false); - req.set_actual_size(128); - - size_t expended_before = old->get_promoted_expended(); - old->configure_plab_for_current_thread(req); - size_t expended_after = old->get_promoted_expended(); - - EXPECT_EQ(expended_before, expended_after) << "Not a promotion, should not expend promotion reserve"; - EXPECT_EQ(plab_promoted(), INITIAL_PLAB_PROMOTED) << "Not a plab, should not have touched plab"; - EXPECT_EQ(plab_size(), INITIAL_PLAB_SIZE) << "Not a plab, should not have touched plab"; - EXPECT_FALSE(promotions_enabled()); + EXPECT_EQ(expended_before + 128, expended_after) << "Should expend promotion"; } #undef SKIP_IF_NOT_SHENANDOAH From c9ab330b7bdd3cc2410ffdb336a63aa0ac7256a3 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Tue, 9 Dec 2025 03:28:11 +0000 Subject: [PATCH 104/141] 8373116: Genshen: arraycopy_work should be always done for arrays in old gen during young concurrent marking 8372498: [genshen] gc/TestAllocHumongousFragment.java#generational causes intermittent SIGSEGV crashes Reviewed-by: wkemper, kdnilsen --- .../share/gc/shenandoah/shenandoahBarrierSet.hpp | 4 ++-- .../gc/shenandoah/shenandoahBarrierSet.inline.hpp | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index 2b5bc766a46..7db478a781a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -128,8 +128,8 @@ public: void write_ref_array(HeapWord* start, size_t count); private: - template - inline void arraycopy_marking(T* dst, size_t count); + template + void arraycopy_marking(T* dst, size_t count); template inline void arraycopy_evacuation(T* src, size_t count); template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index adeea8ebf96..199256ca31b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -429,7 +429,11 @@ void ShenandoahBarrierSet::arraycopy_barrier(T* src, T* dst, size_t count) { // If marking old or young, we must evaluate the SATB barrier. This will be the only // action if we are not marking old. If we are marking old, we must still evaluate the // load reference barrier for a young collection. - arraycopy_marking(dst, count); + if (_heap->mode()->is_generational()) { + arraycopy_marking(dst, count); + } else { + arraycopy_marking(dst, count); + } } if ((gc_state & ShenandoahHeap::EVACUATION) != 0) { @@ -441,11 +445,12 @@ void ShenandoahBarrierSet::arraycopy_barrier(T* src, T* dst, size_t count) { } } -template +template void ShenandoahBarrierSet::arraycopy_marking(T* dst, size_t count) { assert(_heap->is_concurrent_mark_in_progress(), "only during marking"); if (ShenandoahSATBBarrier) { - if (!_heap->marking_context()->allocated_after_mark_start(reinterpret_cast(dst))) { + if (!_heap->marking_context()->allocated_after_mark_start(reinterpret_cast(dst)) || + (IS_GENERATIONAL && _heap->heap_region_containing(dst)->is_old() && _heap->is_concurrent_young_mark_in_progress())) { arraycopy_work(dst, count); } } From 35fe0b11015bd3a88ee21c76b54f9d4969fdedf6 Mon Sep 17 00:00:00 2001 From: Harshit470250 <133243171+Harshit470250@users.noreply.github.com> Date: Tue, 9 Dec 2025 04:59:53 +0000 Subject: [PATCH 105/141] 8372641: [s390x] Test failure TestMergeStores.java Reviewed-by: mhaessig, amitkumar, lucy --- src/hotspot/cpu/s390/s390.ad | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 7d3e963a108..19bd3620228 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1715,6 +1715,8 @@ bool Matcher::match_rule_supported(int opcode) { switch (opcode) { case Op_ReverseBytesI: case Op_ReverseBytesL: + case Op_ReverseBytesS: + case Op_ReverseBytesUS: return UseByteReverseInstruction; case Op_PopCountI: case Op_PopCountL: @@ -11615,6 +11617,38 @@ instruct vround2D_reg(vecX dst, vecX src, immI8 rmode) %{ // Byte reverse +instruct bytes_reverse_short(iRegI dst, iRegI src) %{ + match(Set dst (ReverseBytesS src)); + predicate(UseByteReverseInstruction); + ins_cost(2 * DEFAULT_COST); + size(8); + + format %{ "LRVR $dst, $src\n\t # byte reverse int" + "SRA $dst, 0x0010\t # right shift by 16, sign extended" %} + + ins_encode %{ + __ z_lrvr($dst$$Register, $src$$Register); + __ z_sra($dst$$Register, 0x0010); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct bytes_reverse_unsigned_short(iRegI dst, iRegI src) %{ + match(Set dst (ReverseBytesUS src)); + predicate(UseByteReverseInstruction); + ins_cost(2 * DEFAULT_COST); + size(8); + + format %{ "LRVR $dst, $src\n\t # byte reverse int" + "SRL $dst, 0x0010\t # right shift by 16, zero extended" %} + + ins_encode %{ + __ z_lrvr($dst$$Register, $src$$Register); + __ z_srl($dst$$Register, 0x0010); + %} + ins_pipe(pipe_class_dummy); +%} + instruct bytes_reverse_int(iRegI dst, iRegI src) %{ match(Set dst (ReverseBytesI src)); predicate(UseByteReverseInstruction); // See Matcher::match_rule_supported From 020e3f959194029715c18891e79aeed020abd59c Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 9 Dec 2025 05:15:47 +0000 Subject: [PATCH 106/141] 8373293: Change the exception handling in TestNestHostErrorWithMultiThread.java Reviewed-by: jpai, iklam --- .../TestNestHostErrorWithMultiThread.java | 69 +++++++++++++------ 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestHostErrorWithMultiThread.java b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestHostErrorWithMultiThread.java index 11025fd4c12..0559c5858e0 100644 --- a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestHostErrorWithMultiThread.java +++ b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestHostErrorWithMultiThread.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,14 +41,12 @@ import java.util.concurrent.CountDownLatch; public class TestNestHostErrorWithMultiThread { - public static void main(String args[]) { + public static void main(String args[]) throws Throwable { CountDownLatch runLatch = new CountDownLatch(1); CountDownLatch startLatch = new CountDownLatch(2); - Runnable test = new Test(runLatch, startLatch); - - Thread t1 = new Thread(test); - Thread t2 = new Thread(test); + TestThread t1 = new TestThread(runLatch, startLatch); + TestThread t2 = new TestThread(runLatch, startLatch); t1.start(); t2.start(); @@ -59,39 +58,65 @@ public class TestNestHostErrorWithMultiThread { t1.join(); t2.join(); + + Throwable threadException = t1.exception() != null ? t1.exception() + : t2.exception(); + if (threadException != null) { + Throwable t = threadException; + try { + throw new Error("TestThread encountered unexpected exception", t); + } + catch (OutOfMemoryError oome) { + // If we encounter an OOME trying to create the wrapper Error, + // then just re-throw the original exception so we report it and + // not the secondary OOME. + throw t; + } + } } catch (InterruptedException e) { throw new Error("Unexpected interrupt"); } } - static class Test implements Runnable { + static class TestThread extends Thread { private CountDownLatch runLatch; private CountDownLatch startLatch; + private Throwable exception; - Test(CountDownLatch runLatch, CountDownLatch startLatch) { + Throwable exception() { + return exception; + } + + TestThread(CountDownLatch runLatch, CountDownLatch startLatch) { this.runLatch = runLatch; this.startLatch = startLatch; } @Override public void run() { + // Don't allow any exceptions to escape - the main thread will + // report them. try { - startLatch.countDown(); - // Try to have all threads trigger the nesthost check at the same time - runLatch.await(); - HostNoNestMember h = new HostNoNestMember(); - h.test(); - throw new Error("IllegalAccessError was not thrown as expected"); - } catch (IllegalAccessError expected) { - String msg = "current type is not listed as a nest member"; - if (!expected.getMessage().contains(msg)) { - throw new Error("Wrong " + expected.getClass().getSimpleName() +": \"" + - expected.getMessage() + "\" does not contain \"" + - msg + "\"", expected); + try { + startLatch.countDown(); + // Try to have all threads trigger the nesthost check at the same time + runLatch.await(); + HostNoNestMember h = new HostNoNestMember(); + h.test(); + throw new Error("IllegalAccessError was not thrown as expected"); + } catch (IllegalAccessError expected) { + String msg = "current type is not listed as a nest member"; + if (!expected.getMessage().contains(msg)) { + throw new Error("Wrong " + expected.getClass().getSimpleName() +": \"" + + expected.getMessage() + "\" does not contain \"" + + msg + "\"", expected); + } + System.out.println("OK - got expected exception: " + expected); + } catch (InterruptedException e) { + throw new Error("Unexpected interrupt", e); } - System.out.println("OK - got expected exception: " + expected); - } catch (InterruptedException e) { - throw new Error("Unexpected interrupt"); + } catch (Throwable t) { + exception = t; } } } From cba09cd10d4e4482852a317786242836419c313b Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 9 Dec 2025 07:40:52 +0000 Subject: [PATCH 107/141] 5107379: Component orientation in JOptionPane is not proper in Motif L&F. Reviewed-by: tr, kizune --- .../swing/plaf/motif/MotifOptionPaneUI.java | 5 +- .../javax/swing/plaf/motif/TestIconRTL.java | 119 ++++++++++++++++++ 2 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 test/jdk/javax/swing/plaf/motif/TestIconRTL.java 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 e68d7e2d8bf..21e8c0f6747 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, 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 @@ -25,6 +25,7 @@ package com.sun.java.swing.plaf.motif; +import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; @@ -102,7 +103,7 @@ public class MotifOptionPaneUI extends BasicOptionPaneUI JLabel iconLabel = new JLabel(sideIcon); iconLabel.setVerticalAlignment(SwingConstants.CENTER); - top.add(iconLabel, "West"); + top.add(iconLabel, BorderLayout.BEFORE_LINE_BEGINS); } } diff --git a/test/jdk/javax/swing/plaf/motif/TestIconRTL.java b/test/jdk/javax/swing/plaf/motif/TestIconRTL.java new file mode 100644 index 00000000000..e86e1ab38a6 --- /dev/null +++ b/test/jdk/javax/swing/plaf/motif/TestIconRTL.java @@ -0,0 +1,119 @@ +/* + * 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 5107379 + * @summary Component orientation in JOptionPane is not proper in Motif L&F. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestIconRTL + */ + +import java.awt.ComponentOrientation; +import java.util.concurrent.atomic.AtomicBoolean; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class TestIconRTL { + + private static JFrame frame; + private static JOptionPane pane; + + static final String INSTRUCTIONS = """ + A JOptionPane is shown in Motif LookAndFeel with "Orientation" menu. + Click on "Orientation" menu and + test with "Left To Right" and "Right to Left" Orientation + If JOptionPane is drawn properly in different orientation, + then test passed, otherwise it failed."""; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel"); + PassFailJFrame.builder() + .title("TestIconRTL Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(TestIconRTL::createTestUI) + .build() + .awaitAndCheck(); + } + + static JFrame createTestUI() { + pane = new JOptionPane(new String("Testing CCC4265463"), + JOptionPane.INFORMATION_MESSAGE, JOptionPane.YES_NO_CANCEL_OPTION); + pane.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + pane.setVisible(true); + + frame = new JFrame("TestIconRTL"); + + JMenuBar menuBar = new JMenuBar(); + menuBar.add(getOrientationJMenu()); + + frame.setJMenuBar(menuBar); + + frame.getContentPane().add(pane); + frame.pack(); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setLocationRelativeTo(null); + return frame; + } + + public static void test() throws Exception { + AtomicBoolean leftToRightOrientationFlag = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> leftToRightOrientationFlag.set(pane.getComponentOrientation().isLeftToRight())); + if (leftToRightOrientationFlag.get()) { + System.out.println("LTR LOCATION ..."); + } else { + System.out.println("RTL LOCATION ..."); + } + } + + private static JMenu getOrientationJMenu() { + JMenu lafMenu = new JMenu("Orientation"); + JMenuItem leftToRight = new JMenuItem("Left to Right"); + leftToRight.addActionListener(e -> { + pane.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT); + pane.invalidate(); + SwingUtilities.updateComponentTreeUI(frame); + }); + + JMenuItem rightToLeft = new JMenuItem("Right to Left"); + rightToLeft.addActionListener(e -> { + pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); + pane.invalidate(); + SwingUtilities.updateComponentTreeUI(frame); + }); + + pane.invalidate(); + lafMenu.add(leftToRight); + lafMenu.add(rightToLeft); + return lafMenu; + } + + +} From 3a8a6e07f2a2cffa467815df55e746e92765903d Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Tue, 9 Dec 2025 09:15:04 +0000 Subject: [PATCH 108/141] 8319326: GC: Make TestParallelRefProc use createTestJavaProcessBuilder Reviewed-by: stefank, iwalulya --- .../gc/arguments/TestParallelRefProc.java | 85 +++++++++++++------ 1 file changed, 57 insertions(+), 28 deletions(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java b/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java index 6e2e3c0239e..2cd9e9cd60b 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelRefProc.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 @@ -24,13 +24,30 @@ package gc.arguments; /* - * @test TestParallelRefProc - * @summary Test defaults processing for -XX:+ParallelRefProcEnabled. + * @test id=Serial + * @summary Test defaults processing for -XX:+ParallelRefProcEnabled with Serial GC. * @library /test/lib * @library / - * @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 gc.arguments.TestParallelRefProc + * @requires vm.gc.Serial + * @run driver gc.arguments.TestParallelRefProc Serial + */ + +/* + * @test id=Parallel + * @summary Test defaults processing for -XX:+ParallelRefProcEnabled with Parallel GC. + * @library /test/lib + * @library / + * @requires vm.gc.Parallel + * @run driver gc.arguments.TestParallelRefProc Parallel + */ + +/* + * @test id=G1 + * @summary Test defaults processing for -XX:+ParallelRefProcEnabled with G1 GC. + * @library /test/lib + * @library / + * @requires vm.gc.G1 + * @run driver gc.arguments.TestParallelRefProc G1 */ import java.util.Arrays; @@ -38,34 +55,46 @@ import java.util.ArrayList; import jdk.test.lib.process.OutputAnalyzer; -import jtreg.SkippedException; -import jdk.test.whitebox.gc.GC; - public class TestParallelRefProc { public static void main(String args[]) throws Exception { - boolean noneGCSupported = true; - if (GC.Serial.isSupported()) { - noneGCSupported = false; - testFlag(new String[] { "-XX:+UseSerialGC" }, false); + if (args.length == 0) { + throw new IllegalArgumentException("Test type must be specified as argument"); } - if (GC.Parallel.isSupported()) { - noneGCSupported = false; - testFlag(new String[] { "-XX:+UseParallelGC", "-XX:ParallelGCThreads=1" }, false); - testFlag(new String[] { "-XX:+UseParallelGC", "-XX:ParallelGCThreads=2" }, true); - testFlag(new String[] { "-XX:+UseParallelGC", "-XX:-ParallelRefProcEnabled", "-XX:ParallelGCThreads=2" }, false); - } - if (GC.G1.isSupported()) { - noneGCSupported = false; - testFlag(new String[] { "-XX:+UseG1GC", "-XX:ParallelGCThreads=1" }, false); - testFlag(new String[] { "-XX:+UseG1GC", "-XX:ParallelGCThreads=2" }, true); - testFlag(new String[] { "-XX:+UseG1GC", "-XX:-ParallelRefProcEnabled", "-XX:ParallelGCThreads=2" }, false); - } - if (noneGCSupported) { - throw new SkippedException("Skipping test because none of Serial/Parallel/G1 is supported."); + + String testType = args[0]; + + switch (testType) { + case "Serial": + testSerial(); + break; + case "Parallel": + testParallel(); + break; + case "G1": + testG1(); + break; + default: + throw new IllegalArgumentException("Unknown test type \"" + testType + "\""); } } + private static void testSerial() throws Exception { + testFlag(new String[] { "-XX:+UseSerialGC" }, false); + } + + private static void testParallel() throws Exception { + testFlag(new String[] { "-XX:+UseParallelGC", "-XX:ParallelGCThreads=1" }, false); + testFlag(new String[] { "-XX:+UseParallelGC", "-XX:ParallelGCThreads=2" }, true); + testFlag(new String[] { "-XX:+UseParallelGC", "-XX:-ParallelRefProcEnabled", "-XX:ParallelGCThreads=2" }, false); + } + + private static void testG1() throws Exception { + testFlag(new String[] { "-XX:+UseG1GC", "-XX:ParallelGCThreads=1" }, false); + testFlag(new String[] { "-XX:+UseG1GC", "-XX:ParallelGCThreads=2" }, true); + testFlag(new String[] { "-XX:+UseG1GC", "-XX:-ParallelRefProcEnabled", "-XX:ParallelGCThreads=2" }, false); + } + private static final String parallelRefProcEnabledPattern = " *bool +ParallelRefProcEnabled *= *true +\\{product\\}"; @@ -77,7 +106,7 @@ public class TestParallelRefProc { result.addAll(Arrays.asList(args)); result.add("-XX:+PrintFlagsFinal"); result.add("-version"); - OutputAnalyzer output = GCArguments.executeLimitedTestJava(result); + OutputAnalyzer output = GCArguments.executeTestJava(result); output.shouldHaveExitValue(0); From 24244e41210be5b71b9e8238badbf975ed4b02ef Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Tue, 9 Dec 2025 09:17:38 +0000 Subject: [PATCH 109/141] 8319161: GC: Make TestParallelGCThreads use createTestJavaProcessBuilder Reviewed-by: stefank, iwalulya --- .../gc/arguments/TestParallelGCThreads.java | 139 ++++++++++++------ 1 file changed, 91 insertions(+), 48 deletions(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java b/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java index 0ce17efd1a7..9b5e9843b5e 100644 --- a/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.java +++ b/test/hotspot/jtreg/gc/arguments/TestParallelGCThreads.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 @@ -24,30 +24,86 @@ package gc.arguments; /* - * @test TestParallelGCThreads + * @test id=DefaultValue * @bug 8059527 8081382 - * @summary Tests argument processing for ParallelGCThreads + * @summary Tests default value of ParallelGCThreads * @library /test/lib * @library / - * @modules java.base/jdk.internal.misc - * java.management - * @build jdk.test.whitebox.WhiteBox - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI gc.arguments.TestParallelGCThreads + * @requires vm.gc.Z | vm.gc.Parallel | vm.gc.G1 + * @run driver gc.arguments.TestParallelGCThreads DefaultValue + */ + +/* + * @test id=Z + * @bug 8059527 8081382 + * @summary Tests argument processing for ParallelGCThreads with ZGC + * @library /test/lib + * @library / + * @requires vm.gc.Z + * @run driver gc.arguments.TestParallelGCThreads Z + */ + +/* + * @test id=Parallel + * @bug 8059527 8081382 + * @summary Tests argument processing for ParallelGCThreads with Parallel GC + * @library /test/lib + * @library / + * @requires vm.gc.Parallel + * @run driver gc.arguments.TestParallelGCThreads Parallel + */ + +/* + * @test id=G1 + * @bug 8059527 8081382 + * @summary Tests argument processing for ParallelGCThreads with G1 GC + * @library /test/lib + * @library / + * @requires vm.gc.G1 + * @run driver gc.arguments.TestParallelGCThreads G1 + */ + +/* + * @test id=MaxValue + * @bug 8059527 8081382 + * @summary Tests max value for ParallelGCThreads + * @library /test/lib + * @library / + * @requires vm.gc.Serial + * @run driver gc.arguments.TestParallelGCThreads MaxValue */ -import java.util.ArrayList; -import java.util.List; import jdk.test.lib.Asserts; import jdk.test.lib.process.OutputAnalyzer; -import jtreg.SkippedException; -import jdk.test.whitebox.gc.GC; public class TestParallelGCThreads { public static void main(String args[]) throws Exception { - testFlags(); - testDefaultValue(); + if (args.length == 0) { + throw new IllegalArgumentException("Test type must be specified as argument"); + } + + String testType = args[0]; + + switch (testType) { + case "DefaultValue": + testDefaultValue(); + break; + case "Z": + testFlags("-XX:+UseZGC"); + break; + case "Parallel": + testFlags("-XX:+UseParallelGC"); + break; + case "G1": + testFlags("-XX:+UseG1GC"); + break; + case "MaxValue": + testMaxValue(); + break; + default: + throw new IllegalArgumentException("Unknown test type \"" + testType + "\""); + } } private static final String flagName = "ParallelGCThreads"; @@ -55,8 +111,8 @@ public class TestParallelGCThreads { // uint ParallelGCThreads = 23 {product} private static final String printFlagsFinalPattern = " *uint *" + flagName + " *:?= *(\\d+) *\\{product\\} *"; - public static void testDefaultValue() throws Exception { - OutputAnalyzer output = GCArguments.executeLimitedTestJava( + private static void testDefaultValue() throws Exception { + OutputAnalyzer output = GCArguments.executeTestJava( "-XX:+UnlockExperimentalVMOptions", "-XX:+PrintFlagsFinal", "-version"); String value = output.firstMatch(printFlagsFinalPattern, 1); @@ -64,10 +120,10 @@ public class TestParallelGCThreads { try { Asserts.assertNotNull(value, "Couldn't find uint flag " + flagName); - Long longValue = new Long(value); + Long longValue = Long.valueOf(value); // Sanity check that we got a non-zero value. - Asserts.assertNotEquals(longValue, "0"); + Asserts.assertNotEquals(longValue, 0L); output.shouldHaveExitValue(0); } catch (Exception e) { @@ -76,41 +132,28 @@ public class TestParallelGCThreads { } } - public static void testFlags() throws Exception { - // For each parallel collector (G1, Parallel) - List supportedGC = new ArrayList(); + private static void testFlags(String gcFlag) throws Exception { - if (GC.G1.isSupported()) { - supportedGC.add("G1"); - } - if (GC.Parallel.isSupported()) { - supportedGC.add("Parallel"); - } + // Make sure the VM does not allow ParallelGCThreads set to 0 + OutputAnalyzer output = GCArguments.executeTestJava( + gcFlag, + "-XX:ParallelGCThreads=0", + "-XX:+PrintFlagsFinal", + "-version"); + output.shouldHaveExitValue(1); - if (supportedGC.isEmpty()) { - throw new SkippedException("Skipping test because none of G1/Parallel is supported."); - } - - for (String gc : supportedGC) { - // Make sure the VM does not allow ParallelGCThreads set to 0 - OutputAnalyzer output = GCArguments.executeLimitedTestJava( - "-XX:+Use" + gc + "GC", - "-XX:ParallelGCThreads=0", + // Do some basic testing to ensure the flag updates the count + for (long i = 1; i <= 3; i++) { + long count = getParallelGCThreadCount( + gcFlag, + "-XX:ParallelGCThreads=" + i, "-XX:+PrintFlagsFinal", "-version"); - output.shouldHaveExitValue(1); - - // Do some basic testing to ensure the flag updates the count - for (long i = 1; i <= 3; i++) { - long count = getParallelGCThreadCount( - "-XX:+Use" + gc + "GC", - "-XX:ParallelGCThreads=" + i, - "-XX:+PrintFlagsFinal", - "-version"); - Asserts.assertEQ(count, i, "Specifying ParallelGCThreads=" + i + " for " + gc + "GC does not set the thread count properly!"); - } + Asserts.assertEQ(count, i, "Specifying ParallelGCThreads=" + i + " for \"" + gcFlag + "\" does not set the thread count properly!"); } + } + private static void testMaxValue() throws Exception { // Test the max value for ParallelGCThreads // So setting ParallelGCThreads=2147483647 should give back 2147483647 long count = getParallelGCThreadCount( @@ -122,7 +165,7 @@ public class TestParallelGCThreads { } public static long getParallelGCThreadCount(String... flags) throws Exception { - OutputAnalyzer output = GCArguments.executeLimitedTestJava(flags); + OutputAnalyzer output = GCArguments.executeTestJava(flags); output.shouldHaveExitValue(0); String stdout = output.getStdout(); return FlagsValue.getFlagLongValue("ParallelGCThreads", stdout); From 9c91c68d1d5938d7e2b9a90c82b0a36ef1a063cd Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Tue, 9 Dec 2025 09:18:04 +0000 Subject: [PATCH 110/141] 8373111: Test java/lang/management/MemoryMXBean/MemoryManagement.java timed out Reviewed-by: lmesnik --- .../management/MemoryMXBean/MemoryManagement.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/lang/management/MemoryMXBean/MemoryManagement.java b/test/jdk/java/lang/management/MemoryMXBean/MemoryManagement.java index b136b724b71..f6c7446d1f3 100644 --- a/test/jdk/java/lang/management/MemoryMXBean/MemoryManagement.java +++ b/test/jdk/java/lang/management/MemoryMXBean/MemoryManagement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, 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 @@ -49,7 +49,7 @@ * * @modules jdk.management * - * @run main/timeout=600 MemoryManagement + * @run main/othervm/timeout=600 -Xmn8m MemoryManagement */ import java.lang.management.*; @@ -58,6 +58,10 @@ import javax.management.*; import javax.management.openmbean.CompositeData; public class MemoryManagement { + + private static final int YOUNG_GEN_SIZE = 8 * 1024 * 1024; // Must match -Xmn set on the @run line + private static final int NUM_CHUNKS = 2; + private static final MemoryMXBean mm = ManagementFactory.getMemoryMXBean(); private static final List pools = Collections.synchronizedList(ManagementFactory.getMemoryPoolMXBeans()); @@ -66,9 +70,6 @@ public class MemoryManagement { private static volatile MemoryPoolMXBean mpool = null; private static volatile boolean trace = false; private static volatile boolean testFailed = false; - private static final int NUM_CHUNKS = 2; - // Must match -Xmn set on the @run line - private static final int YOUNG_GEN_SIZE = 8 * 1024 * 1024; private static volatile long chunkSize; private static volatile int listenerInvoked = 0; From 786833cd1bf8eda1cef25da392a055f4eb371abf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sikstr=C3=B6m?= Date: Tue, 9 Dec 2025 09:44:18 +0000 Subject: [PATCH 111/141] 8373022: serviceability/sa/ClhsdbScanOops.java assumes no GC should occur Reviewed-by: cjplummer, stefank, ayang, tschatzl --- test/hotspot/jtreg/ProblemList.txt | 3 --- test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java | 5 ++++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index ddc6e55dc05..48d0da048fe 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -140,9 +140,6 @@ serviceability/sa/ClhsdbPstack.java#core 8318754 macosx-aarch64 serviceability/sa/TestJmapCore.java 8318754 macosx-aarch64 serviceability/sa/TestJmapCoreMetaspace.java 8318754 macosx-aarch64 -serviceability/sa/ClhsdbScanOops.java#parallel 8373022 generic-all -serviceability/sa/ClhsdbScanOops.java#serial 8373022 generic-all - serviceability/sa/ClhsdbThreadContext.java 8356704 windows-x64 serviceability/jvmti/stress/StackTrace/NotSuspended/GetStackTraceNotSuspendedStressTest.java 8315980 linux-all,windows-x64 diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java index b6919a566a9..ef75b08c995 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbScanOops.java @@ -60,7 +60,10 @@ public class ClhsdbScanOops { try { ClhsdbLauncher test = new ClhsdbLauncher(); - theApp = LingeredApp.startApp(gc); + // This test assumes that no GC should happen during its execution. + // Setting the initial heap size to a reasonably high number avoids + // running a GC. + theApp = LingeredApp.startApp(gc, "-XX:InitialHeapSize=100M"); System.out.println ("Started LingeredApp with the GC option " + gc + " and pid " + theApp.getPid()); From 1f49edd9783ed4579d989d6939ee75e926f0716a Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 9 Dec 2025 10:02:01 +0000 Subject: [PATCH 112/141] 4459231: Focus of JTabbedPane(with Scrollable tablayout) changes on change in LookAndFeel Reviewed-by: tr, kizune --- .../swing/plaf/basic/BasicTabbedPaneUI.java | 10 ++ .../JTabbedPane/TabbedPaneBugWithLNF.java | 110 ++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 test/jdk/javax/swing/JTabbedPane/TabbedPaneBugWithLNF.java diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java index 59799f4d91a..842e8892c76 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -293,6 +293,16 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { installDefaults(); installListeners(); installKeyboardActions(); + setFocusIndex(tabPane.getSelectedIndex(), false); + + if (tabPane.getLayout() instanceof TabbedPaneScrollLayout) { + ensureCurrentLayout(); + int index = tabPane.getSelectedIndex(); + if (index < rects.length && index != -1) { + tabScroller.tabPanel.scrollRectToVisible( + (Rectangle)rects[index].clone()); + } + } } public void uninstallUI(JComponent c) { diff --git a/test/jdk/javax/swing/JTabbedPane/TabbedPaneBugWithLNF.java b/test/jdk/javax/swing/JTabbedPane/TabbedPaneBugWithLNF.java new file mode 100644 index 00000000000..cf989280da2 --- /dev/null +++ b/test/jdk/javax/swing/JTabbedPane/TabbedPaneBugWithLNF.java @@ -0,0 +1,110 @@ +/* + * 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 4459231 + * @summary Verifies if JTabbedPane(with Scrollable tablayout) changes focus + * on change in LookAndFeel + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TabbedPaneBugWithLNF + */ + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +public class TabbedPaneBugWithLNF { + + private static String LNF = "com.sun.java.swing.plaf.motif.MotifLookAndFeel"; + private static JTabbedPane tabPane; + private static JButton testBtn; + + static final String INSTRUCTIONS = """ + A JTabbedPane with 10 tabs will be shown. + Scroll the tabs till the end, i.e., to "Testing Tab9". + Select that tab. + You will see the main tab JButton's text changed to 'Test Button9'. + Click on it, which will change the lookandfeel. + Verify if child tabs have scrolled back to starting child tab + i.e., 'Testing Tab0', where as the selected tab is still 'Testing Tab9'. + If it does, press Fail + else if focus of the child Tab is still at "Testing Tab9" press Pass."""; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); + PassFailJFrame.builder() + .title("TabbedPaneBugWithLNF Test Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(TabbedPaneBugWithLNF::createUI) + .position(PassFailJFrame.Position.TOP_LEFT_CORNER) + .build() + .awaitAndCheck(); + } + + static JFrame createUI() { + JFrame frame = new JFrame("TabbedPaneBugWithLNF"); + frame.setSize(640, 180); + + tabPane = new JTabbedPane(JTabbedPane.BOTTOM,JTabbedPane.SCROLL_TAB_LAYOUT); + + tabPane.addTab("Testing Tab0", testBtn = new JButton("Test Button0")); + + tabPane.addTab("Testing Tab1", testBtn = new JButton("Test Button1")); + + tabPane.addTab("Testing Tab2", testBtn = new JButton("Test Button2")); + + tabPane.addTab("Testing Tab3", testBtn = new JButton("Test Button3")); + + tabPane.addTab("Testing Tab4", testBtn = new JButton("Test Button4")); + + tabPane.addTab("Testing Tab5", testBtn = new JButton("Test Button5")); + + tabPane.addTab("Testing Tab6", testBtn = new JButton("Test Button6")); + + tabPane.addTab("Testing Tab7", testBtn = new JButton("Test Button7")); + tabPane.addTab("Testing Tab8", testBtn = new JButton("Test Button8")); + JButton myBtn = null; + tabPane.addTab("Testing Tab9", myBtn = new JButton("Test Button9")); + myBtn.addActionListener( new ActionListener() { + public void actionPerformed(ActionEvent ae) { + try { + UIManager.setLookAndFeel(LNF); + SwingUtilities.updateComponentTreeUI(frame); + System.out.println("tabPane.selectedIndex " + tabPane.getSelectedIndex()); + } catch (Exception exc) { + System.out.println("Error changing L&F : " + LNF); + } + } + }); + frame.add(tabPane); + return frame; + } +} + From 0a557890a50b0dc83c70dc877027d951dcc05470 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 9 Dec 2025 10:04:25 +0000 Subject: [PATCH 113/141] 8373025: test/hotspot/jtreg/gc/cslocker/TestCSLocker.java may deadlock Reviewed-by: ayang, tschatzl, stefank --- test/hotspot/jtreg/ProblemList.txt | 1 - .../jtreg/gc/cslocker/TestCSLocker.java | 24 ++++------------- .../jtreg/gc/cslocker/libTestCSLocker.c | 26 +++++++++++-------- 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 48d0da048fe..177c14da785 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -94,7 +94,6 @@ gc/shenandoah/TestEvilSyncBug.java#generational 8345501 generic-all gc/shenandoah/TestRetainObjects.java#no-tlab 8361099 generic-all gc/shenandoah/TestSieveObjects.java#no-tlab 8361099 generic-all gc/shenandoah/TestSieveObjects.java#no-tlab-genshen 8361099 generic-all -gc/cslocker/TestCSLocker.java 8373025 generic-all ############################################################################# diff --git a/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java b/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java index 3550c4e5f14..82dc2fb99a1 100644 --- a/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java +++ b/test/hotspot/jtreg/gc/cslocker/TestCSLocker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,18 +33,11 @@ import static gc.testlibrary.Allocation.blackHole; * @summary completely in JNI CS, while other is trying to allocate memory * @summary provoking GC. OOM means FAIL, deadlock means PASS. * - * @comment This test assumes that no allocation happens during the sleep loop, - * which is something that we can't guarantee. With ZGC we see test - * timeouts because the main thread allocates and waits for the GC, - * which waits for the CSLocker, which waits for the main thread. - * @requires vm.gc != "Z" - * * @run main/native/othervm -Xmx256m gc.cslocker.TestCSLocker */ public class TestCSLocker extends Thread { - static int timeoutMillis = 5000; public static void main(String args[]) throws Exception { // start garbage producer thread GarbageProducer garbageProducer = new GarbageProducer(1000000, 10); @@ -53,15 +46,9 @@ public class TestCSLocker extends Thread // start CS locker thread CSLocker csLocker = new CSLocker(); csLocker.start(); - // After the CSLocker thread has started, any operation such as an allocation, - // which could rely on the GC to make progress, will cause a deadlock that will - // make the test time out. That includes printing. Please don't use any such - // code until unlock() is called below. - // check timeout to success deadlocking - sleep(timeoutMillis); - - csLocker.unlock(); + // Wait for the csLocker thread to finish its critical section + csLocker.join(); garbageProducer.interrupt(); } } @@ -97,11 +84,10 @@ class CSLocker extends Thread public void run() { int[] a = new int[10]; a[0] = 1; - if (!lock(a)) { + if (!criticalSection(a)) { throw new RuntimeException("failed to acquire CSLock"); } } - native boolean lock(int[] array); - native void unlock(); + native boolean criticalSection(int[] array); } diff --git a/test/hotspot/jtreg/gc/cslocker/libTestCSLocker.c b/test/hotspot/jtreg/gc/cslocker/libTestCSLocker.c index ae75c631072..58779d40cb9 100644 --- a/test/hotspot/jtreg/gc/cslocker/libTestCSLocker.c +++ b/test/hotspot/jtreg/gc/cslocker/libTestCSLocker.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,9 +23,15 @@ #include +#ifdef WINDOWS +#include +#else +#include +#endif + static volatile int release_critical = 0; -JNIEXPORT jboolean JNICALL Java_gc_cslocker_CSLocker_lock +JNIEXPORT jboolean JNICALL Java_gc_cslocker_CSLocker_criticalSection (JNIEnv *env, jobject obj, jintArray array) { jboolean retval = JNI_TRUE; @@ -33,17 +39,15 @@ JNIEXPORT jboolean JNICALL Java_gc_cslocker_CSLocker_lock if (nativeArray == NULL) { retval = JNI_FALSE; + } else { + // Wait for 5 seconds +#ifdef WINDOWS + Sleep(5000); +#else + sleep(5); +#endif } - // deadblock - while (!release_critical) /* empty */; - (*env)->ReleasePrimitiveArrayCritical(env, array, nativeArray, 0); return retval; } - -JNIEXPORT void JNICALL Java_gc_cslocker_CSLocker_unlock - (JNIEnv *env, jobject obj) -{ - release_critical = 1; -} From 830c4d3b198597b6af7a21b708bd3a852af200d4 Mon Sep 17 00:00:00 2001 From: Anton Artemov Date: Tue, 9 Dec 2025 10:15:04 +0000 Subject: [PATCH 114/141] 8366272: The os::xxx APIs do not manage errno correctly Reviewed-by: dholmes --- src/hotspot/os/aix/os_aix.cpp | 2 +- src/hotspot/os/bsd/os_bsd.cpp | 2 +- src/hotspot/os/linux/os_linux.cpp | 2 +- src/hotspot/os/posix/os_posix.cpp | 1 + src/hotspot/os/posix/signals_posix.cpp | 3 +-- src/hotspot/os/windows/os_windows.cpp | 11 ++++++----- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 7de031cac58..f88729cdc66 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -2333,8 +2333,8 @@ int os::open(const char *path, int oflag, int mode) { if (ret != -1) { if ((st_mode & S_IFMT) == S_IFDIR) { - errno = EISDIR; ::close(fd); + errno = EISDIR; return -1; } } else { diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 0889cc4cdf8..dc8f5187b5a 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -2277,8 +2277,8 @@ int os::open(const char *path, int oflag, int mode) { if (ret != -1) { if ((st_mode & S_IFMT) == S_IFDIR) { - errno = EISDIR; ::close(fd); + errno = EISDIR; return -1; } } else { diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 880dbeccf7d..ba05fde7f12 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4932,8 +4932,8 @@ int os::open(const char *path, int oflag, int mode) { if (ret != -1) { if ((st_mode & S_IFMT) == S_IFDIR) { - errno = EISDIR; ::close(fd); + errno = EISDIR; return -1; } } else { diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 8f1f07dd055..ef52b946cc6 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1028,6 +1028,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } else { errno = ENAMETOOLONG; } + ErrnoPreserver ep; permit_forbidden_function::free(p); // *not* os::free } else { // Fallback for platforms struggling with modern Posix standards (AIX 5.3, 6.1). If realpath diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 625eb63445a..a989b40d49d 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -1645,7 +1645,7 @@ static void SR_handler(int sig, siginfo_t* siginfo, void* context) { // Save and restore errno to avoid confusing native code with EINTR // after sigsuspend. - int old_errno = errno; + ErrnoPreserver ep; PosixSignals::unblock_error_signals(); @@ -1727,7 +1727,6 @@ static void SR_handler(int sig, siginfo_t* siginfo, void* context) { // ignore } - errno = old_errno; } static int SR_initialize() { diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index b9aeb4e8dd6..0ac05e8a435 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -4782,8 +4782,8 @@ int os::stat(const char *path, struct stat *sbuf) { path_to_target = get_path_to_target(wide_path); if (path_to_target == nullptr) { // it is a symbolic link, but we failed to resolve it - errno = ENOENT; os::free(wide_path); + errno = ENOENT; return -1; } } @@ -4794,14 +4794,14 @@ int os::stat(const char *path, struct stat *sbuf) { // if getting attributes failed, GetLastError should be called immediately after that if (!bret) { DWORD errcode = ::GetLastError(); + log_debug(os)("os::stat() failed to GetFileAttributesExW: GetLastError->%lu.", errcode); + os::free(wide_path); + os::free(path_to_target); if (errcode == ERROR_FILE_NOT_FOUND || errcode == ERROR_PATH_NOT_FOUND) { errno = ENOENT; } else { errno = 0; } - log_debug(os)("os::stat() failed to GetFileAttributesExW: GetLastError->%lu.", errcode); - os::free(wide_path); - os::free(path_to_target); return -1; } @@ -5000,8 +5000,8 @@ int os::open(const char *path, int oflag, int mode) { path_to_target = get_path_to_target(wide_path); if (path_to_target == nullptr) { // it is a symbolic link, but we failed to resolve it - errno = ENOENT; os::free(wide_path); + errno = ENOENT; return -1; } } @@ -5275,6 +5275,7 @@ char* os::realpath(const char* filename, char* outbuf, size_t outbuflen) { } else { errno = ENAMETOOLONG; } + ErrnoPreserver ep; permit_forbidden_function::free(p); // *not* os::free } return result; From a4eb57c5ec6254e59e486042015dd00457284ef2 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 9 Dec 2025 12:45:36 +0000 Subject: [PATCH 115/141] 8367028: compiler/c2/irTests/TestFloat16ScalarOperations.java failing intermittently because of constant folding Reviewed-by: chagedorn, syan, rcastanedalo --- .../irTests/TestFloat16ScalarOperations.java | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java index c8ee5e730fa..445fef5e55a 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java @@ -68,6 +68,15 @@ public class TestFloat16ScalarOperations { private static final Float16 RANDOM4 = Float16.valueOf(genF.next()); private static final Float16 RANDOM5 = Float16.valueOf(genF.next()); + // We have to ensure that the constants are not special values that lead the operations to + // constant fold. For example "x + 0" could constant fold to "x", so we need to avoid that + // the add constant is zero. + private static Generator genSmallRangeF = G.uniformFloats(0.1f, 0.9f); + private static final Float16 RANDOM_CON_ADD = Float16.valueOf(genSmallRangeF.next()); + private static final Float16 RANDOM_CON_SUB = Float16.valueOf(genSmallRangeF.next()); + private static final Float16 RANDOM_CON_MUL = Float16.valueOf(genSmallRangeF.next()); + private static final Float16 RANDOM_CON_DIV = Float16.valueOf(genSmallRangeF.next()); + private static Float16 RANDOM1_VAR = RANDOM1; private static Float16 RANDOM2_VAR = RANDOM2; private static Float16 RANDOM3_VAR = RANDOM3; @@ -435,10 +444,10 @@ public class TestFloat16ScalarOperations { @Warmup(10000) public short testRandomFP16ConstantPatternSet1() { short res = 0; - res += Float.floatToFloat16(RANDOM1_VAR.floatValue() + RANDOM2.floatValue()); - res += Float.floatToFloat16(RANDOM2_VAR.floatValue() - RANDOM3.floatValue()); - res += Float.floatToFloat16(RANDOM3_VAR.floatValue() * RANDOM4.floatValue()); - res += Float.floatToFloat16(RANDOM4_VAR.floatValue() / RANDOM5.floatValue()); + res += Float.floatToFloat16(RANDOM1_VAR.floatValue() + RANDOM_CON_ADD.floatValue()); + res += Float.floatToFloat16(RANDOM2_VAR.floatValue() - RANDOM_CON_SUB.floatValue()); + res += Float.floatToFloat16(RANDOM3_VAR.floatValue() * RANDOM_CON_MUL.floatValue()); + res += Float.floatToFloat16(RANDOM4_VAR.floatValue() / RANDOM_CON_DIV.floatValue()); return res; } @@ -456,10 +465,10 @@ public class TestFloat16ScalarOperations { @Warmup(10000) public short testRandomFP16ConstantPatternSet2() { short res = 0; - res += Float.floatToFloat16(RANDOM2.floatValue() + RANDOM1_VAR.floatValue()); - res += Float.floatToFloat16(RANDOM3.floatValue() - RANDOM2_VAR.floatValue()); - res += Float.floatToFloat16(RANDOM4.floatValue() * RANDOM3_VAR.floatValue()); - res += Float.floatToFloat16(RANDOM5.floatValue() / RANDOM4_VAR.floatValue()); + res += Float.floatToFloat16(RANDOM_CON_ADD.floatValue() + RANDOM1_VAR.floatValue()); + res += Float.floatToFloat16(RANDOM_CON_SUB.floatValue() - RANDOM2_VAR.floatValue()); + res += Float.floatToFloat16(RANDOM_CON_MUL.floatValue() * RANDOM3_VAR.floatValue()); + res += Float.floatToFloat16(RANDOM_CON_DIV.floatValue() / RANDOM4_VAR.floatValue()); return res; } From 8c8d21db6f5bdc35f6eddf91065b4eec462a716f Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 9 Dec 2025 16:10:13 +0000 Subject: [PATCH 116/141] 8373295: Wrong log tag for UseCompressedOops ergo setting Reviewed-by: dholmes, ysuenaga --- src/hotspot/share/runtime/arguments.cpp | 8 +- .../appcds/sharedStrings/SysDictCrash.java | 84 ------------------- 2 files changed, 4 insertions(+), 88 deletions(-) delete mode 100644 test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SysDictCrash.java diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 4a983095593..dab3a60c650 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1604,10 +1604,10 @@ void Arguments::set_heap_size() { // and UseCompressedOops was not specified. if (reasonable_max > max_coop_heap) { if (FLAG_IS_ERGO(UseCompressedOops) && has_ram_limit) { - aot_log_info(aot)("UseCompressedOops disabled due to " - "max heap %zu > compressed oop heap %zu. " - "Please check the setting of MaxRAMPercentage %5.2f.", - reasonable_max, (size_t)max_coop_heap, MaxRAMPercentage); + log_debug(gc, heap, coops)("UseCompressedOops disabled due to " + "max heap %zu > compressed oop heap %zu. " + "Please check the setting of MaxRAMPercentage %5.2f.", + reasonable_max, (size_t)max_coop_heap, MaxRAMPercentage); FLAG_SET_ERGO(UseCompressedOops, false); } else { reasonable_max = max_coop_heap; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SysDictCrash.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SysDictCrash.java deleted file mode 100644 index 9462f4f9d0b..00000000000 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SysDictCrash.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/* - * @test - * @summary Regression test for JDK-8098821 - * @bug 8098821 - * @requires vm.cds.write.archived.java.heap - * @requires vm.gc == null - * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds - * @run driver SysDictCrash - */ - -import jdk.test.lib.cds.CDSOptions; -import jdk.test.lib.cds.CDSTestUtils; -import jdk.test.lib.process.OutputAnalyzer; - -public class SysDictCrash { - public static void main(String[] args) throws Exception { - SharedStringsUtils.run(args, SysDictCrash::test); - } - - public static void test(String[] args) throws Exception { - String vmOptionsPrefix[] = SharedStringsUtils.getChildVMOptionsPrefix(); - - // SharedBaseAddress=0 puts the archive at a very high address, which provokes the crash. - boolean continueTest = true; - - CDSOptions opts = (new CDSOptions()) - .addPrefix(vmOptionsPrefix, - "-XX:+UseG1GC", "-XX:MaxRAMPercentage=12.5", - "-cp", ".", - "-XX:SharedBaseAddress=0", - "-showversion", "-Xlog:cds,aot+hashtables") - .setArchiveName("./SysDictCrash.jsa"); - OutputAnalyzer output = CDSTestUtils.createArchive(opts); - try { - TestCommon.checkDump(output); - } catch (java.lang.RuntimeException re) { - if (!output.getStdout().contains("UseCompressedOops disabled due to")) { - throw re; - } else { - System.out.println("Shared archive was not created due to UseCompressedOops and UseCompressedClassPointers have been disabled."); - continueTest = false; - } - } - - if (!continueTest) { - return; - } - - opts = (new CDSOptions()) - .setArchiveName("./SysDictCrash.jsa") // prevents the assignment of a default archive name - .setUseVersion(false) // the -version must be the last arg for this test to work - .addSuffix(vmOptionsPrefix, - "-Xlog:cds", - "-XX:+UseG1GC", "-XX:MaxRAMPercentage=12.5", - "-XX:SharedArchiveFile=./SysDictCrash.jsa", - "-version"); - CDSTestUtils.run(opts) - .assertNormalExit(); - } -} From 831fe94c75c407b2399be9b89630d8d117c2996c Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Tue, 9 Dec 2025 17:01:08 +0000 Subject: [PATCH 117/141] 8373255: Unexpected iobj and ipdb files after JDK-8370438 Reviewed-by: serb --- make/common/native/Flags.gmk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/make/common/native/Flags.gmk b/make/common/native/Flags.gmk index efb4c08e74c..6353b490654 100644 --- a/make/common/native/Flags.gmk +++ b/make/common/native/Flags.gmk @@ -234,6 +234,9 @@ define SetupLinkerFlags ifeq ($(call isTargetOs, macosx), true) $1_EXTRA_LDFLAGS += -Wl,-object_path_lto,$$($1_OBJECT_DIR)/$$($1_NAME)_lto_helper.o endif + ifeq ($(TOOLCHAIN_TYPE), microsoft) + $1_EXTRA_LDFLAGS += -LTCGOUT:$$($1_OBJECT_DIR)/$$($1_NAME).iobj + endif endif $1_EXTRA_LDFLAGS += $$($1_LDFLAGS_$(OPENJDK_TARGET_OS_TYPE)) $$($1_LDFLAGS_$(OPENJDK_TARGET_OS)) \ From b99be505a5e3c8304be62a8b373d746fc52e8f0e Mon Sep 17 00:00:00 2001 From: Neha Joshi Date: Tue, 9 Dec 2025 18:06:39 +0000 Subject: [PATCH 118/141] 8368524: Tests are skipped and shown as passed in test/jdk/sun/security/pkcs11/Cipher/KeyWrap Reviewed-by: myankelevich, rhalade --- .../pkcs11/Cipher/KeyWrap/NISTWrapKAT.java | 18 ++++++++++-------- .../pkcs11/Cipher/KeyWrap/TestGeneral.java | 1 + 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java index e8f637e0b0c..b570a0dd030 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java +++ b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/NISTWrapKAT.java @@ -83,7 +83,7 @@ public class NISTWrapKAT extends PKCS11Test { private static String KEK2 = "5840DF6E29B02AF1AB493B705BF16EA1AE8338F4DCC176A8"; - private static final List skippedList = new ArrayList <>(); + private static final List skippedAlgoList = new ArrayList <>(); private static byte[] toBytes(String hex, int hexLen) { if (hexLen < hex.length()) { @@ -274,8 +274,8 @@ public class NISTWrapKAT extends PKCS11Test { dataLen + "-byte key with " + 8*keyLen + "-bit KEK"); int allowed = Cipher.getMaxAllowedKeyLength("AES"); if (keyLen > allowed) { - System.out.println("=> skip, exceeds max allowed size " + allowed); - skippedList.add(algo + " Cipher with wrapping " + + System.err.println("Skip, exceeds max allowed size " + allowed); + skippedAlgoList.add(algo + " Cipher with wrapping " + dataLen + "-byte key with " + 8 * keyLen + "-bit KEK exceeds max allowed size " + allowed); return; @@ -344,8 +344,8 @@ public class NISTWrapKAT extends PKCS11Test { dataLen + "-byte data with " + 8*keyLen + "-bit KEK"); int allowed = Cipher.getMaxAllowedKeyLength("AES"); if (keyLen > allowed) { - System.out.println("=> skip, exceeds max allowed size " + allowed); - skippedList.add(algo + " Cipher with enc " + + System.err.println("Skip, exceeds max allowed size " + allowed); + skippedAlgoList.add(algo + " Cipher with enc " + dataLen + "-byte data with " + 8 * keyLen + "-bit KEK exceeds max allowed size " + allowed); return; @@ -416,7 +416,9 @@ public class NISTWrapKAT extends PKCS11Test { for (Object[] td : testDatum) { String algo = (String) td[0]; if (p.getService("Cipher", algo) == null) { - skippedList.add("No support for " + algo); + System.err.println("Skip, due to no support: " + algo); + skippedAlgoList.add("No support for " + algo); + continue; } testKeyWrap(algo, (String) td[1], (int) td[2], (String) td[3], (int) td[4], (String) td[5], p); @@ -424,9 +426,9 @@ public class NISTWrapKAT extends PKCS11Test { (int) td[4], (String) td[5], p); } - if (!skippedList.isEmpty()) { + if (!skippedAlgoList.isEmpty()) { throw new SkippedException("One or more tests skipped " - + skippedList); + + skippedAlgoList); } else { System.out.println("All Tests Passed"); } diff --git a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java index f5e4494fc59..d7cdfc6c04c 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java +++ b/test/jdk/sun/security/pkcs11/Cipher/KeyWrap/TestGeneral.java @@ -273,6 +273,7 @@ public class TestGeneral extends PKCS11Test { for (String a : algos) { if (p.getService("Cipher", a) == null) { skippedList.add(a); + continue; } System.out.println("Testing " + a); From b2daf9de3097de4d3b3c7d565e29a48b4aae19ee Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 9 Dec 2025 18:21:12 +0000 Subject: [PATCH 119/141] 8355522: Remove the `java.locale.useOldISOCodes` system property Reviewed-by: jlu, joehw --- .../share/classes/java/util/Locale.java | 38 ++++------------ .../jdk/internal/util/StaticProperty.java | 9 ---- .../classes/sun/util/locale/BaseLocale.java | 24 +++++----- .../util/locale/provider/LocaleResources.java | 11 ----- test/jdk/java/util/Locale/LocaleTest.java | 45 ++++++------------- .../java/util/Locale/UseOldISOCodesTest.java | 15 +++---- 6 files changed, 38 insertions(+), 104 deletions(-) diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 54863d58782..f45a52c14fa 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -535,34 +535,13 @@ import sun.util.locale.provider.TimeZoneNameUtility; * *

      Legacy language codes

      * - *

      Locale's constructors have always converted three language codes to - * their earlier, obsoleted forms: {@code he} maps to {@code iw}, - * {@code yi} maps to {@code ji}, and {@code id} maps to - * {@code in}. Since Java SE 17, this is no longer the case. Each - * language maps to its new form; {@code iw} maps to {@code he}, {@code ji} - * maps to {@code yi}, and {@code in} maps to {@code id}. - * - *

      For backwards compatible behavior, the system property - * {@systemProperty java.locale.useOldISOCodes} reverts the behavior - * back to that of before Java SE 17. If the system property is set to - * {@code true}, those three current language codes are mapped to their - * backward compatible forms. The property is only read at Java runtime - * startup and subsequent calls to {@code System.setProperty()} will - * have no effect. As of Java SE 25, the use of the - * {@code java.locale.useOldISOCodes} system property is deprecated. - * This backwards compatible behavior will be removed in a future release - * of the JDK. - * - *

      The APIs added in Java SE 7 map between the old and new language codes, - * maintaining the mapped codes internal to Locale (so that - * {@code getLanguage} and {@code toString} reflect the mapped - * code, which depends on the {@code java.locale.useOldISOCodes} system - * property), but using the new codes in the BCP 47 language tag APIs (so - * that {@code toLanguageTag} reflects the new one). This - * preserves the equivalence between Locales no matter which code or - * API is used to construct them. Java's default resource bundle - * lookup mechanism also implements this mapping, so that resources - * can be named using either convention, see {@link ResourceBundle.Control}. + *

      For compatibility, a {@code Locale} created with one of the + * three obsolete language codes, {@code iw}, {@code ji}, or {@code in}, + * will map the language to its modern equivalent, {@code he}, {@code yi}, + * or {@code id}, respectively. + *

      The default resource bundle lookup mechanism also implements + * this mapping, so that resources can be named using either convention, + * see {@link ResourceBundle.Control}. * * @spec https://www.rfc-editor.org/info/rfc4647 * RFC 4647: Matching of Language Tags @@ -2527,8 +2506,7 @@ public final class Locale implements Cloneable, Serializable { private static String convertOldISOCodes(String language) { // we accept both the old and the new ISO codes for the languages whose ISO - // codes have changed, but we always store the NEW code, unless the property - // java.locale.useOldISOCodes is set to "true" + // codes have changed, but we always store the NEW code return BaseLocale.convertOldISOCodes(LocaleUtils.toLowerString(language).intern()); } diff --git a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java index 4fb3ae7a184..4740062dcde 100644 --- a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java +++ b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java @@ -53,7 +53,6 @@ public final class StaticProperty { private static final String STDOUT_ENCODING; private static final String SUN_JNU_ENCODING; private static final String JAVA_PROPERTIES_DATE; - private static final String JAVA_LOCALE_USE_OLD_ISO_CODES; private static final String OS_NAME; private static final String OS_ARCH; private static final String OS_VERSION; @@ -94,7 +93,6 @@ public final class StaticProperty { STDOUT_ENCODING = getProperty(props, "stdout.encoding"); SUN_JNU_ENCODING = getProperty(props, "sun.jnu.encoding"); JAVA_PROPERTIES_DATE = getProperty(props, "java.properties.date", null); - JAVA_LOCALE_USE_OLD_ISO_CODES = getProperty(props, "java.locale.useOldISOCodes", ""); OS_NAME = getProperty(props, "os.name"); OS_ARCH = getProperty(props, "os.arch"); OS_VERSION = getProperty(props, "os.version"); @@ -258,13 +256,6 @@ public final class StaticProperty { return JAVA_PROPERTIES_DATE; } - /** - * {@return the {@code java.locale.useOldISOCodes} system property} - */ - public static String javaLocaleUseOldISOCodes() { - return JAVA_LOCALE_USE_OLD_ISO_CODES; - } - /** * {@return the {@code os.name} system property} */ diff --git a/src/java.base/share/classes/sun/util/locale/BaseLocale.java b/src/java.base/share/classes/sun/util/locale/BaseLocale.java index 91efc61d1bf..58ec6d76aa5 100644 --- a/src/java.base/share/classes/sun/util/locale/BaseLocale.java +++ b/src/java.base/share/classes/sun/util/locale/BaseLocale.java @@ -34,7 +34,6 @@ package sun.util.locale; import jdk.internal.misc.CDS; import jdk.internal.util.ReferencedKeySet; -import jdk.internal.util.StaticProperty; import jdk.internal.vm.annotation.Stable; import java.util.StringJoiner; @@ -110,16 +109,14 @@ public final class BaseLocale { private @Stable int hash; /** - * Boolean for the old ISO language code compatibility. - * The system property "java.locale.useOldISOCodes" is not security sensitive, - * so no need to ensure privileged access here. + * Emit the warning message if the system property "java.locale.useOldISOCodes" is + * specified. */ - private static final boolean OLD_ISO_CODES = StaticProperty.javaLocaleUseOldISOCodes() - .equalsIgnoreCase("true"); static { - if (OLD_ISO_CODES) { - System.err.println("WARNING: The use of the system property \"java.locale.useOldISOCodes\"" + - " is deprecated. It will be removed in a future release of the JDK."); + if (System.getProperty("java.locale.useOldISOCodes") != null) { + System.err.println("WARNING: The system property" + + " \"java.locale.useOldISOCodes\" is no longer supported." + + " Any specified value will be ignored."); } } @@ -166,7 +163,8 @@ public final class BaseLocale { } } - // JDK uses deprecated ISO639.1 language codes for he, yi and id + // Normalize deprecated ISO 639-1 language codes for Hebrew, Yiddish, + // and Indonesian to their current standard forms. if (!language.isEmpty()) { language = convertOldISOCodes(language); } @@ -183,9 +181,9 @@ public final class BaseLocale { public static String convertOldISOCodes(String language) { return switch (language) { - case "he", "iw" -> OLD_ISO_CODES ? "iw" : "he"; - case "id", "in" -> OLD_ISO_CODES ? "in" : "id"; - case "yi", "ji" -> OLD_ISO_CODES ? "ji" : "yi"; + case "iw" -> "he"; + case "in" -> "id"; + case "ji" -> "yi"; default -> language; }; } diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index c539f57141e..ac43b22a3bd 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -62,7 +62,6 @@ import java.util.concurrent.ConcurrentMap; import java.util.regex.Pattern; import java.util.stream.Stream; -import jdk.internal.util.StaticProperty; import sun.util.resources.LocaleData; import sun.util.resources.OpenListResourceBundle; import sun.util.resources.TimeZoneNamesBundle; @@ -288,16 +287,6 @@ public class LocaleResources { } public String getLocaleName(String key) { - // Get names for old ISO codes with new ISO code resources - if (StaticProperty.javaLocaleUseOldISOCodes().equalsIgnoreCase("true")) { - key = switch (key) { - case "iw" -> "he"; - case "in" -> "id"; - case "ji" -> "yi"; - default -> key; - }; - } - Object localeName = null; String cacheKey = LOCALE_NAMES + key; diff --git a/test/jdk/java/util/Locale/LocaleTest.java b/test/jdk/java/util/Locale/LocaleTest.java index 0cf272f20a0..76fbb83c11a 100644 --- a/test/jdk/java/util/Locale/LocaleTest.java +++ b/test/jdk/java/util/Locale/LocaleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * 4118587 4118595 4122371 4126371 4126880 4135316 4135752 4139504 4139940 4143951 * 4147315 4147317 4147552 4335196 4778440 4940539 5010672 6475525 6544471 6627549 * 6786276 7066203 7085757 8008577 8030696 8170840 8174269 8255086 8263202 8287868 - * 8337603 + * 8337603 8355522 * @summary test Locales * @modules jdk.localedata * @run junit LocaleTest @@ -703,40 +703,21 @@ test commented out pending API-change approval @Test public void TestChangedISO639Codes() { Locale hebrewOld = Locale.of("iw", "IL"); - Locale hebrewNew = Locale.of("he", "IL"); Locale yiddishOld = Locale.of("ji", "IL"); - Locale yiddishNew = Locale.of("yi", "IL"); Locale indonesianOld = Locale.of("in"); - Locale indonesianNew = Locale.of("id"); - if ("true".equalsIgnoreCase(System.getProperty("java.locale.useOldISOCodes"))) { - if (!hebrewNew.getLanguage().equals("iw")) { - fail("Got back wrong language code for new Hebrew: expected \"iw\", got \"" - + hebrewNew.getLanguage() + "\""); - } - if (!yiddishNew.getLanguage().equals("ji")) { - fail("Got back wrong language code for new Yiddish: expected \"ji\", got \"" - + yiddishNew.getLanguage() + "\""); - } - if (!indonesianNew.getLanguage().equals("in")) { - fail("Got back wrong language code for new Indonesian: expected \"in\", got \"" - + indonesianNew.getLanguage() + "\""); - } - } else { - if (!hebrewOld.getLanguage().equals("he")) { - fail("Got back wrong language code for old Hebrew: expected \"he\", got \"" - + hebrewNew.getLanguage() + "\""); - } - if (!yiddishOld.getLanguage().equals("yi")) { - fail("Got back wrong language code for old Yiddish: expected \"yi\", got \"" - + yiddishNew.getLanguage() + "\""); - } - if (!indonesianOld.getLanguage().equals("id")) { - fail("Got back wrong language code for old Indonesian: expected \"id\", got \"" - + indonesianNew.getLanguage() + "\""); - } + if (!hebrewOld.getLanguage().equals("he")) { + fail("Got back wrong language code for old Hebrew: expected \"he\", got \"" + + hebrewOld.getLanguage() + "\""); + } + if (!yiddishOld.getLanguage().equals("yi")) { + fail("Got back wrong language code for old Yiddish: expected \"yi\", got \"" + + yiddishOld.getLanguage() + "\""); + } + if (!indonesianOld.getLanguage().equals("id")) { + fail("Got back wrong language code for old Indonesian: expected \"id\", got \"" + + indonesianOld.getLanguage() + "\""); } - } /** diff --git a/test/jdk/java/util/Locale/UseOldISOCodesTest.java b/test/jdk/java/util/Locale/UseOldISOCodesTest.java index 1909497535c..3e836782fc3 100644 --- a/test/jdk/java/util/Locale/UseOldISOCodesTest.java +++ b/test/jdk/java/util/Locale/UseOldISOCodesTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8295232 8353118 + * @bug 8295232 8353118 8355522 * @summary Tests for the "java.locale.useOldISOCodes" system property * @library /test/lib * @run junit UseOldISOCodesTest @@ -34,7 +34,7 @@ import jdk.test.lib.process.ProcessTools; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; public class UseOldISOCodesTest { @@ -44,7 +44,7 @@ public class UseOldISOCodesTest { .outputTo(System.out) .errorTo(System.err); oa.shouldHaveExitValue(0); - oa.stderrShouldMatch("WARNING: The use of the system property \"java.locale.useOldISOCodes\" is deprecated. It will be removed in a future release of the JDK."); + oa.stderrShouldMatch("WARNING: The system property \"java.locale.useOldISOCodes\" is no longer supported. Any specified value will be ignored."); } static class Runner { @@ -52,12 +52,9 @@ public class UseOldISOCodesTest { private static final String newCode = "he"; public static void main(String[] args) { - // Ensure java.locale.useOldISOCodes is only interpreted at runtime startup - // Should have no effect - System.setProperty("java.locale.useOldISOCodes", "false"); - Locale locale = Locale.of(newCode); - assertEquals(obsoleteCode, locale.getLanguage(), - "newCode 'he' was not mapped to 'iw' with useOldISOCodes=true"); + // Ensure java.locale.useOldISOCodes should have no effect + assertNotEquals(obsoleteCode, Locale.of(newCode).getLanguage(), + "newCode 'he' was mapped to 'iw' with useOldISOCodes=true"); } } } From 1ae4a6c43ea21d4b147bcfcfaf1484c6e618dce5 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Tue, 9 Dec 2025 18:48:33 +0000 Subject: [PATCH 120/141] 8373101: JdkClient and JdkServer test classes ignore namedGroups field Reviewed-by: rhalade --- .../javax/net/ssl/TLSCommon/interop/JdkClient.java | 13 ++++++++++++- .../javax/net/ssl/TLSCommon/interop/JdkServer.java | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkClient.java b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkClient.java index 79476cbb81e..eb6ecbb12b8 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkClient.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkClient.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 @@ -25,6 +25,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.net.ssl.SNIHostName; @@ -86,6 +87,16 @@ public class JdkClient extends AbstractClient { if (builder.getAppProtocols() != null) { sslParams.setApplicationProtocols(builder.getAppProtocols()); } + + NamedGroup[] namedGroups = builder.getNamedGroups(); + if (namedGroups != null + && namedGroups.length > 0) { + String[] namedGroupStrs = Arrays.stream(namedGroups) + .map(NamedGroup::name) + .toArray(String[]::new); + sslParams.setNamedGroups(namedGroupStrs); + } + socket.setSSLParameters(sslParams); } diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java index 1521325b65a..20bfffbac7d 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,9 @@ */ import java.io.IOException; -import java.net.InetAddress; import java.net.SocketException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.net.ssl.SNIHostName; @@ -85,6 +85,16 @@ public class JdkServer extends AbstractServer { System.out.println("appProtocol: " + appProtocol); } } + + NamedGroup[] namedGroups = builder.getNamedGroups(); + if (namedGroups != null + && namedGroups.length > 0) { + String[] namedGroupStrs = Arrays.stream(namedGroups) + .map(NamedGroup::name) + .toArray(String[]::new); + sslParams.setNamedGroups(namedGroupStrs); + } + serverSocket.setSSLParameters(sslParams); } From 7f9951a93479ac0ddd74375fdef92095fb65741b Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 10 Dec 2025 00:07:28 +0000 Subject: [PATCH 121/141] 8373207: Make DeferredStatic class template constant initializable Reviewed-by: jsjolen, stefank, iwalulya --- src/hotspot/share/utilities/deferredStatic.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/utilities/deferredStatic.hpp b/src/hotspot/share/utilities/deferredStatic.hpp index 3a32f920fe8..a37b169803a 100644 --- a/src/hotspot/share/utilities/deferredStatic.hpp +++ b/src/hotspot/share/utilities/deferredStatic.hpp @@ -35,7 +35,7 @@ // object must be explicitly initialized before use. This avoids problems // resulting from the unspecified initialization time and ordering between // different objects that comes from using undeferred objects (the so-called -// "Static Initialization Order Fiasco). +// "Static Initialization Order Fiasco"). // // Once initialized, the object is never destroyed. This avoids similar issues // with the timing and ordering of destruction on normal program exit. @@ -53,7 +53,7 @@ class DeferredStatic { public: NONCOPYABLE(DeferredStatic); - DeferredStatic() + constexpr DeferredStatic() DEBUG_ONLY(: _initialized(false)) { // Do not construct value, on purpose. } From eef9813ad42b02db5fc636e661a751d5120a639e Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Wed, 10 Dec 2025 00:50:48 +0000 Subject: [PATCH 122/141] 8371446: VectorAPI: Add unit tests for masks from various long values Reviewed-by: psandoz --- .../incubator/vector/AbstractVectorTest.java | 53 +-- .../incubator/vector/Byte128VectorTests.java | 340 +++++++++++------- .../incubator/vector/Byte256VectorTests.java | 340 +++++++++++------- .../incubator/vector/Byte512VectorTests.java | 340 +++++++++++------- .../incubator/vector/Byte64VectorTests.java | 340 +++++++++++------- .../incubator/vector/ByteMaxVectorTests.java | 324 +++++++++++------ .../vector/Double128VectorTests.java | 336 ++++++++++------- .../vector/Double256VectorTests.java | 336 ++++++++++------- .../vector/Double512VectorTests.java | 336 ++++++++++------- .../incubator/vector/Double64VectorTests.java | 336 ++++++++++------- .../vector/DoubleMaxVectorTests.java | 320 +++++++++++------ .../incubator/vector/Float128VectorTests.java | 336 ++++++++++------- .../incubator/vector/Float256VectorTests.java | 336 ++++++++++------- .../incubator/vector/Float512VectorTests.java | 336 ++++++++++------- .../incubator/vector/Float64VectorTests.java | 336 ++++++++++------- .../incubator/vector/FloatMaxVectorTests.java | 320 +++++++++++------ .../incubator/vector/Int128VectorTests.java | 340 +++++++++++------- .../incubator/vector/Int256VectorTests.java | 340 +++++++++++------- .../incubator/vector/Int512VectorTests.java | 340 +++++++++++------- .../incubator/vector/Int64VectorTests.java | 340 +++++++++++------- .../incubator/vector/IntMaxVectorTests.java | 324 +++++++++++------ .../incubator/vector/Long128VectorTests.java | 340 +++++++++++------- .../incubator/vector/Long256VectorTests.java | 340 +++++++++++------- .../incubator/vector/Long512VectorTests.java | 340 +++++++++++------- .../incubator/vector/Long64VectorTests.java | 340 +++++++++++------- .../incubator/vector/LongMaxVectorTests.java | 324 +++++++++++------ .../incubator/vector/Short128VectorTests.java | 340 +++++++++++------- .../incubator/vector/Short256VectorTests.java | 340 +++++++++++------- .../incubator/vector/Short512VectorTests.java | 340 +++++++++++------- .../incubator/vector/Short64VectorTests.java | 340 +++++++++++------- .../incubator/vector/ShortMaxVectorTests.java | 324 +++++++++++------ test/jdk/jdk/incubator/vector/gen-template.sh | 15 +- .../templates/Kernel-BoolBinary-op.template | 11 + .../templates/Kernel-BoolUnary-op.template | 9 + .../templates/Unit-BoolBinary-op.template | 10 + .../templates/Unit-BoolUnary-op.template | 10 + .../templates/Unit-Mask-FromToLong.template | 27 ++ .../templates/Unit-Miscellaneous.template | 132 +------ .../vector/templates/Unit-header.template | 49 ++- 39 files changed, 6447 insertions(+), 3933 deletions(-) create mode 100644 test/jdk/jdk/incubator/vector/templates/Kernel-BoolBinary-op.template create mode 100644 test/jdk/jdk/incubator/vector/templates/Kernel-BoolUnary-op.template create mode 100644 test/jdk/jdk/incubator/vector/templates/Unit-BoolBinary-op.template create mode 100644 test/jdk/jdk/incubator/vector/templates/Unit-BoolUnary-op.template create mode 100644 test/jdk/jdk/incubator/vector/templates/Unit-Mask-FromToLong.template diff --git a/test/jdk/jdk/incubator/vector/AbstractVectorTest.java b/test/jdk/jdk/incubator/vector/AbstractVectorTest.java index 71cabe75b76..b334e64ab80 100644 --- a/test/jdk/jdk/incubator/vector/AbstractVectorTest.java +++ b/test/jdk/jdk/incubator/vector/AbstractVectorTest.java @@ -110,19 +110,19 @@ public class AbstractVectorTest { } static final List> BOOLEAN_MASK_GENERATORS = List.of( - withToString("mask[i % 2]", (int l) -> { - boolean[] a = new boolean[l]; - for (int i = 0; i < l; i++) { - a[i] = (i % 2 == 0); - } - return a; + withToString("mask[i % 2]", (int s) -> { + return fill_boolean(s, + i -> ((i % 2) == 0)); }), - withToString("mask[true]", (int l) -> { - boolean[] a = new boolean[l]; + withToString("mask[true]", (int s) -> { + boolean[] a = new boolean[s]; Arrays.fill(a, true); return a; }), - withToString("mask[false]", boolean[]::new) + withToString("mask[false]", boolean[]::new), + withToString("mask[random]", (int s) -> { + return fill_boolean(s,_i -> RAND.nextBoolean()); + }) ); static final List>> @@ -131,6 +131,26 @@ public class AbstractVectorTest { flatMap(fa -> BOOLEAN_MASK_GENERATORS.stream().skip(1).map( fb -> List.of(fa, fb))).collect(Collectors.toList()); + static long[] pack_booleans_to_longs(boolean[] mask) { + int totalLongs = (mask.length + 63) / 64; // ceil division + long[] packed = new long[totalLongs]; + for (int i = 0; i < mask.length; i++) { + int longIndex = i / 64; + int bitIndex = i % 64; + if (mask[i]) { + packed[longIndex] |= 1L << bitIndex; + } + } + return packed; + } + + static final List> LONG_MASK_GENERATORS = BOOLEAN_MASK_GENERATORS.stream() + .map(f -> withToString( + f.toString().replace("mask", "long_mask"), + (IntFunction) (int l) -> pack_booleans_to_longs(f.apply(l)) + )) + .collect(Collectors.toList()); + static final List> INT_SHUFFLE_GENERATORS = List.of( withToStringBi("shuffle[random]", (Integer l, Integer m) -> RAND.ints(l, 0, m).toArray()) @@ -210,21 +230,6 @@ public class AbstractVectorTest { return a; } - interface FBooleanBinOp { - boolean apply(boolean a, boolean b); - } - - static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBooleanBinOp f) { - int i = 0; - try { - for (; i < a.length; i++) { - Assert.assertEquals(r[i], f.apply(a[i], b[i])); - } - } catch (AssertionError e) { - Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); - } - } - // Non-optimized test partial wrap derived from the Spec: // Validation function for lane indexes which may be out of the valid range of [0..VLENGTH-1]. // The index is forced into this range by adding or subtracting a suitable multiple of VLENGTH. diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index bea4d541987..4980c66c02a 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java @@ -393,6 +393,36 @@ public class Byte128VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { byte apply(byte a, byte b); } @@ -1095,12 +1125,6 @@ public class Byte128VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -1232,8 +1256,23 @@ public class Byte128VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4464,7 +4503,7 @@ public class Byte128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueByte128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4488,7 +4527,7 @@ public class Byte128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueByte128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6390,6 +6429,157 @@ public class Byte128VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Byte128VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandByte128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorByte128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorByte128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotByte128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqByte128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotByte128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Byte128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongByte128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "byteCompareOpProvider") static void ltByte128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -6700,115 +6890,22 @@ public class Byte128VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsByte128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqByte128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeByte128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6913,23 +7010,6 @@ public class Byte128VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongByte128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index be5b3cf6198..b3cad54e101 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java @@ -393,6 +393,36 @@ public class Byte256VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { byte apply(byte a, byte b); } @@ -1095,12 +1125,6 @@ public class Byte256VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -1232,8 +1256,23 @@ public class Byte256VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4464,7 +4503,7 @@ public class Byte256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueByte256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4488,7 +4527,7 @@ public class Byte256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueByte256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6390,6 +6429,157 @@ public class Byte256VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Byte256VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandByte256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorByte256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorByte256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotByte256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqByte256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotByte256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Byte256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongByte256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "byteCompareOpProvider") static void ltByte256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -6700,115 +6890,22 @@ public class Byte256VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsByte256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqByte256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeByte256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6913,23 +7010,6 @@ public class Byte256VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongByte256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index 0fd68b6f712..83e48cd2fdc 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java @@ -393,6 +393,36 @@ public class Byte512VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { byte apply(byte a, byte b); } @@ -1095,12 +1125,6 @@ public class Byte512VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -1232,8 +1256,23 @@ public class Byte512VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4464,7 +4503,7 @@ public class Byte512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueByte512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4488,7 +4527,7 @@ public class Byte512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueByte512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6390,6 +6429,157 @@ public class Byte512VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Byte512VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandByte512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorByte512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorByte512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotByte512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqByte512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotByte512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Byte512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongByte512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "byteCompareOpProvider") static void ltByte512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -6700,115 +6890,22 @@ public class Byte512VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsByte512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqByte512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeByte512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6913,23 +7010,6 @@ public class Byte512VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongByte512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index 112b2e56b6f..0088b3fbf8e 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java @@ -393,6 +393,36 @@ public class Byte64VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { byte apply(byte a, byte b); } @@ -1095,12 +1125,6 @@ public class Byte64VectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -1232,8 +1256,23 @@ public class Byte64VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4464,7 +4503,7 @@ public class Byte64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueByte64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4488,7 +4527,7 @@ public class Byte64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueByte64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6390,6 +6429,157 @@ public class Byte64VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Byte64VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandByte64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorByte64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorByte64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotByte64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqByte64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Byte64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotByte64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Byte64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongByte64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "byteCompareOpProvider") static void ltByte64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -6700,115 +6890,22 @@ public class Byte64VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsByte64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqByte64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Byte64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeByte64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6913,23 +7010,6 @@ public class Byte64VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongByte64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index 435cacc013e..6df01fb48e3 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java @@ -398,6 +398,36 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { byte apply(byte a, byte b); } @@ -1100,12 +1130,6 @@ public class ByteMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> BYTE_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> BYTE_GENERATOR_TRIPLES = BYTE_GENERATOR_PAIRS.stream(). @@ -1237,8 +1261,23 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4469,7 +4508,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueByteMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4493,7 +4532,7 @@ public class ByteMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueByteMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6395,6 +6434,157 @@ public class ByteMaxVectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, ByteMaxVectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandByteMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorByteMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorByteMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotByteMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqByteMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ByteMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotByteMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, ByteMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongByteMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "byteCompareOpProvider") static void ltByteMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { byte[] a = fa.apply(SPECIES.length()); @@ -6705,115 +6895,22 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsByteMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ByteMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ByteMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ByteMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ByteMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqByteMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ByteMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeByteMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6918,7 +7015,6 @@ public class ByteMaxVectorTests extends AbstractVectorTest { } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index f15ce88ddb8..879dac4c966 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { double apply(double a, double b); } @@ -1187,12 +1217,6 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). @@ -1291,8 +1315,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4806,6 +4845,157 @@ relativeError)); assertArraysEquals(r, a, mask, Double128VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandDouble128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorDouble128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorDouble128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotDouble128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqDouble128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotDouble128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Double128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongDouble128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "doubleCompareOpProvider") static void ltDouble128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); @@ -5095,115 +5285,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsDouble128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqDouble128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeDouble128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5308,23 +5405,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongDouble128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index e6c3662e0ad..87230330642 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { double apply(double a, double b); } @@ -1187,12 +1217,6 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). @@ -1291,8 +1315,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4806,6 +4845,157 @@ relativeError)); assertArraysEquals(r, a, mask, Double256VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandDouble256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorDouble256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorDouble256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotDouble256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqDouble256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotDouble256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Double256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongDouble256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "doubleCompareOpProvider") static void ltDouble256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); @@ -5095,115 +5285,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsDouble256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqDouble256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeDouble256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5308,23 +5405,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongDouble256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index 7c37c9878e8..af8fbf5f51f 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { double apply(double a, double b); } @@ -1187,12 +1217,6 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). @@ -1291,8 +1315,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4806,6 +4845,157 @@ relativeError)); assertArraysEquals(r, a, mask, Double512VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandDouble512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorDouble512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorDouble512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotDouble512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqDouble512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotDouble512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Double512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongDouble512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "doubleCompareOpProvider") static void ltDouble512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); @@ -5095,115 +5285,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsDouble512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqDouble512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeDouble512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5308,23 +5405,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongDouble512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 85b96288b37..67822ae5353 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { double apply(double a, double b); } @@ -1187,12 +1217,6 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). @@ -1291,8 +1315,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4806,6 +4845,157 @@ relativeError)); assertArraysEquals(r, a, mask, Double64VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandDouble64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorDouble64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorDouble64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotDouble64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqDouble64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Double64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotDouble64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Double64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongDouble64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "doubleCompareOpProvider") static void ltDouble64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); @@ -5095,115 +5285,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsDouble64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqDouble64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Double64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeDouble64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5308,23 +5405,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongDouble64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index 7245990d66c..5d7ae07c55a 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -416,6 +416,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { double apply(double a, double b); } @@ -1192,12 +1222,6 @@ relativeError)); flatMap(fa -> DOUBLE_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> DOUBLE_GENERATOR_TRIPLES = DOUBLE_GENERATOR_PAIRS.stream(). @@ -1296,8 +1320,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4811,6 +4850,157 @@ relativeError)); assertArraysEquals(r, a, mask, DoubleMaxVectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, DoubleMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, DoubleMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, DoubleMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, DoubleMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, DoubleMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotDoubleMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, DoubleMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongDoubleMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "doubleCompareOpProvider") static void ltDoubleMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { double[] a = fa.apply(SPECIES.length()); @@ -5100,115 +5290,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsDoubleMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, DoubleMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, DoubleMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, DoubleMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, DoubleMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqDoubleMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, DoubleMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeDoubleMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5313,7 +5410,6 @@ relativeError)); } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index c4f4ed1b966..0d3ce311a90 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { float apply(float a, float b); } @@ -1198,12 +1228,6 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). @@ -1302,8 +1326,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4775,6 +4814,157 @@ relativeError)); assertArraysEquals(r, a, mask, Float128VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandFloat128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorFloat128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorFloat128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotFloat128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqFloat128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotFloat128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Float128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongFloat128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "floatCompareOpProvider") static void ltFloat128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); @@ -5074,115 +5264,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsFloat128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqFloat128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeFloat128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5287,23 +5384,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongFloat128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 87cbc165d59..88ea856f17b 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { float apply(float a, float b); } @@ -1198,12 +1228,6 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). @@ -1302,8 +1326,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4775,6 +4814,157 @@ relativeError)); assertArraysEquals(r, a, mask, Float256VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandFloat256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorFloat256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorFloat256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotFloat256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqFloat256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotFloat256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Float256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongFloat256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "floatCompareOpProvider") static void ltFloat256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); @@ -5074,115 +5264,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsFloat256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqFloat256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeFloat256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5287,23 +5384,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongFloat256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index beb9561d882..cdccbfdd319 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { float apply(float a, float b); } @@ -1198,12 +1228,6 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). @@ -1302,8 +1326,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4775,6 +4814,157 @@ relativeError)); assertArraysEquals(r, a, mask, Float512VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandFloat512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorFloat512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorFloat512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotFloat512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqFloat512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotFloat512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Float512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongFloat512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "floatCompareOpProvider") static void ltFloat512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); @@ -5074,115 +5264,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsFloat512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqFloat512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeFloat512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5287,23 +5384,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongFloat512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index ee630abd8e0..056eae1974f 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -411,6 +411,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { float apply(float a, float b); } @@ -1198,12 +1228,6 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). @@ -1302,8 +1326,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4775,6 +4814,157 @@ relativeError)); assertArraysEquals(r, a, mask, Float64VectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandFloat64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorFloat64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorFloat64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotFloat64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqFloat64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Float64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotFloat64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Float64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongFloat64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "floatCompareOpProvider") static void ltFloat64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); @@ -5074,115 +5264,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsFloat64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqFloat64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Float64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeFloat64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5287,23 +5384,6 @@ relativeError)); } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongFloat64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 41e4d6e4a5d..19bd385ca1f 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -416,6 +416,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { float apply(float a, float b); } @@ -1203,12 +1233,6 @@ relativeError)); flatMap(fa -> FLOAT_GENERATORS.stream().skip(1).map(fb -> List.of(fa, fb))). collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> FLOAT_GENERATOR_TRIPLES = FLOAT_GENERATOR_PAIRS.stream(). @@ -1307,8 +1331,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4780,6 +4819,157 @@ relativeError)); assertArraysEquals(r, a, mask, FloatMaxVectorTests::SQRT); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandFloatMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, FloatMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorFloatMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, FloatMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorFloatMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, FloatMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotFloatMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, FloatMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqFloatMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, FloatMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotFloatMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, FloatMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongFloatMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "floatCompareOpProvider") static void ltFloatMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { float[] a = fa.apply(SPECIES.length()); @@ -5079,115 +5269,22 @@ relativeError)); } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsFloatMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, FloatMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, FloatMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, FloatMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, FloatMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqFloatMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, FloatMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeFloatMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -5292,7 +5389,6 @@ relativeError)); } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index d6bca96ea6e..1bf3203790c 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.java @@ -393,6 +393,36 @@ public class Int128VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { int apply(int a, int b); } @@ -1085,12 +1115,6 @@ public class Int128VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Int128VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4508,7 +4547,7 @@ public class Int128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueInt128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4532,7 +4571,7 @@ public class Int128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueInt128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6434,6 +6473,157 @@ public class Int128VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Int128VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandInt128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorInt128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorInt128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotInt128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqInt128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotInt128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Int128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongInt128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "intCompareOpProvider") static void ltInt128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -6733,115 +6923,22 @@ public class Int128VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsInt128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqInt128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeInt128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6946,23 +7043,6 @@ public class Int128VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongInt128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index ac98217b714..5973fec7e57 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.java @@ -393,6 +393,36 @@ public class Int256VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { int apply(int a, int b); } @@ -1085,12 +1115,6 @@ public class Int256VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Int256VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4508,7 +4547,7 @@ public class Int256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueInt256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4532,7 +4571,7 @@ public class Int256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueInt256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6434,6 +6473,157 @@ public class Int256VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Int256VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandInt256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorInt256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorInt256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotInt256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqInt256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotInt256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Int256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongInt256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "intCompareOpProvider") static void ltInt256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -6733,115 +6923,22 @@ public class Int256VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsInt256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqInt256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeInt256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6946,23 +7043,6 @@ public class Int256VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongInt256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index b56236db322..a1e969fc852 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.java @@ -393,6 +393,36 @@ public class Int512VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { int apply(int a, int b); } @@ -1085,12 +1115,6 @@ public class Int512VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Int512VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4508,7 +4547,7 @@ public class Int512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueInt512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4532,7 +4571,7 @@ public class Int512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueInt512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6434,6 +6473,157 @@ public class Int512VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Int512VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandInt512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorInt512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorInt512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotInt512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqInt512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotInt512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Int512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongInt512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "intCompareOpProvider") static void ltInt512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -6733,115 +6923,22 @@ public class Int512VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsInt512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqInt512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeInt512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6946,23 +7043,6 @@ public class Int512VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongInt512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index f87a0eb458c..15b3b68820e 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.java @@ -393,6 +393,36 @@ public class Int64VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { int apply(int a, int b); } @@ -1085,12 +1115,6 @@ public class Int64VectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Int64VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4508,7 +4547,7 @@ public class Int64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueInt64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4532,7 +4571,7 @@ public class Int64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueInt64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6434,6 +6473,157 @@ public class Int64VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Int64VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandInt64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorInt64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorInt64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotInt64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqInt64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Int64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotInt64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Int64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongInt64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "intCompareOpProvider") static void ltInt64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -6733,115 +6923,22 @@ public class Int64VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsInt64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqInt64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Int64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeInt64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6946,23 +7043,6 @@ public class Int64VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongInt64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index c61aab0013e..67368e0f70e 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java @@ -398,6 +398,36 @@ public class IntMaxVectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { int apply(int a, int b); } @@ -1090,12 +1120,6 @@ public class IntMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> INT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> INT_GENERATOR_TRIPLES = INT_GENERATOR_PAIRS.stream(). @@ -1227,8 +1251,23 @@ public class IntMaxVectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4513,7 +4552,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueIntMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4537,7 +4576,7 @@ public class IntMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueIntMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6439,6 +6478,157 @@ public class IntMaxVectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, IntMaxVectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandIntMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorIntMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorIntMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotIntMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqIntMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, IntMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotIntMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, IntMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongIntMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "intCompareOpProvider") static void ltIntMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { int[] a = fa.apply(SPECIES.length()); @@ -6738,115 +6928,22 @@ public class IntMaxVectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsIntMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, IntMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, IntMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, IntMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, IntMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqIntMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, IntMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeIntMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6951,7 +7048,6 @@ public class IntMaxVectorTests extends AbstractVectorTest { } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index a8cf38c003a..6f91fb9ffbf 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.java @@ -350,6 +350,36 @@ public class Long128VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { long apply(long a, long b); } @@ -1075,12 +1105,6 @@ public class Long128VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -1219,8 +1243,23 @@ public class Long128VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4530,7 +4569,7 @@ public class Long128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueLong128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4554,7 +4593,7 @@ public class Long128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueLong128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6386,6 +6425,157 @@ public class Long128VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Long128VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandLong128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorLong128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorLong128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotLong128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqLong128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotLong128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Long128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongLong128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "longCompareOpProvider") static void ltLong128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -6619,115 +6809,22 @@ public class Long128VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsLong128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqLong128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeLong128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6832,23 +6929,6 @@ public class Long128VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongLong128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index a394a59699f..118c955ad24 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.java @@ -350,6 +350,36 @@ public class Long256VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { long apply(long a, long b); } @@ -1075,12 +1105,6 @@ public class Long256VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -1219,8 +1243,23 @@ public class Long256VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4530,7 +4569,7 @@ public class Long256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueLong256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4554,7 +4593,7 @@ public class Long256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueLong256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6386,6 +6425,157 @@ public class Long256VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Long256VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandLong256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorLong256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorLong256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotLong256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqLong256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotLong256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Long256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongLong256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "longCompareOpProvider") static void ltLong256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -6619,115 +6809,22 @@ public class Long256VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsLong256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqLong256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeLong256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6832,23 +6929,6 @@ public class Long256VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongLong256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 2f12ea98399..1bca0ef0ebd 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.java @@ -350,6 +350,36 @@ public class Long512VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { long apply(long a, long b); } @@ -1075,12 +1105,6 @@ public class Long512VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -1219,8 +1243,23 @@ public class Long512VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4530,7 +4569,7 @@ public class Long512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueLong512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4554,7 +4593,7 @@ public class Long512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueLong512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6386,6 +6425,157 @@ public class Long512VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Long512VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandLong512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorLong512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorLong512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotLong512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqLong512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotLong512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Long512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongLong512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "longCompareOpProvider") static void ltLong512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -6619,115 +6809,22 @@ public class Long512VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsLong512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqLong512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeLong512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6832,23 +6929,6 @@ public class Long512VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongLong512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index 0fda0abed58..212bbb5047c 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.java @@ -350,6 +350,36 @@ public class Long64VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { long apply(long a, long b); } @@ -1075,12 +1105,6 @@ public class Long64VectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -1219,8 +1243,23 @@ public class Long64VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4530,7 +4569,7 @@ public class Long64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueLong64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4554,7 +4593,7 @@ public class Long64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueLong64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6386,6 +6425,157 @@ public class Long64VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Long64VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandLong64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorLong64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorLong64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotLong64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqLong64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Long64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotLong64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Long64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongLong64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "longCompareOpProvider") static void ltLong64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -6619,115 +6809,22 @@ public class Long64VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsLong64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqLong64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Long64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeLong64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6832,23 +6929,6 @@ public class Long64VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongLong64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index 7aa2bc4c510..3eba905e4f8 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java @@ -355,6 +355,36 @@ public class LongMaxVectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { long apply(long a, long b); } @@ -1080,12 +1110,6 @@ public class LongMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> LONG_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> LONG_GENERATOR_TRIPLES = LONG_GENERATOR_PAIRS.stream(). @@ -1224,8 +1248,23 @@ public class LongMaxVectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4535,7 +4574,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueLongMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4559,7 +4598,7 @@ public class LongMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueLongMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6391,6 +6430,157 @@ public class LongMaxVectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, LongMaxVectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandLongMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorLongMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorLongMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotLongMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqLongMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, LongMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotLongMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, LongMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongLongMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "longCompareOpProvider") static void ltLongMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { long[] a = fa.apply(SPECIES.length()); @@ -6624,115 +6814,22 @@ public class LongMaxVectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsLongMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, LongMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, LongMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, LongMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, LongMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqLongMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, LongMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeLongMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6837,7 +6934,6 @@ public class LongMaxVectorTests extends AbstractVectorTest { } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index 5f4c54bb708..50be26b163a 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.java @@ -393,6 +393,36 @@ public class Short128VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { short apply(short a, short b); } @@ -1085,12 +1115,6 @@ public class Short128VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Short128VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4455,7 +4494,7 @@ public class Short128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueShort128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4479,7 +4518,7 @@ public class Short128VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueShort128VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6381,6 +6420,157 @@ public class Short128VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Short128VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandShort128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorShort128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorShort128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotShort128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqShort128VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short128VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotShort128VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Short128VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongShort128VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "shortCompareOpProvider") static void ltShort128VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -6680,115 +6870,22 @@ public class Short128VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsShort128VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short128VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short128VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short128VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short128VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqShort128VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short128VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeShort128VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6893,23 +6990,6 @@ public class Short128VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongShort128VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index 88986575f60..5f63164755b 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.java @@ -393,6 +393,36 @@ public class Short256VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { short apply(short a, short b); } @@ -1085,12 +1115,6 @@ public class Short256VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Short256VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4455,7 +4494,7 @@ public class Short256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueShort256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4479,7 +4518,7 @@ public class Short256VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueShort256VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6381,6 +6420,157 @@ public class Short256VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Short256VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandShort256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorShort256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorShort256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotShort256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqShort256VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short256VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotShort256VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Short256VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongShort256VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "shortCompareOpProvider") static void ltShort256VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -6680,115 +6870,22 @@ public class Short256VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsShort256VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short256VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short256VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short256VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short256VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqShort256VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short256VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeShort256VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6893,23 +6990,6 @@ public class Short256VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongShort256VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index 0f474375a47..5044f8db482 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.java @@ -393,6 +393,36 @@ public class Short512VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { short apply(short a, short b); } @@ -1085,12 +1115,6 @@ public class Short512VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Short512VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4455,7 +4494,7 @@ public class Short512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueShort512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4479,7 +4518,7 @@ public class Short512VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueShort512VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6381,6 +6420,157 @@ public class Short512VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Short512VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandShort512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorShort512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorShort512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotShort512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqShort512VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short512VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotShort512VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Short512VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongShort512VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "shortCompareOpProvider") static void ltShort512VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -6680,115 +6870,22 @@ public class Short512VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsShort512VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short512VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short512VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short512VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short512VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqShort512VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short512VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeShort512VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6893,23 +6990,6 @@ public class Short512VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongShort512VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index 4b99ed6d84c..bc12c3f0938 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.java @@ -393,6 +393,36 @@ public class Short64VectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { short apply(short a, short b); } @@ -1085,12 +1115,6 @@ public class Short64VectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -1222,8 +1246,23 @@ public class Short64VectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4455,7 +4494,7 @@ public class Short64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueShort64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4479,7 +4518,7 @@ public class Short64VectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueShort64VectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6381,6 +6420,157 @@ public class Short64VectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, Short64VectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandShort64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorShort64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorShort64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotShort64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqShort64VectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, Short64VectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotShort64VectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, Short64VectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongShort64VectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "shortCompareOpProvider") static void ltShort64VectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -6680,115 +6870,22 @@ public class Short64VectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsShort64VectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short64VectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short64VectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short64VectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short64VectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqShort64VectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, Short64VectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeShort64VectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6893,23 +6990,6 @@ public class Short64VectorTests extends AbstractVectorTest { } } - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLongShort64VectorTestsSmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index 2bb3b9c1557..ec2df02b171 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java @@ -398,6 +398,36 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { short apply(short a, short b); } @@ -1090,12 +1120,6 @@ public class ShortMaxVectorTests extends AbstractVectorTest { .flatMap(pair -> SHORT_SATURATING_GENERATORS_ASSOC.stream().map(f -> List.of(pair.get(0), pair.get(1), f))) .collect(Collectors.toList()); - @DataProvider - public Object[][] boolUnaryOpProvider() { - return BOOL_ARRAY_GENERATORS.stream(). - map(f -> new Object[]{f}). - toArray(Object[][]::new); - } static final List>> SHORT_GENERATOR_TRIPLES = SHORT_GENERATOR_PAIRS.stream(). @@ -1227,8 +1251,23 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } @@ -4460,7 +4499,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void anyTrueShortMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -4484,7 +4523,7 @@ public class ShortMaxVectorTests extends AbstractVectorTest { return res; } - @Test(dataProvider = "boolUnaryOpProvider") + @Test(dataProvider = "boolMaskUnaryOpProvider") static void allTrueShortMaxVectorTests(IntFunction fm) { boolean[] mask = fm.apply(SPECIES.length()); boolean[] r = fmr.apply(SPECIES.length()); @@ -6386,6 +6425,157 @@ public class ShortMaxVectorTests extends AbstractVectorTest { assertArraysEquals(r, a, mask, ShortMaxVectorTests::REVERSE_BYTES); } + static boolean band(boolean a, boolean b) { + return a & b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandShortMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.and(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::band); + } + + static boolean bor(boolean a, boolean b) { + return a | b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskorShortMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.or(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::bor); + } + + static boolean bxor(boolean a, boolean b) { + return a != b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskxorShortMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.xor(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::bxor); + } + + static boolean bandNot(boolean a, boolean b) { + return a & !b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskandNotShortMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.andNot(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::bandNot); + } + + static boolean beq(boolean a, boolean b) { + return a == b; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskeqShortMaxVectorTests(IntFunction fa, IntFunction fb) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.eq(bv).intoArray(r, i); + } + } + + assertArraysEquals(r, a, b, ShortMaxVectorTests::beq); + } + + static boolean unot(boolean a) { + return !a; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void masknotShortMaxVectorTests(IntFunction fa) { + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.not().intoArray(r, i); + } + } + + assertArraysEquals(r, a, ShortMaxVectorTests::unot); + } + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void maskFromToLongShortMaxVectorTests(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } + @Test(dataProvider = "shortCompareOpProvider") static void ltShortMaxVectorTestsBroadcastSmokeTest(IntFunction fa, IntFunction fb) { short[] a = fa.apply(SPECIES.length()); @@ -6685,115 +6875,22 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqualsShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEqualsShortMaxVectorTests(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ShortMaxVectorTests::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOrShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ShortMaxVectorTests::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXorShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ShortMaxVectorTests::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNotShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ShortMaxVectorTests::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEqShortMaxVectorTestsSmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, ShortMaxVectorTests::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCodeShortMaxVectorTestsSmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -6898,7 +6995,6 @@ public class ShortMaxVectorTests extends AbstractVectorTest { } } - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/gen-template.sh b/test/jdk/jdk/incubator/vector/gen-template.sh index a6f794a5559..46ccc0c8550 100644 --- a/test/jdk/jdk/incubator/vector/gen-template.sh +++ b/test/jdk/jdk/incubator/vector/gen-template.sh @@ -73,6 +73,9 @@ binary_math_template="Binary-op-math" binary_math_broadcast_template="Binary-Broadcast-op-math" bool_reduction_scalar="BoolReduction-Scalar-op" bool_reduction_template="BoolReduction-op" +bool_binary_template="BoolBinary-op" +bool_unary_template="BoolUnary-op" +mask_fromtolong_template="Mask-FromToLong" with_op_template="With-Op" shift_template="Shift-op" shift_masked_template="Shift-Masked-op" @@ -230,7 +233,8 @@ function gen_op_tmpl { local gen_perf_tests=$generate_perf_tests if [[ $template == *"-Broadcast-"* ]] || [[ $template == "Miscellaneous" ]] || - [[ $template == *"Compare-Masked"* ]] || [[ $template == *"Compare-Broadcast"* ]]; then + [[ $template == *"Compare-Masked"* ]] || [[ $template == *"Compare-Broadcast"* ]] || + [[ $template == *"Mask-Binary"* ]]; then gen_perf_tests=false fi if [ $gen_perf_tests == true ]; then @@ -625,6 +629,15 @@ gen_unary_alu_op "REVERSE_BYTES" "\$Boxtype\$.reverseBytes(a)" "intOrLong" gen_unary_alu_op "REVERSE_BYTES" "\$Boxtype\$.reverseBytes(a)" "short" gen_unary_alu_op "REVERSE_BYTES" "a" "byte" +# Mask operations +gen_op_tmpl $bool_binary_template "and" "a \& b" +gen_op_tmpl $bool_binary_template "or" "a | b" +gen_op_tmpl $bool_binary_template "xor" "a != b" +gen_op_tmpl $bool_binary_template "andNot" "a \& !b" +gen_op_tmpl $bool_binary_template "eq" "a == b" +gen_op_tmpl $bool_unary_template "not" "!a" +gen_op_tmpl $mask_fromtolong_template "FromToLong" "" + # Miscellaneous Smoke Tests gen_op_tmpl $miscellaneous_template "MISC" "" "" diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-BoolBinary-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-BoolBinary-op.template new file mode 100644 index 00000000000..3f5bc428cdd --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-BoolBinary-op.template @@ -0,0 +1,11 @@ + boolean[] a = fa.apply(SPECIES.length()); + boolean[] b = fb.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + VectorMask bv = SPECIES.loadMask(b, i); + av.[[TEST]](bv).intoArray(r, i); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-BoolUnary-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-BoolUnary-op.template new file mode 100644 index 00000000000..836db281c1b --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-BoolUnary-op.template @@ -0,0 +1,9 @@ + boolean[] a = fa.apply(SPECIES.length()); + boolean[] r = new boolean[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + VectorMask av = SPECIES.loadMask(a, i); + av.[[TEST]]().intoArray(r, i); + } + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-BoolBinary-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-BoolBinary-op.template new file mode 100644 index 00000000000..9ee79e05363 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Unit-BoolBinary-op.template @@ -0,0 +1,10 @@ + + static boolean b[[TEST]](boolean a, boolean b) { + return [[TEST_OP]]; + } + + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void mask[[TEST]]$vectorteststype$(IntFunction fa, IntFunction fb) { +[[KERNEL]] + assertArraysEquals(r, a, b, $vectorteststype$::b[[TEST]]); + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-BoolUnary-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-BoolUnary-op.template new file mode 100644 index 00000000000..6b1f2185528 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Unit-BoolUnary-op.template @@ -0,0 +1,10 @@ + + static boolean u[[TEST]](boolean a) { + return [[TEST_OP]]; + } + + @Test(dataProvider = "boolMaskUnaryOpProvider") + static void mask[[TEST]]$vectorteststype$(IntFunction fa) { +[[KERNEL]] + assertArraysEquals(r, a, $vectorteststype$::u[[TEST]]); + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Mask-FromToLong.template b/test/jdk/jdk/incubator/vector/templates/Unit-Mask-FromToLong.template new file mode 100644 index 00000000000..784ef5f81b9 --- /dev/null +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Mask-FromToLong.template @@ -0,0 +1,27 @@ + + private static final long LONG_MASK_BITS = 0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length()); + + static void assertArraysEquals(long[] r, long[] a, long bits) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], a[i] & bits); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], a[i] & bits, "(" + a[i] + ") at index #" + i); + } + } + + @Test(dataProvider = "longMaskProvider") + static void mask[[TEST]]$vectorteststype$(IntFunction fa) { + long[] a = fa.apply(SPECIES.length()); + long[] r = new long[a.length]; + + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i++) { + VectorMask vmask = VectorMask.fromLong(SPECIES, a[i]); + r[i] = vmask.toLong(); + } + } + assertArraysEquals(r, a, LONG_MASK_BITS); + } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template b/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template index 9a020c66d52..460f7624f2c 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Miscellaneous.template @@ -382,115 +382,22 @@ } } - @Test(dataProvider = "maskCompareOpProvider") - static void maskEquals$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { + @Test(dataProvider = "boolMaskBinaryOpProvider") + static void maskEquals$vectorteststype$(IntFunction fa, IntFunction fb) { boolean[] a = fa.apply(SPECIES.length()); boolean[] b = fb.apply(SPECIES.length()); - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - boolean equals = av.equals(bv); - int to = i + SPECIES.length(); - Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + for (int ic = 0; ic < INVOC_COUNT; ic++) { + for (int i = 0; i < a.length; i += SPECIES.length()) { + var av = SPECIES.loadMask(a, i); + var bv = SPECIES.loadMask(b, i); + boolean equals = av.equals(bv); + int to = i + SPECIES.length(); + Assert.assertEquals(equals, Arrays.equals(a, i, to, b, i, to)); + } } } - static boolean band(boolean a, boolean b) { - return a & b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAnd$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.and(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, $vectorteststype$::band); - } - - static boolean bor(boolean a, boolean b) { - return a | b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskOr$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.or(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, $vectorteststype$::bor); - } - - static boolean bxor(boolean a, boolean b) { - return a != b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskXor$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.xor(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, $vectorteststype$::bxor); - } - - static boolean bandNot(boolean a, boolean b) { - return a & !b; - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskAndNot$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.andNot(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, $vectorteststype$::bandNot); - } - - static boolean beq(boolean a, boolean b) { - return (a == b); - } - - @Test(dataProvider = "maskCompareOpProvider") - static void maskEq$vectorteststype$SmokeTest(IntFunction fa, IntFunction fb) { - boolean[] a = fa.apply(SPECIES.length()); - boolean[] b = fb.apply(SPECIES.length()); - boolean[] r = new boolean[a.length]; - - for (int i = 0; i < a.length; i += SPECIES.length()) { - var av = SPECIES.loadMask(a, i); - var bv = SPECIES.loadMask(b, i); - var cv = av.eq(bv); - cv.intoArray(r, i); - } - assertArraysEquals(r, a, b, $vectorteststype$::beq); - } - @Test(dataProvider = "maskProvider") static void maskHashCode$vectorteststype$SmokeTest(IntFunction fa) { boolean[] a = fa.apply(SPECIES.length()); @@ -595,25 +502,6 @@ } } -#if[!MaxBit] - @DataProvider - public static Object[][] longMaskProvider() { - return new Object[][]{ - {0xFFFFFFFFFFFFFFFFL}, - {0x0000000000000000L}, - {0x5555555555555555L}, - {0x0123456789abcdefL}, - }; - } - - @Test(dataProvider = "longMaskProvider") - static void maskFromToLong$vectorteststype$SmokeTest(long inputLong) { - var vmask = VectorMask.fromLong(SPECIES, inputLong); - long outputLong = vmask.toLong(); - Assert.assertEquals(outputLong, (inputLong & (((0xFFFFFFFFFFFFFFFFL >>> (64 - SPECIES.length())))))); - } -#end[!MaxBit] - @DataProvider public static Object[][] offsetProvider() { return new Object[][]{ diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 33c52f18c1c..328a8335df3 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -490,6 +490,36 @@ relativeError)); } } + interface FBoolUnOp { + boolean apply(boolean a); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, FBoolUnOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i]), "(" + a[i] + ") at index #" + i); + } + } + + interface FBoolBinOp { + boolean apply(boolean a, boolean b); + } + + static void assertArraysEquals(boolean[] r, boolean[] a, boolean[] b, FBoolBinOp f) { + int i = 0; + try { + for (; i < a.length; i++) { + Assert.assertEquals(r[i], f.apply(a[i], b[i])); + } + } catch (AssertionError e) { + Assert.assertEquals(r[i], f.apply(a[i], b[i]), "(" + a[i] + ", " + b[i] + ") at index #" + i); + } + } + interface FBinOp { $type$ apply($type$ a, $type$ b); } @@ -1521,8 +1551,23 @@ relativeError)); } @DataProvider - public Object[][] maskCompareOpProvider() { - return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream().map(List::toArray). + public Object[][] longMaskProvider() { + return LONG_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskBinaryOpProvider() { + return BOOLEAN_MASK_COMPARE_GENERATOR_PAIRS.stream(). + map(List::toArray). + toArray(Object[][]::new); + } + + @DataProvider + public Object[][] boolMaskUnaryOpProvider() { + return BOOLEAN_MASK_GENERATORS.stream(). + map(f -> new Object[]{f}). toArray(Object[][]::new); } From a26221299e657b64379d2d56ed3b073f12b227d1 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 10 Dec 2025 02:04:12 +0000 Subject: [PATCH 123/141] 8255463: java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java failed with ThreadTimeoutException Reviewed-by: dfuchs, djelinski, bpb --- .../inheritedChannel/InheritedChannelTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java index 99a127ca5ad..934bf509d88 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java @@ -40,7 +40,6 @@ * @key intermittent */ -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -77,7 +76,7 @@ public class InheritedChannelTest { }; } - @Test(dataProvider = "testCases", timeOut=30000) + @Test(dataProvider = "testCases") public void test(String desc, List opts) throws Throwable { String pathVar = Platform.sharedLibraryPathVariableName(); System.out.println(pathVar + "=" + libraryPath); From b6732d6048259de68a3dd5b4f66ac82f87270404 Mon Sep 17 00:00:00 2001 From: Xiaohong Gong Date: Wed, 10 Dec 2025 02:09:49 +0000 Subject: [PATCH 124/141] 8371603: C2: Missing Ideal optimizations for load and store vectors on SVE Co-authored-by: Emanuel Peter Reviewed-by: epeter, erfang, haosun --- src/hotspot/cpu/aarch64/aarch64_vector.ad | 29 +- src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 | 29 +- src/hotspot/share/opto/matcher.hpp | 4 + src/hotspot/share/opto/vectornode.cpp | 65 ++- src/hotspot/share/opto/vectornode.hpp | 1 - .../compiler/lib/ir_framework/IRNode.java | 10 + .../TestVectorLoadStoreOptimization.java | 105 +++++ .../TestVectorOperationsWithPartialSize.java | 432 ++++++++++++++++++ 8 files changed, 619 insertions(+), 56 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestVectorLoadStoreOptimization.java create mode 100644 test/hotspot/jtreg/compiler/vectorapi/TestVectorOperationsWithPartialSize.java diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index 842784d1a29..78ef121bd29 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -346,8 +346,14 @@ source %{ } bool Matcher::vector_needs_partial_operations(Node* node, const TypeVect* vt) { - // Only SVE has partial vector operations - if (UseSVE == 0) { + // 1. Only SVE requires partial vector operations. + // 2. The vector size in bytes must be smaller than MaxVectorSize. + // 3. Predicated vectors have a mask input, which guarantees that + // out-of-bounds lanes remain inactive. + int length_in_bytes = vt->length_in_bytes(); + if (UseSVE == 0 || + length_in_bytes == MaxVectorSize || + node->is_predicated_vector()) { return false; } @@ -370,21 +376,22 @@ source %{ return !node->in(1)->is_Con(); case Op_LoadVector: case Op_StoreVector: - // We use NEON load/store instructions if the vector length is <= 128 bits. - return vt->length_in_bytes() > 16; case Op_AddReductionVI: case Op_AddReductionVL: - // We may prefer using NEON instructions rather than SVE partial operations. - return !VM_Version::use_neon_for_vector(vt->length_in_bytes()); + // For these ops, we prefer using NEON instructions rather than SVE + // predicated instructions for better performance. + return !VM_Version::use_neon_for_vector(length_in_bytes); case Op_MinReductionV: case Op_MaxReductionV: - // For BYTE/SHORT/INT/FLOAT/DOUBLE types, we may prefer using NEON - // instructions rather than SVE partial operations. + // For BYTE/SHORT/INT/FLOAT/DOUBLE types, we prefer using NEON + // instructions rather than SVE predicated instructions for + // better performance. return vt->element_basic_type() == T_LONG || - !VM_Version::use_neon_for_vector(vt->length_in_bytes()); + !VM_Version::use_neon_for_vector(length_in_bytes); default: - // For other ops whose vector size is smaller than the max vector size, a - // full-sized unpredicated operation does not impact the final vector result. + // For other ops whose vector size is smaller than the max vector + // size, a full-sized unpredicated operation does not impact the + // vector result. return false; } } diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index dff82ce95ac..66dc22c3758 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -336,8 +336,14 @@ source %{ } bool Matcher::vector_needs_partial_operations(Node* node, const TypeVect* vt) { - // Only SVE has partial vector operations - if (UseSVE == 0) { + // 1. Only SVE requires partial vector operations. + // 2. The vector size in bytes must be smaller than MaxVectorSize. + // 3. Predicated vectors have a mask input, which guarantees that + // out-of-bounds lanes remain inactive. + int length_in_bytes = vt->length_in_bytes(); + if (UseSVE == 0 || + length_in_bytes == MaxVectorSize || + node->is_predicated_vector()) { return false; } @@ -360,21 +366,22 @@ source %{ return !node->in(1)->is_Con(); case Op_LoadVector: case Op_StoreVector: - // We use NEON load/store instructions if the vector length is <= 128 bits. - return vt->length_in_bytes() > 16; case Op_AddReductionVI: case Op_AddReductionVL: - // We may prefer using NEON instructions rather than SVE partial operations. - return !VM_Version::use_neon_for_vector(vt->length_in_bytes()); + // For these ops, we prefer using NEON instructions rather than SVE + // predicated instructions for better performance. + return !VM_Version::use_neon_for_vector(length_in_bytes); case Op_MinReductionV: case Op_MaxReductionV: - // For BYTE/SHORT/INT/FLOAT/DOUBLE types, we may prefer using NEON - // instructions rather than SVE partial operations. + // For BYTE/SHORT/INT/FLOAT/DOUBLE types, we prefer using NEON + // instructions rather than SVE predicated instructions for + // better performance. return vt->element_basic_type() == T_LONG || - !VM_Version::use_neon_for_vector(vt->length_in_bytes()); + !VM_Version::use_neon_for_vector(length_in_bytes); default: - // For other ops whose vector size is smaller than the max vector size, a - // full-sized unpredicated operation does not impact the final vector result. + // For other ops whose vector size is smaller than the max vector + // size, a full-sized unpredicated operation does not impact the + // vector result. return false; } } diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp index ca13d0166a1..a071cff9e3c 100644 --- a/src/hotspot/share/opto/matcher.hpp +++ b/src/hotspot/share/opto/matcher.hpp @@ -329,6 +329,10 @@ public: 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 + // controlling only the lanes in range [0, vector_length) are processed. This applies + // to operations whose vector length is less than the hardware-supported maximum + // vector length. Returns true if the operation requires masking, false otherwise. static bool vector_needs_partial_operations(Node* node, const TypeVect* vt); static bool vector_rearrange_requires_load_shuffle(BasicType elem_bt, int vlen); diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 57b94205e5e..271dc901dcb 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -936,28 +936,26 @@ bool VectorNode::is_scalar_op_that_returns_int_but_vector_op_returns_long(int op } } +// Idealize vector operations whose vector size is less than the hardware supported +// max vector size. Generate a vector mask for the operation. Lanes with indices +// inside of the vector size are set to true, while the remaining lanes are set to +// false. Returns the corresponding masked vector node. +static Node* ideal_partial_operations(PhaseGVN* phase, Node* node, const TypeVect* vt) { + if (!Matcher::vector_needs_partial_operations(node, vt)) { + return nullptr; + } -Node* VectorNode::try_to_gen_masked_vector(PhaseGVN* gvn, Node* node, const TypeVect* vt) { int vopc = node->Opcode(); uint vlen = vt->length(); BasicType bt = vt->element_basic_type(); + assert(Matcher::match_rule_supported_vector_masked(vopc, vlen, bt), + "The masked feature is required for the vector operation"); + assert(Matcher::match_rule_supported_vector(Op_VectorMaskGen, vlen, bt), + "'VectorMaskGen' is required to generate a vector mask"); - // Predicated vectors do not need to add another mask input - if (node->is_predicated_vector() || !Matcher::has_predicated_vectors() || - !Matcher::match_rule_supported_vector_masked(vopc, vlen, bt) || - !Matcher::match_rule_supported_vector(Op_VectorMaskGen, vlen, bt)) { - return nullptr; - } - - Node* mask = nullptr; - // Generate a vector mask for vector operation whose vector length is lower than the - // hardware supported max vector length. - if (vt->length_in_bytes() < (uint)MaxVectorSize) { - Node* length = gvn->transform(new ConvI2LNode(gvn->makecon(TypeInt::make(vlen)))); - mask = gvn->transform(VectorMaskGenNode::make(length, bt, vlen)); - } else { - return nullptr; - } + // Generate a vector mask, with lanes inside of the vector length set to true. + Node* length = phase->transform(new ConvI2LNode(phase->makecon(TypeInt::make(vlen)))); + Node* mask = phase->transform(VectorMaskGenNode::make(length, bt, vlen)); // Generate the related masked op for vector load/store/load_gather/store_scatter. // Or append the mask to the vector op's input list by default. @@ -1037,8 +1035,9 @@ bool VectorNode::should_swap_inputs_to_help_global_value_numbering() { } Node* VectorNode::Ideal(PhaseGVN* phase, bool can_reshape) { - if (Matcher::vector_needs_partial_operations(this, vect_type())) { - return try_to_gen_masked_vector(phase, this, vect_type()); + Node* n = ideal_partial_operations(phase, this, vect_type()); + if (n != nullptr) { + return n; } // Sort inputs of commutative non-predicated vector operations to help value numbering. @@ -1119,9 +1118,9 @@ LoadVectorNode* LoadVectorNode::make(int opc, Node* ctl, Node* mem, } Node* LoadVectorNode::Ideal(PhaseGVN* phase, bool can_reshape) { - const TypeVect* vt = vect_type(); - if (Matcher::vector_needs_partial_operations(this, vt)) { - return VectorNode::try_to_gen_masked_vector(phase, this, vt); + Node* n = ideal_partial_operations(phase, this, vect_type()); + if (n != nullptr) { + return n; } return LoadNode::Ideal(phase, can_reshape); } @@ -1133,9 +1132,9 @@ StoreVectorNode* StoreVectorNode::make(int opc, Node* ctl, Node* mem, Node* adr, } Node* StoreVectorNode::Ideal(PhaseGVN* phase, bool can_reshape) { - const TypeVect* vt = vect_type(); - if (Matcher::vector_needs_partial_operations(this, vt)) { - return VectorNode::try_to_gen_masked_vector(phase, this, vt); + Node* n = ideal_partial_operations(phase, this, vect_type()); + if (n != nullptr) { + return n; } return StoreNode::Ideal(phase, can_reshape); } @@ -1411,11 +1410,11 @@ ReductionNode* ReductionNode::make(int opc, Node* ctrl, Node* n1, Node* n2, Basi } Node* ReductionNode::Ideal(PhaseGVN* phase, bool can_reshape) { - const TypeVect* vt = vect_type(); - if (Matcher::vector_needs_partial_operations(this, vt)) { - return VectorNode::try_to_gen_masked_vector(phase, this, vt); + Node* n = ideal_partial_operations(phase, this, vect_type()); + if (n != nullptr) { + return n; } - return nullptr; + return Node::Ideal(phase, can_reshape); } // Convert fromLong to maskAll if the input sets or unsets all lanes. @@ -1893,11 +1892,11 @@ Node* VectorMaskOpNode::make(Node* mask, const Type* ty, int mopc) { } Node* VectorMaskOpNode::Ideal(PhaseGVN* phase, bool can_reshape) { - const TypeVect* vt = vect_type(); - if (Matcher::vector_needs_partial_operations(this, vt)) { - return VectorNode::try_to_gen_masked_vector(phase, this, vt); + Node* n = ideal_partial_operations(phase, this, vect_type()); + if (n != nullptr) { + return n; } - return nullptr; + return TypeNode::Ideal(phase, can_reshape); } Node* VectorMaskCastNode::Identity(PhaseGVN* phase) { diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index 427aeff53fc..dc7aa13cf36 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -117,7 +117,6 @@ class VectorNode : public TypeNode { static bool is_vector_bitwise_not_pattern(Node* n); static Node* degenerate_vector_rotate(Node* n1, Node* n2, bool is_rotate_left, int vlen, BasicType bt, PhaseGVN* phase); - static Node* try_to_gen_masked_vector(PhaseGVN* gvn, Node* node, const TypeVect* vt); // [Start, end) half-open range defining which operands are vectors static void vector_operands(Node* n, uint* start, uint* end); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 41f185f3686..608027e7ee1 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -1478,6 +1478,16 @@ public class IRNode { beforeMatchingNameRegex(VECTOR_MASK_LANE_IS_SET, "ExtractUB"); } + public static final String VECTOR_MASK_GEN = PREFIX + "VECTOR_MASK_GEN" + POSTFIX; + static { + beforeMatchingNameRegex(VECTOR_MASK_GEN, "VectorMaskGen"); + } + + public static final String VECTOR_MASK_FIRST_TRUE = PREFIX + "VECTOR_MASK_FIRST_TRUE" + POSTFIX; + static { + beforeMatchingNameRegex(VECTOR_MASK_FIRST_TRUE, "VectorMaskFirstTrue"); + } + // Can only be used if avx512_vnni is available. public static final String MUL_ADD_VS2VI_VNNI = PREFIX + "MUL_ADD_VS2VI_VNNI" + POSTFIX; static { diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorLoadStoreOptimization.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLoadStoreOptimization.java new file mode 100644 index 00000000000..c603f450d0c --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorLoadStoreOptimization.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * 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 compiler.lib.generators.*; +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; +import jdk.test.lib.Asserts; + +/** + * @test 8371603 + * @key randomness + * @library /test/lib / + * @summary Test the missing optimization issues for vector load/store caused by JDK-8286941 + * @modules jdk.incubator.vector + * + * @run driver ${test.main.class} + */ +public class TestVectorLoadStoreOptimization { + private static final int LENGTH = 1024; + private static final Generators random = Generators.G; + + private static final VectorSpecies SPECIES = IntVector.SPECIES_PREFERRED; + + private static int[] a; + + static { + a = new int[LENGTH]; + random.fill(random.ints(), a); + } + + // Test that "LoadVectorNode::Ideal()" calls "LoadNode::Ideal()" as expected, + // which sees the previous stores that go to the same position in-dependently, + // and optimize out the load with matched store values. + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, "1" }, + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) + public static void testLoadVector() { + IntVector v1 = IntVector.fromArray(SPECIES, a, 0); + v1.intoArray(a, SPECIES.length()); + v1.intoArray(a, 2 * SPECIES.length()); + // The second load vector equals to the first one and should be optimized + // out by "LoadNode::Ideal()". + IntVector v2 = IntVector.fromArray(SPECIES, a, SPECIES.length()); + v2.intoArray(a, 3 * SPECIES.length()); + } + + @Check(test = "testLoadVector") + public static void testLoadVectorVerify() { + for (int i = SPECIES.length(); i < 4 * SPECIES.length(); i += SPECIES.length()) { + for (int j = 0; j < SPECIES.length(); j++) { + Asserts.assertEquals(a[i + j], a[j]); + } + } + } + + // Test that "StoreVectorNode::Ideal()" calls "StoreNode::Ideal()" as expected, + // which can get rid of previous stores that go to the same position. + @Test + @IR(counts = { IRNode.STORE_VECTOR, "1" }, + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) + public static void testStoreVector() { + IntVector v1 = IntVector.fromArray(SPECIES, a, 0 * SPECIES.length()); + IntVector v2 = IntVector.fromArray(SPECIES, a, 1 * SPECIES.length()); + // Useless store to same position as below, which should be optimized out by + // "StoreNode::Ideal()". + v1.intoArray(a, 3 * SPECIES.length()); + v2.intoArray(a, 3 * SPECIES.length()); + } + + @Check(test = "testStoreVector") + public static void testStoreVectorVerify() { + for (int i = 3 * SPECIES.length(); i < 4 * SPECIES.length(); i++) { + Asserts.assertEquals(a[i], a[i - 2 * SPECIES.length()]); + } + } + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector") + .start(); + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorOperationsWithPartialSize.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorOperationsWithPartialSize.java new file mode 100644 index 00000000000..6fd20b7e2fb --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorOperationsWithPartialSize.java @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * 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 compiler.lib.generators.*; +import compiler.lib.ir_framework.*; +import jdk.incubator.vector.*; +import jdk.test.lib.Asserts; + +/** + * @test 8371603 + * @key randomness + * @library /test/lib / + * @summary Test vector operations with vector size less than MaxVectorSize + * @modules jdk.incubator.vector + * + * @run driver ${test.main.class} + */ + +public class TestVectorOperationsWithPartialSize { + private static final int SIZE = 1024; + private static final Generators random = Generators.G; + + private static final VectorSpecies ISPEC_128 = IntVector.SPECIES_128; + private static final VectorSpecies LSPEC_128 = LongVector.SPECIES_128; + private static final VectorSpecies FSPEC_128 = FloatVector.SPECIES_128; + private static final VectorSpecies DSPEC_128 = DoubleVector.SPECIES_128; + private static final VectorSpecies ISPEC_256 = IntVector.SPECIES_256; + private static final VectorSpecies LSPEC_256 = LongVector.SPECIES_256; + + private static int[] ia; + private static int[] ib; + private static long[] la; + private static long[] lb; + private static float[] fa; + private static float[] fb; + private static double[] da; + private static double[] db; + private static boolean[] m; + private static boolean[] mr; + private static int[] indices; + + static { + ia = new int[SIZE]; + ib = new int[SIZE]; + la = new long[SIZE]; + lb = new long[SIZE]; + fa = new float[SIZE]; + fb = new float[SIZE]; + da = new double[SIZE]; + db = new double[SIZE]; + m = new boolean[SIZE]; + mr = new boolean[SIZE]; + indices = new int[SIZE]; + + random.fill(random.ints(), ia); + random.fill(random.longs(), la); + random.fill(random.floats(), fa); + random.fill(random.doubles(), da); + random.fill(random.uniformInts(0, ISPEC_128.length()), indices); + for (int i = 0; i < SIZE; i++) { + m[i] = i % 2 == 0; + } + } + + // ================ Load/Store/Gather/Scatter Tests ================== + + private static void verifyLoadStore(int[] expected, int[] actual, int vlen) { + for (int i = 0; i < vlen; i++) { + Asserts.assertEquals(expected[i], actual[i]); + } + } + + private static void verifyLoadGatherStoreScatter(int[] expected, int[] actual, int[] indices, int vlen) { + for (int i = 0; i < vlen; i++) { + Asserts.assertEquals(expected[indices[i]], actual[indices[i]]); + } + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "0", + IRNode.LOAD_VECTOR_I, IRNode.VECTOR_SIZE_4, "1", + IRNode.STORE_VECTOR, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public void testLoadStore_128() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + v.intoArray(ib, 0); + verifyLoadStore(ia, ib, ISPEC_128.length()); + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.LOAD_VECTOR_MASKED, "1", + IRNode.STORE_VECTOR_MASKED, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=64"}) + public void testLoadStore_256() { + IntVector v = IntVector.fromArray(ISPEC_256, ia, 0); + v.intoArray(ib, 0); + verifyLoadStore(ia, ib, ISPEC_256.length()); + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.LOAD_VECTOR_GATHER_MASKED, "1", + IRNode.STORE_VECTOR_SCATTER_MASKED, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public void testLoadGatherStoreScatter_128() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0, indices, 0); + v.intoArray(ib, 0, indices, 0); + verifyLoadGatherStoreScatter(ia, ib, indices, ISPEC_128.length()); + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.LOAD_VECTOR_GATHER_MASKED, "1", + IRNode.STORE_VECTOR_SCATTER_MASKED, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=64"}) + public void testLoadGatherStoreScatter_256() { + IntVector v = IntVector.fromArray(ISPEC_256, ia, 0, indices, 0); + v.intoArray(ib, 0, indices, 0); + verifyLoadGatherStoreScatter(ia, ib, indices, ISPEC_256.length()); + } + + // ===================== Reduction Tests - Add ===================== + + interface binOpInt { + int apply(int a, int b); + } + + interface binOpLong { + long apply(long a, long b); + } + + private static int reduceLanes(int init, int[] arr, int vlen, binOpInt f) { + int result = init; + for (int i = 0; i < vlen; i++) { + result = f.apply(arr[i], result); + } + return result; + } + + private static long reduceLanes(long init, long[] arr, int vlen,binOpLong f) { + long result = init; + for (int i = 0; i < vlen; i++) { + result = f.apply(arr[i], result); + } + return result; + } + + // Reduction add operations with integer types are implemented with NEON SIMD instructions + // when the vector size is less than or equal to 128-bit. + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "0", + IRNode.ADD_REDUCTION_VI, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public int testAddReductionInt_128() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.ADD); + Asserts.assertEquals(reduceLanes(0, ia, ISPEC_128.length(), (a, b) -> (a + b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.ADD_REDUCTION_VI, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=64"}) + public int testAddReductionInt_256() { + IntVector v = IntVector.fromArray(ISPEC_256, ia, 0); + int result = v.reduceLanes(VectorOperators.ADD); + Asserts.assertEquals(reduceLanes(0, ia, ISPEC_256.length(), (a, b) -> (a + b)), result); + return result; + } + + // Reduction add operations with long types are implemented with NEON SIMD instructions + // when the vector size is less than or equal to 128-bit. + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "0", + IRNode.ADD_REDUCTION_VL, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public long testAddReductionLong_128() { + LongVector v = LongVector.fromArray(LSPEC_128, la, 0); + long result = v.reduceLanes(VectorOperators.ADD); + Asserts.assertEquals(reduceLanes(0L, la, LSPEC_128.length(), (a, b) -> (a + b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.ADD_REDUCTION_VL, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=64"}) + public long testAddReductionLong_256() { + LongVector v = LongVector.fromArray(LSPEC_256, la, 0); + long result = v.reduceLanes(VectorOperators.ADD); + Asserts.assertEquals(reduceLanes(0L, la, LSPEC_256.length(), (a, b) -> (a + b)), result); + return result; + } + + private static void verifyAddReductionFloat(float actual, float[] arr, int vlen) { + float expected = 0.0f; + for (int i = 0; i < vlen; i++) { + expected += arr[i]; + } + // Floating point addition reduction ops may introduce rounding errors. + float ROUNDING_ERROR_FACTOR_ADD = 10.0f; + float tolerance = Math.ulp(expected) * ROUNDING_ERROR_FACTOR_ADD; + if (Math.abs(expected - actual) > tolerance) { + throw new RuntimeException( + "assertEqualsWithTolerance" + + ": expected " + expected + " but was " + actual + + " (tolerance: " + tolerance + ", diff: " + Math.abs(expected - actual) + ")" + ); + } + } + + private static void verifyAddReductionDouble(double actual, double[] arr, int vlen) { + double expected = 0.0; + for (int i = 0; i < vlen; i++) { + expected += arr[i]; + } + // Floating point addition reduction ops may introduce rounding errors. + double ROUNDING_ERROR_FACTOR_ADD = 10.0; + double tolerance = Math.ulp(expected) * ROUNDING_ERROR_FACTOR_ADD; + if (Math.abs(expected - actual) > tolerance) { + throw new RuntimeException( + "assertEqualsWithTolerance" + + ": expected " + expected + " but was " + actual + + " (tolerance: " + tolerance + ", diff: " + Math.abs(expected - actual) + ")" + ); + } + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.ADD_REDUCTION_VF, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public float testAddReductionFloat() { + FloatVector v = FloatVector.fromArray(FSPEC_128, fa, 0); + float result = v.reduceLanes(VectorOperators.ADD); + verifyAddReductionFloat(result, fa, FSPEC_128.length()); + return result; + } + + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.ADD_REDUCTION_VD, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public double testAddReductionDouble() { + DoubleVector v = DoubleVector.fromArray(DSPEC_128, da, 0); + double result = v.reduceLanes(VectorOperators.ADD); + verifyAddReductionDouble(result, da, DSPEC_128.length()); + return result; + } + + // ============== Reduction Tests - Logical ============== + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.AND_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public int testAndReduction() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.AND); + Asserts.assertEquals(reduceLanes(-1, ia, ISPEC_128.length(), (a, b) -> (a & b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.OR_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public int testOrReduction() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.OR); + Asserts.assertEquals(reduceLanes(0, ia, ISPEC_128.length(), (a, b) -> (a | b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.XOR_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + public int testXorReduction() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.XOR); + Asserts.assertEquals(reduceLanes(0, ia, ISPEC_128.length(), (a, b) -> (a ^ b)), result); + return result; + } + + // ===================== Reduction Tests - Min/Max ===================== + + // Reduction min operations with non-long types are implemented with NEON SIMD instructions + // when the vector size is less than or equal to 128-bit. + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "0", + IRNode.MIN_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public int testMinReductionInt_128() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.MIN); + Asserts.assertEquals(reduceLanes(Integer.MAX_VALUE, ia, ISPEC_128.length(), (a, b) -> Math.min(a, b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.MIN_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 64"}) + public int testMinReductionInt_256() { + IntVector v = IntVector.fromArray(ISPEC_256, ia, 0); + int result = v.reduceLanes(VectorOperators.MIN); + Asserts.assertEquals(reduceLanes(Integer.MAX_VALUE, ia, ISPEC_256.length(), (a, b) -> Math.min(a, b)), result); + return result; + } + + // Reduction max operations with non-long types are implemented with NEON SIMD instructions + // when the vector size is less than or equal to 128-bit. + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "0", + IRNode.MAX_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public int testMaxReductionInt_128() { + IntVector v = IntVector.fromArray(ISPEC_128, ia, 0); + int result = v.reduceLanes(VectorOperators.MAX); + Asserts.assertEquals(reduceLanes(Integer.MIN_VALUE, ia, ISPEC_128.length(), (a, b) -> Math.max(a, b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.MAX_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 64"}) + public int testMaxReductionInt_256() { + IntVector v = IntVector.fromArray(ISPEC_256, ia, 0); + int result = v.reduceLanes(VectorOperators.MAX); + Asserts.assertEquals(reduceLanes(Integer.MIN_VALUE, ia, ISPEC_256.length(), (a, b) -> Math.max(a, b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.MIN_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public static long testMinReductionLong() { + LongVector v = LongVector.fromArray(LSPEC_128, la, 0); + long result = v.reduceLanes(VectorOperators.MIN); + Asserts.assertEquals(reduceLanes(Long.MAX_VALUE, la, LSPEC_128.length(), (a, b) -> Math.min(a, b)), result); + return result; + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.MAX_REDUCTION_V, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public static long testMaxReductionLong() { + LongVector v = LongVector.fromArray(LSPEC_128, la, 0); + long result = v.reduceLanes(VectorOperators.MAX); + Asserts.assertEquals(reduceLanes(Long.MIN_VALUE, la, LSPEC_128.length(), (a, b) -> Math.max(a, b)), result); + return result; + } + + // ====================== VectorMask Tests ====================== + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.VECTOR_LOAD_MASK, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public static void testLoadMask() { + VectorMask vm = VectorMask.fromArray(ISPEC_128, m, 0); + vm.not().intoArray(mr, 0); + // Verify that the mask is loaded correctly. + for (int i = 0; i < ISPEC_128.length(); i++) { + Asserts.assertEquals(!m[i], mr[i]); + } + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.VECTOR_MASK_CMP, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public static void testVectorMaskCmp() { + IntVector v1 = IntVector.fromArray(ISPEC_128, ia, 0); + IntVector v2 = IntVector.fromArray(ISPEC_128, ib, 0); + VectorMask vm = v1.compare(VectorOperators.LT, v2); + vm.intoArray(mr, 0); + // Verify that the mask is generated correctly. + for (int i = 0; i < ISPEC_128.length(); i++) { + Asserts.assertEquals(ia[i] < ib[i], mr[i]); + } + } + + @Test + @IR(counts = {IRNode.VECTOR_MASK_GEN, "1", + IRNode.VECTOR_MASK_FIRST_TRUE, "1"}, + applyIfCPUFeature = {"sve", "true"}, applyIf = {"MaxVectorSize", ">= 32"}) + public static int testFirstTrue() { + VectorMask vm = ISPEC_128.maskAll(false); + int result = vm.firstTrue(); + // The result is the vector length if no lane is true. + // This is the default behavior of the firstTrue method. + Asserts.assertEquals(ISPEC_128.length(), result); + return result; + } + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector") + .start(); + } +} From d36a234c1228fdb12eb5931506ba1e03ebae95fc Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 10 Dec 2025 02:26:04 +0000 Subject: [PATCH 125/141] 8368701: CDS VerifierTest_1A.java failed on machines with 512 GB RAM Reviewed-by: dholmes, lmesnik --- test/hotspot/jtreg/runtime/cds/appcds/VerifierTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/VerifierTest.java b/test/hotspot/jtreg/runtime/cds/appcds/VerifierTest.java index 3ff5da98b42..e0001e021ad 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/VerifierTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/VerifierTest.java @@ -221,6 +221,8 @@ public class VerifierTest implements Opcodes { runtime_arg1 = runtime_arg2 = runtime_arg3 = runtime_setting; } TestCommon.run("-cp", jar, + "-Xms256m", + "-Xmx256m", "-Xlog:cds", runtime_arg1, runtime_arg2, runtime_arg3, "VerifierTest0") @@ -302,6 +304,8 @@ public class VerifierTest implements Opcodes { runtime_arg1 = runtime_arg2 = runtime_arg3 = runtime_setting; } TestCommon.run("-cp", jar, + "-Xms256m", + "-Xmx256m", "-Xlog:cds", runtime_arg1, runtime_arg2, runtime_arg3, "Hi") From a5968f936462741a7edea5bbbe73cb067af3d34f Mon Sep 17 00:00:00 2001 From: Anjian Wen Date: Wed, 10 Dec 2025 02:34:52 +0000 Subject: [PATCH 126/141] 8371968: RISC-V: implement AES CBC intrinsics Reviewed-by: fyang, fjiang --- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 182 +++++++++++++++++- 1 file changed, 181 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index d0cbe8ea347..49c80dce88a 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2606,6 +2606,184 @@ class StubGenerator: public StubCodeGenerator { return start; } + void cipherBlockChaining_encryptAESCrypt(int round, Register from, Register to, Register key, + Register rvec, Register input_len) { + const Register len = x29; + + VectorRegister working_vregs[] = { + v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15 + }; + + const unsigned int BLOCK_SIZE = 16; + + __ mv(len, input_len); + // load init rvec + __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); + __ vle32_v(v16, rvec); + + generate_aes_loadkeys(key, working_vregs, round); + Label L_enc_loop; + __ bind(L_enc_loop); + // Encrypt from source by block size + __ vle32_v(v17, from); + __ addi(from, from, BLOCK_SIZE); + __ vxor_vv(v16, v16, v17); + generate_aes_encrypt(v16, working_vregs, round); + __ vse32_v(v16, to); + __ addi(to, to, BLOCK_SIZE); + __ subi(len, len, BLOCK_SIZE); + __ bnez(len, L_enc_loop); + + // save current rvec and return + __ vse32_v(v16, rvec); + __ mv(x10, input_len); + __ leave(); + __ ret(); + } + + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // c_rarg3 - r vector byte array address + // c_rarg4 - input length + // + // Output: + // x10 - input length + // + address generate_cipherBlockChaining_encryptAESCrypt() { + assert(UseAESIntrinsics, "Must be"); + assert(UseZvkn, "need AES instructions (Zvkned extension) support"); + __ align(CodeEntryAlignment); + StubId stub_id = StubId::stubgen_cipherBlockChaining_encryptAESCrypt_id; + StubCodeMark mark(this, stub_id); + + const Register from = c_rarg0; + const Register to = c_rarg1; + const Register key = c_rarg2; + const Register rvec = c_rarg3; + const Register input_len = c_rarg4; + + const Register keylen = x28; + + address start = __ pc(); + __ enter(); + + Label L_aes128, L_aes192; + // Compute #rounds for AES based on the length of the key array + __ lwu(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + __ mv(t0, 52); + __ bltu(keylen, t0, L_aes128); + __ beq(keylen, t0, L_aes192); + // Else we fallthrough to the biggest case (256-bit key size) + + // Note: the following function performs key += 15*16 + cipherBlockChaining_encryptAESCrypt(15, from, to, key, rvec, input_len); + + // Note: the following function performs key += 11*16 + __ bind(L_aes128); + cipherBlockChaining_encryptAESCrypt(11, from, to, key, rvec, input_len); + + // Note: the following function performs key += 13*16 + __ bind(L_aes192); + cipherBlockChaining_encryptAESCrypt(13, from, to, key, rvec, input_len); + + return start; + } + + void cipherBlockChaining_decryptAESCrypt(int round, Register from, Register to, Register key, + Register rvec, Register input_len) { + const Register len = x29; + + VectorRegister working_vregs[] = { + v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15 + }; + + const unsigned int BLOCK_SIZE = 16; + + __ mv(len, input_len); + // load init rvec + __ vsetivli(x0, 4, Assembler::e32, Assembler::m1); + __ vle32_v(v16, rvec); + + generate_aes_loadkeys(key, working_vregs, round); + Label L_dec_loop; + // Decrypt from source by block size + __ bind(L_dec_loop); + __ vle32_v(v17, from); + __ addi(from, from, BLOCK_SIZE); + __ vmv_v_v(v18, v17); + generate_aes_decrypt(v17, working_vregs, round); + __ vxor_vv(v17, v17, v16); + __ vse32_v(v17, to); + __ vmv_v_v(v16, v18); + __ addi(to, to, BLOCK_SIZE); + __ subi(len, len, BLOCK_SIZE); + __ bnez(len, L_dec_loop); + + // save current rvec and return + __ vse32_v(v16, rvec); + __ mv(x10, input_len); + __ leave(); + __ ret(); + } + + // Arguments: + // + // Inputs: + // c_rarg0 - source byte array address + // c_rarg1 - destination byte array address + // c_rarg2 - K (key) in little endian int array + // c_rarg3 - r vector byte array address + // c_rarg4 - input length + // + // Output: + // x10 - input length + // + address generate_cipherBlockChaining_decryptAESCrypt() { + assert(UseAESIntrinsics, "Must be"); + assert(UseZvkn, "need AES instructions (Zvkned extension) support"); + __ align(CodeEntryAlignment); + StubId stub_id = StubId::stubgen_cipherBlockChaining_decryptAESCrypt_id; + StubCodeMark mark(this, stub_id); + + const Register from = c_rarg0; + const Register to = c_rarg1; + const Register key = c_rarg2; + const Register rvec = c_rarg3; + const Register input_len = c_rarg4; + + const Register keylen = x28; + + address start = __ pc(); + __ enter(); + + Label L_aes128, L_aes192, L_aes128_loop, L_aes192_loop, L_aes256_loop; + // Compute #rounds for AES based on the length of the key array + __ lwu(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + __ mv(t0, 52); + __ bltu(keylen, t0, L_aes128); + __ beq(keylen, t0, L_aes192); + // Else we fallthrough to the biggest case (256-bit key size) + + // Note: the following function performs key += 15*16 + cipherBlockChaining_decryptAESCrypt(15, from, to, key, rvec, input_len); + + // Note: the following function performs key += 11*16 + __ bind(L_aes128); + cipherBlockChaining_decryptAESCrypt(11, from, to, key, rvec, input_len); + + // Note: the following function performs key += 13*16 + __ bind(L_aes192); + cipherBlockChaining_decryptAESCrypt(13, from, to, key, rvec, input_len); + + return start; + } + // Load big-endian 128-bit from memory. void be_load_counter_128(Register counter_hi, Register counter_lo, Register counter) { __ ld(counter_lo, Address(counter, 8)); // Load 128-bits from counter @@ -2772,8 +2950,8 @@ class StubGenerator: public StubCodeGenerator { // x10 - input length // address generate_counterMode_AESCrypt() { + assert(UseAESCTRIntrinsics, "Must be"); assert(UseZvkn, "need AES instructions (Zvkned extension) support"); - assert(UseAESCTRIntrinsics, "need AES instructions (Zvkned extension) support"); assert(UseZbb, "need basic bit manipulation (Zbb extension) support"); __ align(CodeEntryAlignment); @@ -7041,6 +7219,8 @@ static const int64_t right_3_bits = right_n_bits(3); if (UseAESIntrinsics) { StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock(); StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock(); + StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt(); + StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt(); } if (UseAESCTRIntrinsics) { From 1bbbce75c5e68429c2a32519eb3c36d964dcdf57 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 10 Dec 2025 04:31:37 +0000 Subject: [PATCH 127/141] 6726690: SwingUtilities.replaceUI*Map() methods do not remove previously installed maps Reviewed-by: azvegint, tr --- .../classes/javax/swing/SwingUtilities.java | 6 ++ .../javax/swing/SwingUtilities/UIMapTest.java | 90 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 test/jdk/javax/swing/SwingUtilities/UIMapTest.java diff --git a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java index 4633e9c4756..70fbeee8c7b 100644 --- a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java +++ b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java @@ -1813,6 +1813,9 @@ public class SwingUtilities implements SwingConstants while (map != null) { InputMap parent = map.getParent(); + if (uiInputMap == null) { + map.clear(); + } if (parent == null || (parent instanceof UIResource)) { map.setParent(uiInputMap); return; @@ -1837,6 +1840,9 @@ public class SwingUtilities implements SwingConstants while (map != null) { ActionMap parent = map.getParent(); + if (uiActionMap == null) { + map.clear(); + } if (parent == null || (parent instanceof UIResource)) { map.setParent(uiActionMap); return; diff --git a/test/jdk/javax/swing/SwingUtilities/UIMapTest.java b/test/jdk/javax/swing/SwingUtilities/UIMapTest.java new file mode 100644 index 00000000000..4a801580b35 --- /dev/null +++ b/test/jdk/javax/swing/SwingUtilities/UIMapTest.java @@ -0,0 +1,90 @@ +/* + * 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 6726690 + * @summary Verifies SwingUtilities.replaceUI*Map() methods remove + * previously installed maps + * @run main UIMapTest + */ + +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.ComponentInputMap; +import javax.swing.InputMap; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; + +public class UIMapTest { + + public static void main(String[] args) { + + StringBuilder str = new StringBuilder(); + + // Create the test button + JButton button = new JButton("Test"); + + // Create an input map that maps ENTER to the button + ComponentInputMap map = new ComponentInputMap(button); + map.put(KeyStroke.getKeyStroke("pressed ENTER"), "pressed"); + map.put(KeyStroke.getKeyStroke("released ENTER"), "released"); + + // Add the map + SwingUtilities.replaceUIInputMap(button, JComponent.WHEN_IN_FOCUSED_WINDOW, map); + + // Attempt to remove the map + SwingUtilities.replaceUIInputMap(button, JComponent.WHEN_IN_FOCUSED_WINDOW, null); + + if (button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW). + get(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)) != null) { + str.append("\nSwingUtilities.replaceUIInputMap " + + "didn't remove previously installed input map"); + } + + // Get the InputMap for the button when it has focus + InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + + // Map the VK_ENTER key stroke to a specific action name + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "doEnterAction"); + Action enterAction = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { } + }; + button.getActionMap().put("doEnterAction", enterAction); + SwingUtilities.replaceUIActionMap(button, null); + if (button.getActionMap().size() != 0) { + str.append("\nSwingUtilities.replaceUIActionMap " + + "didn't remove previously installed action map"); + } + if (str.length() != 0) { + throw new RuntimeException(str.toString()); + } + } +} From 00068a80304a809297d0df8698850861e9a1c5e9 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 10 Dec 2025 08:45:20 +0000 Subject: [PATCH 128/141] 8354282: C2: more crashes in compiled code because of dependency on removed range check CastIIs Reviewed-by: chagedorn, qamai, galder, epeter --- .../gc/shenandoah/c2/shenandoahSupport.cpp | 2 +- src/hotspot/share/opto/castnode.cpp | 141 ++++++++++------ src/hotspot/share/opto/castnode.hpp | 151 +++++++++++++++--- src/hotspot/share/opto/cfgnode.cpp | 10 +- src/hotspot/share/opto/compile.cpp | 2 +- src/hotspot/share/opto/escape.cpp | 6 +- src/hotspot/share/opto/library_call.cpp | 4 +- src/hotspot/share/opto/loopTransform.cpp | 4 +- src/hotspot/share/opto/loopnode.cpp | 6 +- src/hotspot/share/opto/loopopts.cpp | 4 +- src/hotspot/share/opto/macroArrayCopy.cpp | 2 +- .../c2/irTests/TestPushAddThruCast.java | 29 +++- ...yAccessAboveRCAfterRCCastIIEliminated.java | 82 +++++++++- 13 files changed, 341 insertions(+), 102 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 35ec9ed5c8c..40fe0c00490 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -1394,7 +1394,7 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { } if (addr->Opcode() == Op_AddP) { Node* orig_base = addr->in(AddPNode::Base); - Node* base = new CheckCastPPNode(ctrl, orig_base, orig_base->bottom_type(), ConstraintCastNode::StrongDependency); + Node* base = new CheckCastPPNode(ctrl, orig_base, orig_base->bottom_type(), ConstraintCastNode::DependencyType::NonFloatingNarrowing); phase->register_new_node(base, ctrl); if (addr->in(AddPNode::Base) == addr->in((AddPNode::Address))) { // Field access diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 6d899c1f950..9c764f22e38 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -22,7 +22,6 @@ * */ -#include "castnode.hpp" #include "opto/addnode.hpp" #include "opto/callnode.hpp" #include "opto/castnode.hpp" @@ -35,12 +34,22 @@ #include "opto/type.hpp" #include "utilities/checkedCast.hpp" +const ConstraintCastNode::DependencyType ConstraintCastNode::DependencyType::FloatingNarrowing(true, true, "floating narrowing dependency"); // not pinned, narrows type +const ConstraintCastNode::DependencyType ConstraintCastNode::DependencyType::FloatingNonNarrowing(true, false, "floating non-narrowing dependency"); // not pinned, doesn't narrow type +const ConstraintCastNode::DependencyType ConstraintCastNode::DependencyType::NonFloatingNarrowing(false, true, "non-floating narrowing dependency"); // pinned, narrows type +const ConstraintCastNode::DependencyType ConstraintCastNode::DependencyType::NonFloatingNonNarrowing(false, false, "non-floating non-narrowing dependency"); // pinned, doesn't narrow type + //============================================================================= // If input is already higher or equal to cast type, then this is an identity. Node* ConstraintCastNode::Identity(PhaseGVN* phase) { - if (_dependency == UnconditionalDependency) { + if (!_dependency.narrows_type()) { + // If this cast doesn't carry a type dependency (i.e. not used for type narrowing), we cannot optimize it. return this; } + + // This cast node carries a type dependency. We can remove it if: + // - Its input has a narrower type + // - There's a dominating cast with same input but narrower type Node* dom = dominating_cast(phase, phase); if (dom != nullptr) { return dom; @@ -109,7 +118,7 @@ Node* ConstraintCastNode::Ideal(PhaseGVN* phase, bool can_reshape) { } uint ConstraintCastNode::hash() const { - return TypeNode::hash() + (int)_dependency + (_extra_types != nullptr ? _extra_types->hash() : 0); + return TypeNode::hash() + _dependency.hash() + (_extra_types != nullptr ? _extra_types->hash() : 0); } bool ConstraintCastNode::cmp(const Node &n) const { @@ -117,7 +126,7 @@ bool ConstraintCastNode::cmp(const Node &n) const { return false; } ConstraintCastNode& cast = (ConstraintCastNode&) n; - if (cast._dependency != _dependency) { + if (!cast._dependency.cmp(_dependency)) { return false; } if (_extra_types == nullptr || cast._extra_types == nullptr) { @@ -130,7 +139,7 @@ uint ConstraintCastNode::size_of() const { return sizeof(*this); } -Node* ConstraintCastNode::make_cast_for_basic_type(Node* c, Node* n, const Type* t, DependencyType dependency, BasicType bt) { +Node* ConstraintCastNode::make_cast_for_basic_type(Node* c, Node* n, const Type* t, const DependencyType& dependency, BasicType bt) { switch(bt) { case T_INT: return new CastIINode(c, n, t, dependency); @@ -143,9 +152,9 @@ Node* ConstraintCastNode::make_cast_for_basic_type(Node* c, Node* n, const Type* } TypeNode* ConstraintCastNode::dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) const { - if (_dependency == UnconditionalDependency) { - return nullptr; - } + // See discussion at definition of ConstraintCastNode::DependencyType: replacing this cast with a dominating one is + // not safe if _dependency.narrows_type() is not true. + assert(_dependency.narrows_type(), "cast can't be replaced by dominating one"); Node* val = in(1); Node* ctl = in(0); int opc = Opcode(); @@ -205,30 +214,21 @@ void ConstraintCastNode::dump_spec(outputStream *st) const { st->print(" extra types: "); _extra_types->dump_on(st); } - if (_dependency != RegularDependency) { - st->print(" %s dependency", _dependency == StrongDependency ? "strong" : "unconditional"); - } + st->print(" "); + _dependency.dump_on(st); } #endif -const Type* CastIINode::Value(PhaseGVN* phase) const { - const Type *res = ConstraintCastNode::Value(phase); - if (res == Type::TOP) { - return Type::TOP; - } - assert(res->isa_int(), "res must be int"); - - // Similar to ConvI2LNode::Value() for the same reasons - // see if we can remove type assertion after loop opts - res = widen_type(phase, res, T_INT); - - return res; +CastIINode* CastIINode::make_with(Node* parent, const TypeInteger* type, const DependencyType& dependency) const { + return new CastIINode(in(0), parent, type, dependency, _range_check_dependency, _extra_types); } -Node* ConstraintCastNode::find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, const TypeInteger* type) const { - Node* n = clone(); - n->set_req(1, parent); - n->as_ConstraintCast()->set_type(type); +CastLLNode* CastLLNode::make_with(Node* parent, const TypeInteger* type, const DependencyType& dependency) const { + return new CastLLNode(in(0), parent, type, dependency, _extra_types); +} + +Node* ConstraintCastNode::find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, const TypeInteger* type, const DependencyType& dependency) const { + Node* n = make_with(parent, type, dependency); Node* existing = igvn->hash_find_insert(n); if (existing != nullptr) { n->destruct(igvn); @@ -242,14 +242,13 @@ Node *CastIINode::Ideal(PhaseGVN *phase, bool can_reshape) { if (progress != nullptr) { return progress; } - if (can_reshape && !phase->C->post_loop_opts_phase()) { - // makes sure we run ::Value to potentially remove type assertion after loop opts + if (!phase->C->post_loop_opts_phase()) { + // makes sure we run widen_type() to potentially common type assertions after loop opts phase->C->record_for_post_loop_opts_igvn(this); } if (!_range_check_dependency || phase->C->post_loop_opts_phase()) { return optimize_integer_cast(phase, T_INT); } - phase->C->record_for_post_loop_opts_igvn(this); return nullptr; } @@ -279,9 +278,9 @@ void CastIINode::dump_spec(outputStream* st) const { #endif CastIINode* CastIINode::pin_array_access_node() const { - assert(_dependency == RegularDependency, "already pinned"); + assert(_dependency.is_floating(), "already pinned"); if (has_range_check()) { - return new CastIINode(in(0), in(1), bottom_type(), StrongDependency, has_range_check()); + return new CastIINode(in(0), in(1), bottom_type(), _dependency.with_pinned_dependency(), has_range_check()); } return nullptr; } @@ -315,16 +314,6 @@ void CastIINode::remove_range_check_cast(Compile* C) { } -const Type* CastLLNode::Value(PhaseGVN* phase) const { - const Type* res = ConstraintCastNode::Value(phase); - if (res == Type::TOP) { - return Type::TOP; - } - assert(res->isa_long(), "res must be long"); - - return widen_type(phase, res, T_LONG); -} - bool CastLLNode::is_inner_loop_backedge(ProjNode* proj) { if (proj != nullptr) { Node* ctrl_use = proj->unique_ctrl_out_or_null(); @@ -392,7 +381,7 @@ Node* CastLLNode::Ideal(PhaseGVN* phase, bool can_reshape) { return progress; } if (!phase->C->post_loop_opts_phase()) { - // makes sure we run ::Value to potentially remove type assertion after loop opts + // makes sure we run widen_type() to potentially common type assertions after loop opts phase->C->record_for_post_loop_opts_igvn(this); } // transform (CastLL (ConvI2L ..)) into (ConvI2L (CastII ..)) if the type of the CastLL is narrower than the type of @@ -543,7 +532,7 @@ Node* CastP2XNode::Identity(PhaseGVN* phase) { return this; } -Node* ConstraintCastNode::make_cast_for_type(Node* c, Node* in, const Type* type, DependencyType dependency, +Node* ConstraintCastNode::make_cast_for_type(Node* c, Node* in, const Type* type, const DependencyType& dependency, const TypeTuple* types) { if (type->isa_int()) { return new CastIINode(c, in, type, dependency, false, types); @@ -564,7 +553,7 @@ Node* ConstraintCastNode::make_cast_for_type(Node* c, Node* in, const Type* type return nullptr; } -Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) { +Node* ConstraintCastNode::optimize_integer_cast_of_add(PhaseGVN* phase, BasicType bt) { PhaseIterGVN *igvn = phase->is_IterGVN(); const TypeInteger* this_type = this->type()->isa_integer(bt); if (this_type == nullptr) { @@ -586,8 +575,42 @@ Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) { Node* x = z->in(1); Node* y = z->in(2); - Node* cx = find_or_make_integer_cast(igvn, x, rx); - Node* cy = find_or_make_integer_cast(igvn, y, ry); + const TypeInteger* tx = phase->type(x)->is_integer(bt); + const TypeInteger* ty = phase->type(y)->is_integer(bt); + + // (Cast (Add x y) tz) is transformed into (Add (Cast x rx) (Cast y ry)) + // + // tz = [tzlo, tzhi] + // rx = [rxlo, rxhi] + // ry = [rylo, ryhi] + // with type of x, tx = [txlo, txhi] + // with type of y, ty = [tylo, tyhi] + // + // From Compile::push_thru_add(): + // rxlo = max(tzlo - tyhi, txlo) + // rxhi = min(tzhi - tylo, txhi) + // rylo = max(tzlo - txhi, tylo) + // ryhi = min(tzhi - txlo, tyhi) + // + // If x is a constant, then txlo = txhi + // rxlo = txlo, rxhi = txhi + // The bounds of the type of the Add after transformation then is: + // rxlo + rylo >= txlo + tzlo - txhi >= tzlo + // rxhi + ryhi <= txhi + tzhi - txlo <= tzhi + // The resulting type is not wider than the type of the Cast + // before transformation + // + // If neither x nor y are constant then the type of the resulting + // Add can be wider than the type of the type of the Cast before + // transformation. + // For instance, tx = [0, 10], ty = [0, 10], tz = [0, 10] + // then rx = [0, 10], ry = [0, 10] + // and rx + ry = [0, 20] which is wider than tz + // + // Same reasoning applies to (Cast (Sub x y) tz) + const DependencyType& dependency = (!tx->is_con() && !ty->is_con()) ? _dependency.with_non_narrowing() : _dependency; + Node* cx = find_or_make_integer_cast(igvn, x, rx, dependency); + Node* cy = find_or_make_integer_cast(igvn, y, ry, dependency); if (op == Op_Add(bt)) { return AddNode::make(cx, cy, bt); } else { @@ -599,11 +622,26 @@ Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) { return nullptr; } -const Type* ConstraintCastNode::widen_type(const PhaseGVN* phase, const Type* res, BasicType bt) const { - if (!phase->C->post_loop_opts_phase()) { +Node* ConstraintCastNode::optimize_integer_cast(PhaseGVN* phase, BasicType bt) { + Node* res = optimize_integer_cast_of_add(phase, bt); + if (res != nullptr) { return res; } + const Type* t = Value(phase); + if (t != Type::TOP && phase->C->post_loop_opts_phase()) { + const Type* bottom_t = bottom_type(); + const TypeInteger* wide_t = widen_type(phase, bottom_t, bt); + if (wide_t != bottom_t) { + // Widening the type of the Cast (to allow some commoning) causes the Cast to change how it can be optimized (if + // type of its input is narrower than the Cast's type, we can't remove it to not loose the control dependency). + return make_with(in(1), wide_t, _dependency.with_non_narrowing()); + } + } + return nullptr; +} +const TypeInteger* ConstraintCastNode::widen_type(const PhaseGVN* phase, const Type* res, BasicType bt) const { + const TypeInteger* this_type = res->is_integer(bt); // At VerifyConstraintCasts == 1, we verify the ConstraintCastNodes that are present during code // emission. This allows us detecting possible mis-scheduling due to these nodes being pinned at // the wrong control nodes. @@ -612,10 +650,9 @@ const Type* ConstraintCastNode::widen_type(const PhaseGVN* phase, const Type* re // mis-transformations that may happen due to these nodes being pinned at the wrong control // nodes. if (VerifyConstraintCasts > 1) { - return res; + return this_type; } - const TypeInteger* this_type = res->is_integer(bt); const TypeInteger* in_type = phase->type(in(1))->isa_integer(bt); if (in_type != nullptr && (in_type->lo_as_long() != this_type->lo_as_long() || @@ -636,5 +673,5 @@ const Type* ConstraintCastNode::widen_type(const PhaseGVN* phase, const Type* re MIN2(in_type->hi_as_long(), hi1), MAX2((int)in_type->_widen, w1), bt); } - return res; + return this_type; } diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index 3c6ade64aa8..2ff13e44780 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -33,21 +33,119 @@ // cast to a different range class ConstraintCastNode: public TypeNode { public: - enum DependencyType { - RegularDependency, // if cast doesn't improve input type, cast can be removed - StrongDependency, // leave cast in even if _type doesn't improve input type, can be replaced by stricter dominating cast if one exist - UnconditionalDependency // leave cast in unconditionally + // Cast nodes are subject to a few optimizations: + // + // 1- if the type carried by the Cast doesn't narrow the type of its input, the cast can be replaced by its input. + // Similarly, if a dominating Cast with the same input and a narrower type constraint is found, it can replace the + // current cast. + // + // 2- if the condition that the Cast is control dependent is hoisted, the Cast is hoisted as well + // + // 1- and 2- are not always applied depending on what constraint are applied to the Cast: there are cases where 1- + // and 2- apply, where neither 1- nor 2- apply and where one or the other apply. This class abstract away these + // details. + // + // If _narrows_type is true, the cast carries a type dependency: "after" the control the cast is dependent on, its data + // input is known to have a narrower type (stored in the cast node itself). Optimizations 1- above only apply to cast + // nodes for which _narrows_type is true. + // if _floating is true, the cast only depends on a single control: its control input. Otherwise, it is pinned at its + // current location. Optimizations 2- only apply to cast nodes for which _floating is true. + // _floating here is similar to Node::depends_only_on_test(). + // The 4 combinations of _narrows_types/_floating true/false have some use. See below, at the end of this class + // definition, for examples. + class DependencyType { + private: + const bool _floating; // Does this Cast depends on its control input or is it pinned? + const bool _narrows_type; // Does this Cast narrows the type i.e. if input type is narrower can it be removed? + const char* _desc; + DependencyType(bool depends_on_test, bool narrows_type, const char* desc) + : _floating(depends_on_test), + _narrows_type(narrows_type), + _desc(desc) { + } + NONCOPYABLE(DependencyType); + + public: + + bool is_floating() const { + return _floating; + } + + bool narrows_type() const { + return _narrows_type; + } + + void dump_on(outputStream *st) const { + st->print("%s", _desc); + } + + uint hash() const { + return (_floating ? 1 : 0) + (_narrows_type ? 2 : 0); + } + + bool cmp(const DependencyType& other) const { + return _floating == other._floating && _narrows_type == other._narrows_type; + } + + const DependencyType& with_non_narrowing() const { + if (_floating) { + return FloatingNonNarrowing; + } + return NonFloatingNonNarrowing; + } + + const DependencyType& with_pinned_dependency() const { + if (_narrows_type) { + return NonFloatingNarrowing; + } + return NonFloatingNonNarrowing; + } + + // All the possible combinations of floating/narrowing with example use cases: + + // Use case example: Range Check CastII + // Floating: The Cast is only dependent on the single range check. If the range check was ever to be hoisted it + // would be safe to let the Cast float to where the range check is hoisted up to. + // Narrowing: The Cast narrows the type to a positive index. If the input to the Cast is narrower, we can safely + // remove the cast because the array access will be safe. + static const DependencyType FloatingNarrowing; + // Use case example: Widening Cast nodes' types after loop opts: We want to common Casts with slightly different types. + // Floating: These Casts only depend on the single control. + // NonNarrowing: Even when the input type is narrower, we are not removing the Cast. Otherwise, the dependency + // to the single control is lost, and an array access could float above its range check because we + // just removed the dependency to the range check by removing the Cast. This could lead to an + // out-of-bounds access. + static const DependencyType FloatingNonNarrowing; + // Use case example: An array accesses that is no longer dependent on a single range check (e.g. range check smearing). + // NonFloating: The array access must be pinned below all the checks it depends on. If the check it directly depends + // on with a control input is hoisted, we do not hoist the Cast as well. If we allowed the Cast to float, + // we risk that the array access ends up above another check it depends on (we cannot model two control + // dependencies for a node in the IR). This could lead to an out-of-bounds access. + // Narrowing: If the Cast does not narrow the input type, then it's safe to remove the cast because the array access + // will be safe. + static const DependencyType NonFloatingNarrowing; + // Use case example: Sinking nodes out of a loop + // Non-Floating & Non-Narrowing: We don't want the Cast that forces the node to be out of loop to be removed in any + // case. Otherwise, the sunk node could float back into the loop, undoing the sinking. + // This Cast is only used for pinning without caring about narrowing types. + static const DependencyType NonFloatingNonNarrowing; + }; - protected: - const DependencyType _dependency; +protected: + const DependencyType& _dependency; virtual bool cmp( const Node &n ) const; virtual uint size_of() const; virtual uint hash() const; // Check the type - const Type* widen_type(const PhaseGVN* phase, const Type* res, BasicType bt) const; - Node* find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, const TypeInteger* type) const; + const TypeInteger* widen_type(const PhaseGVN* phase, const Type* res, BasicType bt) const; + + virtual ConstraintCastNode* make_with(Node* parent, const TypeInteger* type, const DependencyType& dependency) const { + ShouldNotReachHere(); // Only implemented for CastII and CastLL + return nullptr; + } + + Node* find_or_make_integer_cast(PhaseIterGVN* igvn, Node* parent, const TypeInteger* type, const DependencyType& dependency) const; - private: // PhiNode::Ideal() transforms a Phi that merges a single uncasted value into a single cast pinned at the region. // The types of cast nodes eliminated as a consequence of this transformation are collected and stored here so the // type dependencies carried by the cast are known. The cast can then be eliminated if the type of its input is @@ -55,7 +153,7 @@ public: const TypeTuple* _extra_types; public: - ConstraintCastNode(Node* ctrl, Node* n, const Type* t, ConstraintCastNode::DependencyType dependency, + ConstraintCastNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency, const TypeTuple* extra_types) : TypeNode(t,2), _dependency(dependency), _extra_types(extra_types) { init_class_id(Class_ConstraintCast); @@ -67,18 +165,21 @@ public: virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual int Opcode() const; virtual uint ideal_reg() const = 0; - virtual bool depends_only_on_test() const { return _dependency == RegularDependency; } - bool carry_dependency() const { return _dependency != RegularDependency; } + bool carry_dependency() const { return !_dependency.cmp(DependencyType::FloatingNarrowing); } + // A cast node depends_only_on_test if and only if it is floating + virtual bool depends_only_on_test() const { return _dependency.is_floating(); } + const DependencyType& dependency() const { return _dependency; } TypeNode* dominating_cast(PhaseGVN* gvn, PhaseTransform* pt) const; - static Node* make_cast_for_basic_type(Node* c, Node* n, const Type* t, DependencyType dependency, BasicType bt); + static Node* make_cast_for_basic_type(Node* c, Node* n, const Type* t, const DependencyType& dependency, BasicType bt); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif - static Node* make_cast_for_type(Node* c, Node* in, const Type* type, DependencyType dependency, + static Node* make_cast_for_type(Node* c, Node* in, const Type* type, const DependencyType& dependency, const TypeTuple* types); + Node* optimize_integer_cast_of_add(PhaseGVN* phase, BasicType bt); Node* optimize_integer_cast(PhaseGVN* phase, BasicType bt); bool higher_equal_types(PhaseGVN* phase, const Node* other) const; @@ -102,7 +203,7 @@ class CastIINode: public ConstraintCastNode { virtual uint size_of() const; public: - CastIINode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, bool range_check_dependency = false, const TypeTuple* types = nullptr) + CastIINode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, bool range_check_dependency = false, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types), _range_check_dependency(range_check_dependency) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastII); @@ -110,7 +211,7 @@ class CastIINode: public ConstraintCastNode { virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node* Identity(PhaseGVN* phase); - virtual const Type* Value(PhaseGVN* phase) const; + virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); bool has_range_check() const { #ifdef _LP64 @@ -122,6 +223,7 @@ class CastIINode: public ConstraintCastNode { } CastIINode* pin_array_access_node() const; + CastIINode* make_with(Node* parent, const TypeInteger* type, const DependencyType& dependency) const; void remove_range_check_cast(Compile* C); #ifndef PRODUCT @@ -131,14 +233,12 @@ class CastIINode: public ConstraintCastNode { class CastLLNode: public ConstraintCastNode { public: - CastLLNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastLLNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastLL); } - virtual const Type* Value(PhaseGVN* phase) const; - static bool is_inner_loop_backedge(ProjNode* proj); static bool cmp_used_at_inner_loop_exit_test(CmpNode* cmp); @@ -147,11 +247,12 @@ public: virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegL; } + CastLLNode* make_with(Node* parent, const TypeInteger* type, const DependencyType& dependency) const; }; class CastHHNode: public ConstraintCastNode { public: - CastHHNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastHHNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastHH); @@ -162,7 +263,7 @@ public: class CastFFNode: public ConstraintCastNode { public: - CastFFNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastFFNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastFF); @@ -173,7 +274,7 @@ public: class CastDDNode: public ConstraintCastNode { public: - CastDDNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastDDNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastDD); @@ -184,7 +285,7 @@ public: class CastVVNode: public ConstraintCastNode { public: - CastVVNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastVVNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CastVV); @@ -198,7 +299,7 @@ public: // cast pointer to pointer (different type) class CastPPNode: public ConstraintCastNode { public: - CastPPNode (Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CastPPNode (Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { init_class_id(Class_CastPP); } @@ -210,7 +311,7 @@ class CastPPNode: public ConstraintCastNode { // for _checkcast, cast pointer to pointer (different type), without JOIN, class CheckCastPPNode: public ConstraintCastNode { public: - CheckCastPPNode(Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) + CheckCastPPNode(Node* ctrl, Node* n, const Type* t, const DependencyType& dependency = DependencyType::FloatingNarrowing, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { assert(ctrl != nullptr, "control must be set"); init_class_id(Class_CheckCastPP); diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 0598f10b880..203aa69ce1b 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -2192,7 +2192,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (phi_type->isa_ptr()) { const Type* uin_type = phase->type(uin); if (!phi_type->isa_oopptr() && !uin_type->isa_oopptr()) { - cast = new CastPPNode(r, uin, phi_type, ConstraintCastNode::StrongDependency, extra_types); + cast = new CastPPNode(r, uin, phi_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing, extra_types); } else { // Use a CastPP for a cast to not null and a CheckCastPP for // a cast to a new klass (and both if both null-ness and @@ -2202,7 +2202,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { // null, uin's type must be casted to not null if (phi_type->join(TypePtr::NOTNULL) == phi_type->remove_speculative() && uin_type->join(TypePtr::NOTNULL) != uin_type->remove_speculative()) { - cast = new CastPPNode(r, uin, TypePtr::NOTNULL, ConstraintCastNode::StrongDependency, extra_types); + cast = new CastPPNode(r, uin, TypePtr::NOTNULL, ConstraintCastNode::DependencyType::NonFloatingNarrowing, extra_types); } // If the type of phi and uin, both casted to not null, @@ -2214,14 +2214,14 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { cast = phase->transform(cast); n = cast; } - cast = new CheckCastPPNode(r, n, phi_type, ConstraintCastNode::StrongDependency, extra_types); + cast = new CheckCastPPNode(r, n, phi_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing, extra_types); } if (cast == nullptr) { - cast = new CastPPNode(r, uin, phi_type, ConstraintCastNode::StrongDependency, extra_types); + cast = new CastPPNode(r, uin, phi_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing, extra_types); } } } else { - cast = ConstraintCastNode::make_cast_for_type(r, uin, phi_type, ConstraintCastNode::StrongDependency, extra_types); + cast = ConstraintCastNode::make_cast_for_type(r, uin, phi_type, ConstraintCastNode::DependencyType::NonFloatingNarrowing, extra_types); } assert(cast != nullptr, "cast should be set"); cast = phase->transform(cast); diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index bf7feeed0a2..621ba684da1 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -4582,7 +4582,7 @@ Node* Compile::constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* // node from floating above the range check during loop optimizations. Otherwise, the // ConvI2L node may be eliminated independently of the range check, causing the data path // to become TOP while the control path is still there (although it's unreachable). - value = new CastIINode(ctrl, value, itype, carry_dependency ? ConstraintCastNode::StrongDependency : ConstraintCastNode::RegularDependency, true /* range check dependency */); + value = new CastIINode(ctrl, value, itype, carry_dependency ? ConstraintCastNode::DependencyType::NonFloatingNarrowing : ConstraintCastNode::DependencyType::FloatingNarrowing, true /* range check dependency */); value = phase->transform(value); } const TypeLong* ltype = TypeLong::make(itype->_lo, itype->_hi, itype->_widen); diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index fb3b5dba42c..b067d93176a 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -748,7 +748,7 @@ Node* ConnectionGraph::specialize_castpp(Node* castpp, Node* base, Node* current _igvn->_worklist.push(current_control); _igvn->_worklist.push(control_successor); - return _igvn->transform(ConstraintCastNode::make_cast_for_type(not_eq_control, base, _igvn->type(castpp), ConstraintCastNode::UnconditionalDependency, nullptr)); + return _igvn->transform(ConstraintCastNode::make_cast_for_type(not_eq_control, base, _igvn->type(castpp), ConstraintCastNode::DependencyType::NonFloatingNonNarrowing, nullptr)); } Node* ConnectionGraph::split_castpp_load_through_phi(Node* curr_addp, Node* curr_load, Node* region, GrowableArray* bases_for_loads, GrowableArray &alloc_worklist) { @@ -1235,7 +1235,7 @@ bool ConnectionGraph::reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, No Node* nsr_merge_pointer = ophi; if (cast != nullptr) { const Type* new_t = merge_t->meet(TypePtr::NULL_PTR); - nsr_merge_pointer = _igvn->transform(ConstraintCastNode::make_cast_for_type(cast->in(0), cast->in(1), new_t, ConstraintCastNode::RegularDependency, nullptr)); + nsr_merge_pointer = _igvn->transform(ConstraintCastNode::make_cast_for_type(cast->in(0), cast->in(1), new_t, ConstraintCastNode::DependencyType::FloatingNarrowing, nullptr)); } for (uint spi = 0; spi < safepoints.size(); spi++) { @@ -1376,7 +1376,7 @@ void ConnectionGraph::reset_scalar_replaceable_entries(PhiNode* ophi) { } if (change) { - Node* new_cast = ConstraintCastNode::make_cast_for_type(out->in(0), out->in(1), out_new_t, ConstraintCastNode::StrongDependency, nullptr); + Node* new_cast = ConstraintCastNode::make_cast_for_type(out->in(0), out->in(1), out_new_t, ConstraintCastNode::DependencyType::NonFloatingNarrowing, nullptr); _igvn->replace_node(out, new_cast); _igvn->register_new_node_with_optimizer(new_cast); } diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 113530c8835..2263fa720ce 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -1183,7 +1183,7 @@ bool LibraryCallKit::inline_preconditions_checkIndex(BasicType bt) { jlong upper_bound = _gvn.type(length)->is_integer(bt)->hi_as_long(); Node* casted_length = ConstraintCastNode::make_cast_for_basic_type( control(), length, TypeInteger::make(0, upper_bound, Type::WidenMax, bt), - ConstraintCastNode::RegularDependency, bt); + ConstraintCastNode::DependencyType::FloatingNarrowing, bt); casted_length = _gvn.transform(casted_length); replace_in_map(length, casted_length); length = casted_length; @@ -1213,7 +1213,7 @@ bool LibraryCallKit::inline_preconditions_checkIndex(BasicType bt) { // index is now known to be >= 0 and < length, cast it Node* result = ConstraintCastNode::make_cast_for_basic_type( control(), index, TypeInteger::make(0, upper_bound, Type::WidenMax, bt), - ConstraintCastNode::RegularDependency, bt); + ConstraintCastNode::DependencyType::FloatingNarrowing, bt); result = _gvn.transform(result); set_result(result); replace_in_map(index, result); diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 5c65103677b..41bce0fe9b5 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1366,7 +1366,7 @@ Node *PhaseIdealLoop::clone_up_backedge_goo(Node *back_ctrl, Node *preheader_ctr // the backedge of the main or post loop is removed, a Div node won't be able to float above the zero trip guard of the // loop and can't execute even if the loop is not reached. void PhaseIdealLoop::cast_incr_before_loop(Node* incr, Node* ctrl, CountedLoopNode* loop) { - Node* castii = new CastIINode(ctrl, incr, TypeInt::INT, ConstraintCastNode::UnconditionalDependency); + Node* castii = new CastIINode(ctrl, incr, TypeInt::INT, ConstraintCastNode::DependencyType::NonFloatingNonNarrowing); register_new_node(castii, ctrl); Node* phi = loop->phi(); assert(phi->in(LoopNode::EntryControl) == incr, "replacing wrong input?"); @@ -3262,7 +3262,7 @@ bool IdealLoopTree::do_remove_empty_loop(PhaseIdealLoop *phase) { Node* cast_ii = ConstraintCastNode::make_cast_for_basic_type( cl->in(LoopNode::EntryControl), exact_limit, phase->_igvn.type(exact_limit), - ConstraintCastNode::UnconditionalDependency, T_INT); + ConstraintCastNode::DependencyType::NonFloatingNonNarrowing, T_INT); phase->register_new_node(cast_ii, cl->in(LoopNode::EntryControl)); Node* final_iv = new SubINode(cast_ii, cl->stride()); diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 03cc5cbcff6..42d3ee105f8 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -1001,7 +1001,7 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { // a negative stride). We add a CastII here to guarantee that, when the counted loop is created in a subsequent loop // opts pass, an accurate range of values for the limits is found. const TypeInt* inner_iters_actual_int_range = TypeInt::make(0, iters_limit, Type::WidenMin); - inner_iters_actual_int = new CastIINode(outer_head, inner_iters_actual_int, inner_iters_actual_int_range, ConstraintCastNode::UnconditionalDependency); + inner_iters_actual_int = new CastIINode(outer_head, inner_iters_actual_int, inner_iters_actual_int_range, ConstraintCastNode::DependencyType::NonFloatingNonNarrowing); _igvn.register_new_node_with_optimizer(inner_iters_actual_int); } else { inner_iters_actual_int = inner_iters_actual; @@ -1315,7 +1315,7 @@ bool PhaseIdealLoop::try_make_short_running_loop(IdealLoopTree* loop, jint strid register_new_node(bol, iff->in(0)); new_limit = ConstraintCastNode::make_cast_for_basic_type(new_predicate_proj, new_limit, TypeInteger::make(1, iters_limit_long, Type::WidenMin, bt), - ConstraintCastNode::UnconditionalDependency, bt); + ConstraintCastNode::DependencyType::NonFloatingNonNarrowing, bt); register_new_node(new_limit, new_predicate_proj); #ifndef PRODUCT @@ -1334,7 +1334,7 @@ bool PhaseIdealLoop::try_make_short_running_loop(IdealLoopTree* loop, jint strid const TypeLong* new_limit_t = new_limit->Value(&_igvn)->is_long(); new_limit = ConstraintCastNode::make_cast_for_basic_type(predicates.entry(), new_limit, TypeLong::make(0, new_limit_t->_hi, new_limit_t->_widen), - ConstraintCastNode::UnconditionalDependency, bt); + ConstraintCastNode::DependencyType::NonFloatingNonNarrowing, bt); register_new_node(new_limit, predicates.entry()); } else { assert(bt == T_INT && known_short_running_loop, "only CountedLoop statically known to be short running"); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index ee3f138b8af..b1422d5db20 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1174,7 +1174,7 @@ Node *PhaseIdealLoop::split_if_with_blocks_pre( Node *n ) { if ( nn ) return nn; } - if (n->is_ConstraintCast()) { + if (n->is_ConstraintCast() && n->as_ConstraintCast()->dependency().narrows_type()) { Node* dom_cast = n->as_ConstraintCast()->dominating_cast(&_igvn, this); // ConstraintCastNode::dominating_cast() uses node control input to determine domination. // Node control inputs don't necessarily agree with loop control info (due to @@ -1837,7 +1837,7 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { if (in != nullptr && ctrl_is_member(n_loop, in)) { const Type* in_t = _igvn.type(in); cast = ConstraintCastNode::make_cast_for_type(x_ctrl, in, in_t, - ConstraintCastNode::UnconditionalDependency, nullptr); + ConstraintCastNode::DependencyType::NonFloatingNonNarrowing, nullptr); } if (cast != nullptr) { Node* prev = _igvn.hash_find_insert(cast); diff --git a/src/hotspot/share/opto/macroArrayCopy.cpp b/src/hotspot/share/opto/macroArrayCopy.cpp index 0ba8ed40c37..fb4a1842a36 100644 --- a/src/hotspot/share/opto/macroArrayCopy.cpp +++ b/src/hotspot/share/opto/macroArrayCopy.cpp @@ -233,7 +233,7 @@ void PhaseMacroExpand::generate_partial_inlining_block(Node** ctrl, MergeMemNode Node* inline_block = generate_guard(ctrl, bol_le, nullptr, PROB_FAIR); Node* stub_block = *ctrl; - Node* casted_length = new CastLLNode(inline_block, length, inline_range, ConstraintCastNode::RegularDependency); + Node* casted_length = new CastLLNode(inline_block, length, inline_range, ConstraintCastNode::DependencyType::FloatingNarrowing); transform_later(casted_length); Node* mask_gen = VectorMaskGenNode::make(casted_length, type); transform_later(mask_gen); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestPushAddThruCast.java b/test/hotspot/jtreg/compiler/c2/irTests/TestPushAddThruCast.java index 7c5fa05f147..3aee78e9d6a 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestPushAddThruCast.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestPushAddThruCast.java @@ -44,13 +44,13 @@ public class TestPushAddThruCast { TestFramework.run(); } - final static int length = RANDOM.nextInt(Integer.MAX_VALUE); - final static long llength = RANDOM.nextInt(Integer.MAX_VALUE); + final static int length = RANDOM.nextInt(5, Integer.MAX_VALUE); + final static long llength = RANDOM.nextInt(2, Integer.MAX_VALUE); static int i; static long l; @Test - @IR(counts = { IRNode.CAST_II, "1" }) + @IR(counts = { IRNode.CAST_II, "2" }) public static int test1() { int j = Objects.checkIndex(i, length); int k = Objects.checkIndex(i + 1, length); @@ -67,7 +67,7 @@ public class TestPushAddThruCast { } @Test - @IR(counts = { IRNode.CAST_LL, "1" }) + @IR(counts = { IRNode.CAST_LL, "2" }) public static long test2() { long j = Objects.checkIndex(l, llength); long k = Objects.checkIndex(l + 1, llength); @@ -82,4 +82,25 @@ public class TestPushAddThruCast { throw new RuntimeException("incorrect result: " + res); } } + + // Test commoning of Casts after loop opts when they are at the same control + @Test + @IR(phase = CompilePhase.ITER_GVN1, counts = { IRNode.CAST_II, "4" }) + @IR(phase = CompilePhase.OPTIMIZE_FINISHED, counts = { IRNode.CAST_II, "2" }) + public static int test3() { + int j = Objects.checkIndex(i - 3, length); + j += Objects.checkIndex(i, length); + j += Objects.checkIndex(i - 2, length); + j += Objects.checkIndex(i - 1, length); + return j; + } + + @Run(test = "test3") + public static void test3_runner() { + i = RANDOM.nextInt(3, length - 1); + int res = test3(); + if (res != i * 4 - 6) { + throw new RuntimeException("incorrect result: " + res + " for i = " + i); + } + } } diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java index 87e87842af3..b31c1425728 100644 --- a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java +++ b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java @@ -44,7 +44,6 @@ public class TestArrayAccessAboveRCAfterRCCastIIEliminated { private static volatile int volatileField; public static void main(String[] args) { - int[] array = new int[100]; for (int i = 0; i < 20_000; i++) { test1(9, 10, 1, true); test1(9, 10, 1, false); @@ -72,6 +71,13 @@ public class TestArrayAccessAboveRCAfterRCCastIIEliminated { test12(9, 10, 1, false); test13(9, 10, 1, true); test13(9, 10, 1, false); + test14(8, 0, 1, true); + test14(8, 0, 1, false); + inlined14(0, 0); + test15(8, 0, 1, true); + test15(8, 0, 1, false); + inlined15(0, 0); + } try { test1(-1, 10, 1, true); @@ -125,6 +131,14 @@ public class TestArrayAccessAboveRCAfterRCCastIIEliminated { test13(-1, 10, 1, true); } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { } + try { + test14(Integer.MAX_VALUE, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } + try { + test15(Integer.MAX_VALUE, 10, 1, true); + } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { + } } private static void test1(int i, int j, int flag, boolean flag2) { @@ -468,6 +482,72 @@ public class TestArrayAccessAboveRCAfterRCCastIIEliminated { } } + // Range check cast type widen after loop opts causes control dependency to be lost + private static void test14(int i, int j, int flag, boolean flag2) { + int l = 0; + for (; l < 10; l++); + j = inlined14(j, l); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[10]; + newArray[i+j] = 42; // i+j in [0, 9] + float[] otherArray = new float[i+j]; // i+j in [0, max] + if (flag == 0) { + } + intField = array[otherArray.length]; + } else { + float[] newArray = new float[10]; + newArray[i+j] = 42; // i+j in [0, 9] + float[] otherArray = new float[i+j]; // i+j in [0, max] + if (flag == 0) { + } + intField = array[otherArray.length]; + } + } + + private static int inlined14(int j, int l) { + if (l == 10) { + j = 1; + } + return j; + } + + private static void test15(int i, int j, int flag, boolean flag2) { + i = Integer.max(i, Integer.MIN_VALUE + 1); + int l = 0; + for (; l < 10; l++); + j = inlined15(j, l); + int[] array = new int[10]; + notInlined(array); + if (flag == 0) { + } + if (flag2) { + float[] newArray = new float[10]; + newArray[i+j] = 42; // i+j in [0, 9] + float[] otherArray = new float[i+j]; // i+j in [0, max] + if (flag == 0) { + } + intField = array[otherArray.length]; + } else { + float[] newArray = new float[10]; + newArray[i+j] = 42; // i+j in [0, 9] + float[] otherArray = new float[i+j]; // i+j in [0, max] + if (flag == 0) { + } + intField = array[otherArray.length]; + } + } + + private static int inlined15(int j, int l) { + if (l == 10) { + j = Integer.max(j, Integer.MIN_VALUE + 10); + } + return j; + } + private static void notInlined(int[] array) { } From b60ac710bebf195972436da324983e61b51484ef Mon Sep 17 00:00:00 2001 From: Anton Seoane Ampudia Date: Wed, 10 Dec 2025 08:53:30 +0000 Subject: [PATCH 129/141] 8364490: Fatal error on large SpecTrapLimitExtraEntries value Reviewed-by: chagedorn, roland --- src/hotspot/share/runtime/globals.hpp | 1 + .../TestSpecTrapLimitExtraEntries.java | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/arguments/TestSpecTrapLimitExtraEntries.java diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 68b5d8254fd..b3e9edc0a80 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1369,6 +1369,7 @@ const int ObjectAlignmentInBytes = 8; \ product(int, SpecTrapLimitExtraEntries, 3, EXPERIMENTAL, \ "Extra method data trap entries for speculation") \ + range(0, 100) \ \ product(double, InlineFrequencyRatio, 0.25, DIAGNOSTIC, \ "Ratio of call site execution to caller method invocation") \ diff --git a/test/hotspot/jtreg/compiler/arguments/TestSpecTrapLimitExtraEntries.java b/test/hotspot/jtreg/compiler/arguments/TestSpecTrapLimitExtraEntries.java new file mode 100644 index 00000000000..83fd16ed0d9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arguments/TestSpecTrapLimitExtraEntries.java @@ -0,0 +1,40 @@ +/* + * 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 8364490 + * @summary "Hello world" sanity test for SpecTrapLimitExtraEntries + * + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:SpecTrapLimitExtraEntries=0 compiler.arguments.TestSpecTrapLimitExtraEntries + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:SpecTrapLimitExtraEntries=100 compiler.arguments.TestSpecTrapLimitExtraEntries + */ + +package compiler.arguments; + +public class TestSpecTrapLimitExtraEntries { + + public static void main(String[] args) { + System.out.println("Passed"); + } +} From 8eaeb6990b85ac8717f4fc4ce883f674017b91f3 Mon Sep 17 00:00:00 2001 From: David Briemann Date: Wed, 10 Dec 2025 10:21:42 +0000 Subject: [PATCH 130/141] 8372589: VM crashes on init when NonNMethodCodeHeapSize is set too small and UseTransparentHugePages is enabled Reviewed-by: mdoerr, chagedorn --- src/hotspot/share/code/codeCache.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index beca3bcbcf5..95a2fb908de 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -227,11 +227,6 @@ void CodeCache::initialize_heaps() { if (!non_nmethod.set) { non_nmethod.size += compiler_buffer_size; - // Further down, just before FLAG_SET_ERGO(), all segment sizes are - // aligned down to the next lower multiple of min_size. For large page - // sizes, this may result in (non_nmethod.size == 0) which is not acceptable. - // Therefore, force non_nmethod.size to at least min_size. - non_nmethod.size = MAX2(non_nmethod.size, min_size); } if (!profiled.set && !non_profiled.set) { @@ -307,11 +302,10 @@ void CodeCache::initialize_heaps() { // Note: if large page support is enabled, min_size is at least the large // page size. This ensures that the code cache is covered by large pages. - non_profiled.size += non_nmethod.size & alignment_mask(min_size); - non_profiled.size += profiled.size & alignment_mask(min_size); - non_nmethod.size = align_down(non_nmethod.size, min_size); - profiled.size = align_down(profiled.size, min_size); - non_profiled.size = align_down(non_profiled.size, min_size); + non_nmethod.size = align_up(non_nmethod.size, min_size); + profiled.size = align_up(profiled.size, min_size); + non_profiled.size = align_up(non_profiled.size, min_size); + cache_size = non_nmethod.size + profiled.size + non_profiled.size; FLAG_SET_ERGO(NonNMethodCodeHeapSize, non_nmethod.size); FLAG_SET_ERGO(ProfiledCodeHeapSize, profiled.size); From b58e3b600bb14bf7133eda0c37a4be4c82919d79 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 10 Dec 2025 12:08:53 +0000 Subject: [PATCH 131/141] 8373227: Test java/net/httpclient/http2/StreamFlowControlTest.java failed: should sleep time be raised? Reviewed-by: djelinski --- .../http2/StreamFlowControlTest.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java b/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java index 3e4ee4864f5..32f96c7ed4b 100644 --- a/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java +++ b/test/jdk/java/net/httpclient/http2/StreamFlowControlTest.java @@ -82,6 +82,9 @@ public class StreamFlowControlTest { String http2URI; String https2URI; final AtomicInteger reqid = new AtomicInteger(); + final static int WINDOW = + Integer.getInteger("jdk.httpclient.windowsize", 2 * 16 * 1024); + @DataProvider(name = "variants") @@ -147,7 +150,11 @@ public class StreamFlowControlTest { // the window is exceeded... long wait = uri.startsWith("https://") ? 800 : 500; try (InputStream is = response.body()) { - sleep(wait); + byte[] discard = new byte[WINDOW/4]; + for (int j=0; j<2; j++) { + sleep(wait); + if (is.read(discard) < 0) break; + } is.readAllBytes(); } // we could fail here if we haven't waited long enough @@ -205,7 +212,11 @@ public class StreamFlowControlTest { sent.join(); long wait = uri.startsWith("https://") ? 800 : 350; try (InputStream is = response.body()) { - sleep(wait); + byte[] discard = new byte[WINDOW/4]; + for (int j=0; j<2; j++) { + sleep(wait); + if (is.read(discard) < 0) break; + } is.readAllBytes(); } // we could fail here if we haven't waited long enough @@ -316,17 +327,16 @@ public class StreamFlowControlTest { bytes = "no request body!" .repeat(100).getBytes(StandardCharsets.UTF_8); } - int window = Integer.getInteger("jdk.httpclient.windowsize", 2 * 16 * 1024); final int maxChunkSize; if (t instanceof FCHttp2TestExchange fct) { - maxChunkSize = Math.min(window, fct.conn.getMaxFrameSize()); + maxChunkSize = Math.min(WINDOW, fct.conn.getMaxFrameSize()); } else { - maxChunkSize = Math.min(window, SettingsFrame.MAX_FRAME_SIZE); + maxChunkSize = Math.min(WINDOW, SettingsFrame.MAX_FRAME_SIZE); } byte[] resp = bytes.length <= maxChunkSize ? bytes : Arrays.copyOfRange(bytes, 0, maxChunkSize); - int max = (window / resp.length) + 2; + int max = (WINDOW / resp.length) + 2; // send in chunks t.sendResponseHeaders(200, 0); for (int i = 0; i <= max; i++) { From 655e9cda3f6b1fa3a6f0553e7745aa088dde53e8 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 10 Dec 2025 13:08:12 +0000 Subject: [PATCH 132/141] 8373335: Serial: Clean up SerialHeap members by access specifies Reviewed-by: jsikstro --- src/hotspot/share/gc/serial/serialHeap.cpp | 6 ++-- src/hotspot/share/gc/serial/serialHeap.hpp | 39 +++++++++++----------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 104924c1cad..08d730bf877 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -91,14 +91,16 @@ SerialHeap::SerialHeap() : CollectedHeap(), _young_gen(nullptr), _old_gen(nullptr), + _young_gen_saved_top(nullptr), + _old_gen_saved_top(nullptr), _rem_set(nullptr), _gc_policy_counters(new GCPolicyCounters("Copy:MSC", 2, 2)), _young_manager(nullptr), _old_manager(nullptr), - _is_heap_almost_full(false), _eden_pool(nullptr), _survivor_pool(nullptr), - _old_pool(nullptr) { + _old_pool(nullptr), + _is_heap_almost_full(false) { _young_manager = new GCMemoryManager("Copy"); _old_manager = new GCMemoryManager("MarkSweepCompact"); GCLocker::initialize(); diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index f5286179abf..36916c3f98e 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -76,6 +76,8 @@ class SerialHeap : public CollectedHeap { private: DefNewGeneration* _young_gen; TenuredGeneration* _old_gen; + + // Used during young-gc HeapWord* _young_gen_saved_top; HeapWord* _old_gen_saved_top; @@ -94,6 +96,10 @@ private: GCMemoryManager* _young_manager; GCMemoryManager* _old_manager; + MemoryPool* _eden_pool; + MemoryPool* _survivor_pool; + MemoryPool* _old_pool; + // Indicate whether heap is almost or approaching full. // Usually, there is some memory headroom for application/gc to run properly. // However, in extreme cases, e.g. young-gen is non-empty after a full gc, we @@ -113,6 +119,19 @@ private: static void verify_not_in_native_if_java_thread() NOT_DEBUG_RETURN; + // Try to allocate space by expanding the heap. + HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); + + HeapWord* mem_allocate_cas_noexpand(size_t size, bool is_tlab); + HeapWord* mem_allocate_work(size_t size, bool is_tlab); + + void initialize_serviceability() override; + + // Set the saved marks of generations, if that makes sense. + // In particular, if any generation might iterate over the oops + // in other generations, it should call this method. + void save_marks(); + public: // Returns JNI_OK on success jint initialize() override; @@ -211,26 +230,6 @@ public: // generations in a fully generational heap. CardTableRS* rem_set() { return _rem_set; } - public: - // Set the saved marks of generations, if that makes sense. - // In particular, if any generation might iterate over the oops - // in other generations, it should call this method. - void save_marks(); - -private: - // Try to allocate space by expanding the heap. - HeapWord* expand_heap_and_allocate(size_t size, bool is_tlab); - - HeapWord* mem_allocate_cas_noexpand(size_t size, bool is_tlab); - HeapWord* mem_allocate_work(size_t size, bool is_tlab); - - MemoryPool* _eden_pool; - MemoryPool* _survivor_pool; - MemoryPool* _old_pool; - - void initialize_serviceability() override; - -public: static SerialHeap* heap(); SerialHeap(); From 54430a87226096725b13f05326d08629420657ca Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Wed, 10 Dec 2025 15:14:46 +0000 Subject: [PATCH 133/141] 8373362: Http3TestServer should not log an exception stack trace when it is stopping normally Reviewed-by: jpai, djelinski --- .../test/lib/http3/Http3ServerExchange.java | 5 +++++ .../test/lib/http3/Http3TestServer.java | 19 ++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) 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 9a39ba4358d..c127abf3c0f 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 @@ -108,6 +108,11 @@ public final class Http3ServerExchange implements Http2TestExchange { rspheadersBuilder = new HttpHeadersBuilder(); } + Http3ServerConnection http3Connection() { + return serverConn; + } + + String connectionTag() { return serverConn.quicConnection().logTag(); } diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3TestServer.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3TestServer.java index ff76c67ed7e..6e81813cac3 100644 --- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3TestServer.java +++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http3/Http3TestServer.java @@ -55,6 +55,7 @@ import jdk.internal.net.http.http3.ConnectionSettings; import jdk.internal.net.http.http3.Http3Error; import jdk.internal.net.http.http3.frames.SettingsFrame; import jdk.internal.net.quic.QuicTLSContext; +import jdk.internal.net.quic.QuicTransportErrors; import jdk.internal.net.quic.QuicVersion; import static java.nio.charset.StandardCharsets.US_ASCII; @@ -261,7 +262,23 @@ public class Http3TestServer implements QuicServer.ConnectionAcceptor, AutoClose handler.handle(exchange); } catch (Throwable failure) { System.err.println("Failed to handle exchange: " + failure); - failure.printStackTrace(); + boolean noError = false; + if (exchange instanceof Http3ServerExchange http3ServerExchange) { + var quicConnection = http3ServerExchange.http3Connection().quicConnection(); + var cause = quicConnection.terminationCause(); + if (cause != null) { + var code = cause.getCloseCode(); + noError = cause.isAppLayer() + ? Http3Error.isNoError(code) + : code == QuicTransportErrors.NO_ERROR.code(); + } + } + // don't print the full stack trace if the connection + // is terminated with no error, in order to avoid + // cluttering the log. + if (!noError) { + failure.printStackTrace(); + } final var ioException = (failure instanceof IOException) ? (IOException) failure : new IOException(failure); From 11aa6e10c017a7257c60eb7395d728d32b2006d4 Mon Sep 17 00:00:00 2001 From: Fairoz Matte Date: Wed, 10 Dec 2025 18:15:32 +0000 Subject: [PATCH 134/141] 8373270: GCC 14.2.0 reports warning: '%s' directive output may be truncated Reviewed-by: kbarrett, dholmes, alanb --- .../unix/native/libjli/java_md_common.c | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/java.base/unix/native/libjli/java_md_common.c b/src/java.base/unix/native/libjli/java_md_common.c index f67a50304d0..45509c7d25d 100644 --- a/src/java.base/unix/native/libjli/java_md_common.c +++ b/src/java.base/unix/native/libjli/java_md_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -259,29 +259,6 @@ JLI_ReportExceptionDescription(JNIEnv * env) { (*env)->ExceptionDescribe(env); } -/* - * Since using the file system as a registry is a bit risky, perform - * additional sanity checks on the identified directory to validate - * it as a valid JDK. - * - * Return 0 if the tests fail; otherwise return non-zero (true). - * - * Note that checking for anything more than the existence of an - * executable object at bin/java relative to the path being checked - * will break the regression tests. - */ -static int -CheckSanity(char *path, char *dir) -{ - char buffer[PATH_MAX]; - - if (JLI_StrLen(path) + JLI_StrLen(dir) + 11 > PATH_MAX) - return (0); /* Silently reject "impossibly" long paths */ - - JLI_Snprintf(buffer, sizeof(buffer), "%s/%s/bin/java", path, dir); - return ((access(buffer, X_OK) == 0) ? 1 : 0); -} - /* * "Borrowed" from Solaris 10 where the unsetenv() function is being added * to libc thanks to SUSv3 (Standard Unix Specification, version 3). As From 413f852bdb4767b2a1c29431144616668888138d Mon Sep 17 00:00:00 2001 From: Mat Carter Date: Wed, 10 Dec 2025 18:49:30 +0000 Subject: [PATCH 135/141] 8369736: Add management interface for AOT cache creation Reviewed-by: mr, iklam, kevinw --- src/hotspot/share/cds/aotMetaspace.cpp | 1 + src/hotspot/share/include/jvm.h | 3 + src/hotspot/share/prims/jvm.cpp | 13 ++ .../classes/sun/management/VMManagement.java | 5 +- .../sun/management/VMManagementImpl.java | 5 +- .../native/libmanagement/VMManagementImpl.c | 7 ++ .../internal/HotSpotAOTCacheImpl.java | 55 ++++++++ .../internal/PlatformMBeanProviderImpl.java | 38 +++++- .../jdk/management/HotSpotAOTCacheMXBean.java | 93 ++++++++++++++ .../aotCache/HotSpotAOTCacheMXBeanTest.java | 118 ++++++++++++++++++ 10 files changed, 335 insertions(+), 3 deletions(-) create mode 100644 src/jdk.management/share/classes/com/sun/management/internal/HotSpotAOTCacheImpl.java create mode 100644 src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/aotCache/HotSpotAOTCacheMXBeanTest.java diff --git a/src/hotspot/share/cds/aotMetaspace.cpp b/src/hotspot/share/cds/aotMetaspace.cpp index f56050d4d31..3c87e3ef797 100644 --- a/src/hotspot/share/cds/aotMetaspace.cpp +++ b/src/hotspot/share/cds/aotMetaspace.cpp @@ -96,6 +96,7 @@ #include "runtime/vmOperations.hpp" #include "runtime/vmThread.hpp" #include "sanitizers/leak.hpp" +#include "services/management.hpp" #include "utilities/align.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/defaultStream.hpp" diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index dccdcacef71..7236679d8f3 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -87,6 +87,9 @@ JVM_InternString(JNIEnv *env, jstring str); /* * java.lang.System */ +JNIEXPORT jboolean JNICALL +JVM_AOTEndRecording(JNIEnv *env); + JNIEXPORT jlong JNICALL JVM_CurrentTimeMillis(JNIEnv *env, jclass ignored); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 16d9efde410..48d89235c98 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -229,6 +229,19 @@ extern void trace_class_resolution(Klass* to_class) { // java.lang.System ////////////////////////////////////////////////////////////////////// +JVM_ENTRY(jboolean, JVM_AOTEndRecording(JNIEnv *env)) +#if INCLUDE_CDS + if (CDSConfig::is_dumping_preimage_static_archive()) { + if (!AOTMetaspace::preimage_static_archive_dumped()) { + AOTMetaspace::dump_static_archive(THREAD); + return JNI_TRUE; + } + } + return JNI_FALSE; +#else + return JNI_FALSE; +#endif // INCLUDE_CDS +JVM_END JVM_LEAF(jlong, JVM_CurrentTimeMillis(JNIEnv *env, jclass ignored)) return os::javaTimeMillis(); diff --git a/src/java.management/share/classes/sun/management/VMManagement.java b/src/java.management/share/classes/sun/management/VMManagement.java index 3e227225ccd..29391cf53ba 100644 --- a/src/java.management/share/classes/sun/management/VMManagement.java +++ b/src/java.management/share/classes/sun/management/VMManagement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, 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 @@ -48,6 +48,9 @@ public interface VMManagement { public boolean isGcNotificationSupported(); public boolean isRemoteDiagnosticCommandsSupported(); + // AOT Subsystem + public boolean endAOTRecording(); + // Class Loading Subsystem public long getTotalClassCount(); public int getLoadedClassCount(); diff --git a/src/java.management/share/classes/sun/management/VMManagementImpl.java b/src/java.management/share/classes/sun/management/VMManagementImpl.java index b8c7a2921d4..0fd0d8ad562 100644 --- a/src/java.management/share/classes/sun/management/VMManagementImpl.java +++ b/src/java.management/share/classes/sun/management/VMManagementImpl.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 @@ -117,6 +117,9 @@ class VMManagementImpl implements VMManagement { public native boolean isThreadCpuTimeEnabled(); public native boolean isThreadAllocatedMemoryEnabled(); + // AOT Subsystem + public native boolean endAOTRecording(); + // Class Loading Subsystem public int getLoadedClassCount() { long count = getTotalClassCount() - getUnloadedClassCount(); diff --git a/src/java.management/share/native/libmanagement/VMManagementImpl.c b/src/java.management/share/native/libmanagement/VMManagementImpl.c index d5141c71ee7..e6570d06bdd 100644 --- a/src/java.management/share/native/libmanagement/VMManagementImpl.c +++ b/src/java.management/share/native/libmanagement/VMManagementImpl.c @@ -101,6 +101,13 @@ Java_sun_management_VMManagementImpl_getVmArguments0 return JVM_GetVmArguments(env); } +JNIEXPORT jboolean JNICALL +Java_sun_management_VMManagementImpl_endAOTRecording + (JNIEnv *env, jobject dummy) +{ + return JVM_AOTEndRecording(env); +} + JNIEXPORT jlong JNICALL Java_sun_management_VMManagementImpl_getTotalClassCount (JNIEnv *env, jobject dummy) diff --git a/src/jdk.management/share/classes/com/sun/management/internal/HotSpotAOTCacheImpl.java b/src/jdk.management/share/classes/com/sun/management/internal/HotSpotAOTCacheImpl.java new file mode 100644 index 00000000000..4bb556455ea --- /dev/null +++ b/src/jdk.management/share/classes/com/sun/management/internal/HotSpotAOTCacheImpl.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025, Microsoft, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.management.internal; + +import javax.management.ObjectName; +import jdk.management.HotSpotAOTCacheMXBean; +import sun.management.Util; +import sun.management.VMManagement; + +/** + * Implementation class for the AOT Cache subsystem. + * + * ManagementFactory.getRuntimeMXBean() returns an instance + * of this class. + */ +public class HotSpotAOTCacheImpl implements HotSpotAOTCacheMXBean { + + private final VMManagement jvm; + /** + * Constructor of HotSpotAOTCacheImpl class. + */ + HotSpotAOTCacheImpl(VMManagement vm) { + this.jvm = vm; + } + + public boolean endRecording() { + return jvm.endAOTRecording(); + } + + public ObjectName getObjectName() { + return Util.newObjectName("jdk.management:type=HotSpotAOTCache"); + } +} \ No newline at end of file diff --git a/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java b/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java index 3a64fe6b858..b000516e626 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.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 @@ -39,6 +39,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.management.DynamicMBean; +import jdk.management.HotSpotAOTCacheMXBean; import jdk.management.VirtualThreadSchedulerMXBean; import sun.management.ManagementFactoryHelper; import sun.management.spi.PlatformMBeanProvider; @@ -159,6 +160,41 @@ public final class PlatformMBeanProviderImpl extends PlatformMBeanProvider { } }); + /** + * HotSpotAOTCacheMXBean. + */ + initMBeanList.add(new PlatformComponent() { + private final Set> mbeanInterfaces = + Set.of(HotSpotAOTCacheMXBean.class); + private final Set mbeanInterfaceNames = + Set.of(HotSpotAOTCacheMXBean.class.getName()); + private HotSpotAOTCacheMXBean impl; + + @Override + public Set> mbeanInterfaces() { + return mbeanInterfaces; + } + + @Override + public Set mbeanInterfaceNames() { + return mbeanInterfaceNames; + } + + @Override + public String getObjectNamePattern() { + return "jdk.management:type=HotSpotAOTCache"; + } + + @Override + public Map nameToMBeanMap() { + HotSpotAOTCacheMXBean impl = this.impl; + if (impl == null) { + this.impl = impl = new HotSpotAOTCacheImpl(ManagementFactoryHelper.getVMManagement()); + } + return Map.of("jdk.management:type=HotSpotAOTCache", impl); + } + }); + /** * VirtualThreadSchedulerMXBean. */ diff --git a/src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java b/src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java new file mode 100644 index 00000000000..2dc02f2bd73 --- /dev/null +++ b/src/jdk.management/share/classes/jdk/management/HotSpotAOTCacheMXBean.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025, Microsoft, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.management; + +import java.lang.management.ManagementFactory; +import java.lang.management.PlatformManagedObject; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +/** + * Management interface for the JDK's Ahead of Time (AOT) Cache. + * + *

      The management interface is registered with the platform {@link MBeanServer + * MBeanServer}. The {@link ObjectName ObjectName} that uniquely identifies the management + * interface within the {@code MBeanServer} is {@code jdk.management:type=HotSpotAOTCache}. + * + *

      Direct access to the MXBean interface can be obtained with + * {@link ManagementFactory#getPlatformMXBean(Class)}. + * + * @since 26 + */ +public interface HotSpotAOTCacheMXBean extends PlatformManagedObject { + /** + * If an AOT recording is in progress, ends the recording. This method returns + * after the AOT artifacts have been completely written. + * + *

      The JVM will start recording AOT artifacts upon start-up if appropriate JVM options are + * given in the command-line. The recording will stop when the JVM exits, or when + * the {@code endRecording} method is called. Examples: + * + *

      ${@code java -XX:AOTCacheOutput=app.aot ....} + * + *

      + * The JVM records optimization information for the current application in the AOT cache file + * {@code app.aot}. In a future run of the application, the option {@code -XX:AOTCache=app.aot} will + * cause the JVM to use the cache to improve the application's startup and warmup performance. + *
      + * + *

      ${@code java -XX:AOTMode=record -XX:AOTConfiguration=app.aotconfig ....} + * + *

      + * The JVM records optimization information for the current application in the AOT configuration + * file {@code app.aotconfig}. Subsequently, an AOT cache file can be created with the command: + * + *

      ${@code java -XX:AOTMode=create -XX:AOTConfiguration=app.aotconfig -XX:AOTCache=app.aot ...} + *

      + * + *

      For more information about creating and using the AOT artifacts, and detailed + * specification of the corresponding JVM command-line options, please refer + * to JEP 483 and JEP 514. + * + *

      Currently there are no APIs to start an AOT recording. AOT recordings must be + * started using JVM command-line options such as {@code -XX:AOTCacheOutput}. + * There are also no APIs to query whether an AOT recording is in progress, or what AOT + * artifacts are being recorded. + * + *

      This method enables an application to end its own AOT recording + * programatically, but that is not necessarily the best approach. Doing so + * requires changing the application’s code, which might not be + * feasible. Even when it is feasible, injecting training-specific logic + * into the application reduces the similarity between training runs and + * production runs, potentially making the AOT cache less effective. It may + * be better to arrange for an external agent to end the training run, + * thereby creating an AOT cache without interfering with the application’s + * code. + * + * @return {@code true} if a recording was in progress and has been ended + * successfully; {@code false} otherwise. + */ + public boolean endRecording(); +} \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/HotSpotAOTCacheMXBeanTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/HotSpotAOTCacheMXBeanTest.java new file mode 100644 index 00000000000..fba3589f5ce --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/HotSpotAOTCacheMXBeanTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Microsoft, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + + +/* + * @test + * @summary Sanity test for HotSpotAOTCache MXBean + * @requires vm.cds.write.archived.java.heap + * @library /test/jdk/lib/testlibrary /test/lib + * @build HotSpotAOTCacheMXBeanTest + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar HotSpotAOTCacheMXBeanApp + * @run driver HotSpotAOTCacheMXBeanTest + */ + +import java.io.IOException; +import java.lang.management.ManagementFactory; +import javax.management.MBeanServer; +import jdk.management.HotSpotAOTCacheMXBean; +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; + +public class HotSpotAOTCacheMXBeanTest { + static final String appJar = ClassFileInstaller.getJarPath("app.jar"); + static final String mainClass = "HotSpotAOTCacheMXBeanApp"; + public static void main(String[] args) throws Exception { + Tester tester = new Tester(); + tester.runAOTWorkflow(); + } + + static class Tester extends CDSAppTester { + public Tester() { + super(mainClass); + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] vmArgs(RunMode runMode) { + return new String[] { + "-Xlog:cds+class=trace", + "--add-modules=jdk.management" + }; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, runMode.name() + }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) { + var name = runMode.name(); + if (runMode.isApplicationExecuted()) { + if(runMode == RunMode.TRAINING) { + out.shouldContain("Hello Leyden " + name); + out.shouldContain("Successfully stopped recording"); + } else if (runMode == RunMode.ASSEMBLY) { + out.shouldNotContain("Hello Leyden "); + } else if (runMode == RunMode.PRODUCTION) { + out.shouldContain("Hello Leyden " + name); + out.shouldContain("Failed to stop recording"); + } + out.shouldNotContain("HotSpotAOTCacheMXBean is not available"); + out.shouldNotContain("IOException occurred!"); + } + } + } +} + +class HotSpotAOTCacheMXBeanApp { + public static void main(String[] args) { + System.out.println("Hello Leyden " + args[0]); + try { + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + HotSpotAOTCacheMXBean aotBean = ManagementFactory.newPlatformMXBeanProxy(server, + "jdk.management:type=HotSpotAOTCache", + HotSpotAOTCacheMXBean.class); + if (aotBean == null) { + System.out.println("HotSpotAOTCacheMXBean is not available"); + return; + } + if (aotBean.endRecording()) { + System.out.println("Successfully stopped recording"); + } else { + System.out.println("Failed to stop recording"); + } + } catch (IOException e) { + System.out.println("IOException occurred!"); + } + } +} \ No newline at end of file From 52aa7fe1c970709fe387b70a5020ea0e77c4047f Mon Sep 17 00:00:00 2001 From: Phil Race Date: Wed, 10 Dec 2025 21:40:18 +0000 Subject: [PATCH 136/141] 8334549: [Sound] Test timed out: javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java Reviewed-by: aivanov, kizune --- .../sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java b/test/jdk/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java index b3198b8ab77..30f38f55acb 100644 --- a/test/jdk/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java +++ b/test/jdk/javax/sound/sampled/Clip/OpenNonIntegralNumberOfSampleframes.java @@ -32,6 +32,7 @@ import javax.sound.sampled.LineUnavailableException; /** * @test + * @key sound * @bug 8167435 */ public final class OpenNonIntegralNumberOfSampleframes { From 74dca863c2e61c13884c3454b8da7be125235970 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 10 Dec 2025 22:46:35 +0000 Subject: [PATCH 137/141] 8371718: (sc) Channels.new{Input,Output}Stream can allocate unbounded memory for a socket channel Reviewed-by: alanb --- .../sun/nio/ch/ChannelInputStream.java | 3 +- .../sun/nio/ch/ChannelOutputStream.java | 11 +++- .../classes/sun/nio/ch/NioSocketImpl.java | 12 ++-- .../classes/sun/nio/ch/SocketChannelImpl.java | 3 +- .../share/classes/sun/nio/ch/Streams.java | 6 +- .../Channels/SocketChannelStreams.java | 64 ++++++++++++++++++- 6 files changed, 83 insertions(+), 16 deletions(-) diff --git a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java index 14b2058d28d..09f6d7b1d75 100644 --- a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java +++ b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,6 +109,7 @@ class ChannelInputStream extends InputStream { if (len == 0) return 0; + len = Math.min(len, Streams.MAX_BUFFER_SIZE); ByteBuffer bb = ((this.bs == bs) ? this.bb : ByteBuffer.wrap(bs)); diff --git a/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java b/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java index dff8af9ebaf..b7207c9fd4b 100644 --- a/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java +++ b/src/java.base/share/classes/sun/nio/ch/ChannelOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, 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 @@ -64,10 +64,15 @@ class ChannelOutputStream extends OutputStream { * If the channel is selectable then it must be configured blocking. */ private void writeFully(ByteBuffer bb) throws IOException { - while (bb.remaining() > 0) { + int pos = bb.position(); + int rem = bb.limit() - pos; + while (rem > 0) { + bb.limit(pos + Math.min(Streams.MAX_BUFFER_SIZE, rem)); int n = ch.write(bb); if (n <= 0) - throw new RuntimeException("no bytes written"); + throw new IOException("Write failed"); + pos += n; + rem -= n; } } diff --git a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java index 57935ff5b00..01f894be227 100644 --- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java @@ -78,10 +78,6 @@ import static jdk.internal.util.Exceptions.formatMsg; public final class NioSocketImpl extends SocketImpl implements PlatformSocketImpl { private static final NativeDispatcher nd = new SocketDispatcher(); - // The maximum number of bytes to read/write per syscall to avoid needing - // a huge buffer from the temporary buffer cache - private static final int MAX_BUFFER_SIZE = 128 * 1024; - // true if this is a SocketImpl for a ServerSocket private final boolean server; @@ -355,8 +351,8 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp // emulate legacy behavior to return -1, even if socket is closed if (readEOF) return -1; - // read up to MAX_BUFFER_SIZE bytes - int size = Math.min(len, MAX_BUFFER_SIZE); + // read up to Streams.MAX_BUFFER_SIZE bytes + int size = Math.min(len, Streams.MAX_BUFFER_SIZE); int n = implRead(b, off, size, remainingNanos); if (n == -1) readEOF = true; @@ -453,8 +449,8 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp int pos = off; int end = off + len; while (pos < end) { - // write up to MAX_BUFFER_SIZE bytes - int size = Math.min((end - pos), MAX_BUFFER_SIZE); + // write up to Streams.MAX_BUFFER_SIZE bytes + int size = Math.min((end - pos), Streams.MAX_BUFFER_SIZE); int n = implWrite(b, pos, size); pos += n; } diff --git a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java index 6f3e8b443dc..868ed3b64bc 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -1373,6 +1373,7 @@ class SocketChannelImpl // nothing to do return 0; } + len = Math.min(len, Streams.MAX_BUFFER_SIZE); readLock.lock(); try { @@ -1469,7 +1470,7 @@ class SocketChannelImpl beginWrite(true); configureSocketNonBlockingIfVirtualThread(); while (pos < end && isOpen()) { - int size = end - pos; + int size = Math.min(end - pos, Streams.MAX_BUFFER_SIZE); int n = tryWrite(b, pos, size); while (IOStatus.okayToRetry(n) && isOpen()) { park(Net.POLLOUT); diff --git a/src/java.base/share/classes/sun/nio/ch/Streams.java b/src/java.base/share/classes/sun/nio/ch/Streams.java index 4326c9e2e0b..847fa8333e8 100644 --- a/src/java.base/share/classes/sun/nio/ch/Streams.java +++ b/src/java.base/share/classes/sun/nio/ch/Streams.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 @@ -33,6 +33,10 @@ import java.nio.channels.WritableByteChannel; * Factory methods for input/output streams based on channels. */ public class Streams { + // The maximum number of bytes to read/write per syscall to avoid needing + // a huge buffer from the temporary buffer cache + static final int MAX_BUFFER_SIZE = 128 * 1024; + private Streams() { } /** diff --git a/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java b/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java index 72c07392d7c..519de1e725f 100644 --- a/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java +++ b/test/jdk/java/nio/channels/Channels/SocketChannelStreams.java @@ -22,10 +22,10 @@ */ /* @test - * @bug 8279339 - * @run testng SocketChannelStreams + * @bug 8279339 8371718 * @summary Exercise InputStream/OutputStream returned by Channels.newXXXStream * when channel is a SocketChannel + * @run testng SocketChannelStreams */ import java.io.Closeable; @@ -35,6 +35,8 @@ import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.channels.ByteChannel; import java.nio.channels.Channels; import java.nio.channels.IllegalBlockingModeException; import java.nio.channels.ServerSocketChannel; @@ -51,6 +53,9 @@ import static org.testng.Assert.*; @Test public class SocketChannelStreams { + // Maximum size of internal temporary buffer + private static final int MAX_BUFFER_SIZE = 128*1024; + private ScheduledExecutorService executor; @BeforeClass() @@ -379,6 +384,25 @@ public class SocketChannelStreams { }); } + /** + * Test that internal buffers have at most MAX_BUFFER_SIZE bytes remaining. + */ + public void testReadLimit() throws IOException { + InputStream in = Channels.newInputStream(new TestChannel()); + byte[] b = new byte[3*MAX_BUFFER_SIZE]; + int n = in.read(b, 0, b.length); + assertEquals(n, MAX_BUFFER_SIZE); + } + + /** + * Test that internal buffers have at most MAX_BUFFER_SIZE bytes remaining. + */ + public void testWriteLimit() throws IOException { + OutputStream out = Channels.newOutputStream(new TestChannel()); + byte[] b = new byte[3*MAX_BUFFER_SIZE]; + out.write(b, 0, b.length); + } + // -- test infrastructure -- private interface ThrowingTask { @@ -477,4 +501,40 @@ public class SocketChannelStreams { private Future schedule(Runnable task, long delay) { return executor.schedule(task, delay, TimeUnit.MILLISECONDS); } + + /** + * ByteChannel that throws if more than 128k bytes remain + * in the buffer supplied for reading or writing. + */ + private static class TestChannel implements ByteChannel { + @Override + public int read(ByteBuffer bb) throws IOException { + int rem = bb.remaining(); + if (rem > MAX_BUFFER_SIZE) { + throw new IOException("too big"); + } + bb.position(bb.limit()); + return rem; + } + + @Override + public int write(ByteBuffer bb) throws IOException { + int rem = bb.remaining(); + if (rem > MAX_BUFFER_SIZE) { + throw new IOException("too big"); + } + bb.position(bb.limit()); + return rem; + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public void close() { + throw new UnsupportedOperationException(); + } + } } From 920a99faeb6e0aee445df39cf8ddd43df18345d6 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Thu, 11 Dec 2025 07:44:10 +0000 Subject: [PATCH 138/141] 8370731: Tests in vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/ failed: OutOfMemoryError Reviewed-by: sspitsyn --- .../CollectionCounters001.java | 53 +++++++++---------- .../TestDescription.java | 5 +- .../TestDescription.java | 5 +- .../TestDescription.java | 5 +- .../TestDescription.java | 5 +- 5 files changed, 38 insertions(+), 35 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters001/CollectionCounters001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters001/CollectionCounters001.java index f256a5649e5..aac6ab88246 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters001/CollectionCounters001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters001/CollectionCounters001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,9 +29,10 @@ * @summary converted from VM Testbase nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters001. * VM Testbase keywords: [monitoring] * + * @requires vm.opt.DisableExplicitGC != "true" * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm -XX:-UseGCOverheadLimit * nsk.monitoring.GarbageCollectorMXBean.CollectionCounters.CollectionCounters001.CollectionCounters001 * -testMode=directly */ @@ -60,6 +61,7 @@ import nsk.share.runner.RunParamsAware; * time. It may be false with -XX:+DisableExplicitGC. */ public class CollectionCounters001 extends MonitoringTestBase implements RunParamsAware, Initializable { + private List gcBeans; private MemoryMXBean memory; Stresser stresser; @@ -76,18 +78,21 @@ public class CollectionCounters001 extends MonitoringTestBase implements RunPara private void runOne(ExecutionController stresser) { updateCounters(); - validate(); - Algorithms.eatMemory(stresser); - if(stresser.continueExecution()) { + validate(false /* don't check gc count increases */); + int iteration = 0; + do { + System.out.println("=========== stresser iter: " + (stresser.getIteration()) + + " runOne iter: " + (++iteration) + " ==========="); + Algorithms.eatMemory(stresser); updateCounters(); - validateNonTrivial(); + validate(true); System.gc(); updateCounters(); - validateNonTrivial(); + validate(true); memory.gc(); updateCounters(); - validateNonTrivial(); - } + validate(true); + } while (stresser.continueExecution()); } public void run() { @@ -98,26 +103,20 @@ public class CollectionCounters001 extends MonitoringTestBase implements RunPara } } - private void validate() { + private void validate(boolean gcCountMustIncrease) { if (collectionCount < 0) - throw new TestFailure("collectionCount negative: " + collectionCount); + throw new TestFailure("collectionCount negative: " + collectionCount); if (collectionTime < 0) - throw new TestFailure("collectionTime negative: " + collectionTime); - if (collectionCount < collectionCountOld) + throw new TestFailure("collectionTime negative: " + collectionTime); + if (collectionTime < collectionTimeOld) + throw new TestFailure("collectionTime decreased: " + collectionTime + " -> " + collectionTimeOld); + if (!gcCountMustIncrease) { + if (collectionCount < collectionCountOld) throw new TestFailure("collectionCount decreased: " + collectionCount + " -> " + collectionCountOld); - if (collectionTime < collectionTimeOld) - throw new TestFailure("collectionTime decreased: " + collectionTime + " -> " + collectionTimeOld); - } - - private void validateNonTrivial() { - if (collectionCount < 0) - throw new TestFailure("collectionCount negative: " + collectionCount); - if (collectionTime < 0) - throw new TestFailure("collectionTime negative: " + collectionTime); - if (collectionCount <= collectionCountOld) + } else { + if (collectionCount <= collectionCountOld) throw new TestFailure("collectionCount not increased: " + collectionCount + " -> " + collectionCountOld); - if (collectionTime < collectionTimeOld) - throw new TestFailure("collection time became smaller: " + collectionTime + " -> " + collectionTimeOld); + } } private void updateCounters() { @@ -126,8 +125,8 @@ public class CollectionCounters001 extends MonitoringTestBase implements RunPara collectionCount = 0; collectionTime = 0; for (GarbageCollectorMXBean gcBean : gcBeans) { - collectionCount += gcBean.getCollectionCount(); - collectionTime += gcBean.getCollectionTime(); + collectionCount += gcBean.getCollectionCount(); + collectionTime += gcBean.getCollectionTime(); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters002/TestDescription.java index 9bfbf141d31..c331991cd68 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,9 +29,10 @@ * @summary converted from VM Testbase nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters002. * VM Testbase keywords: [monitoring] * + * @requires vm.opt.DisableExplicitGC != "true" * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm -XX:-UseGCOverheadLimit * nsk.monitoring.GarbageCollectorMXBean.CollectionCounters.CollectionCounters001.CollectionCounters001 * -testMode=server * -MBeanServer=default diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters003/TestDescription.java index 3524cfd66db..024c8d363a5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,9 +29,10 @@ * @summary converted from VM Testbase nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters003. * VM Testbase keywords: [monitoring] * + * @requires vm.opt.DisableExplicitGC != "true" * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm -XX:-UseGCOverheadLimit * nsk.monitoring.GarbageCollectorMXBean.CollectionCounters.CollectionCounters001.CollectionCounters001 * -testMode=server * -MBeanServer=custom diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters004/TestDescription.java index b215e633464..09cde45ac4f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,9 +29,10 @@ * @summary converted from VM Testbase nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters004. * VM Testbase keywords: [monitoring] * + * @requires vm.opt.DisableExplicitGC != "true" * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm -XX:-UseGCOverheadLimit * nsk.monitoring.GarbageCollectorMXBean.CollectionCounters.CollectionCounters001.CollectionCounters001 * -testMode=proxy * -MBeanServer=default diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters005/TestDescription.java index 63cccf1c268..f70f680498b 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,9 +29,10 @@ * @summary converted from VM Testbase nsk/monitoring/GarbageCollectorMXBean/CollectionCounters/CollectionCounters005. * VM Testbase keywords: [monitoring] * + * @requires vm.opt.DisableExplicitGC != "true" * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm -XX:-UseGCOverheadLimit * nsk.monitoring.GarbageCollectorMXBean.CollectionCounters.CollectionCounters001.CollectionCounters001 * -testMode=proxy * -MBeanServer=custom From b46aef88b333db8866c60c18cbf842b6cb89dacf Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 11 Dec 2025 08:17:25 +0000 Subject: [PATCH 139/141] 8371871: libSharedCloseAgent.cpp crashes VS2019 and older VS2022 compiler Reviewed-by: jvernee, mdoerr --- test/jdk/java/foreign/sharedclosejvmti/libSharedCloseAgent.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/jdk/java/foreign/sharedclosejvmti/libSharedCloseAgent.cpp b/test/jdk/java/foreign/sharedclosejvmti/libSharedCloseAgent.cpp index a82818e0280..3e7fc2e10da 100644 --- a/test/jdk/java/foreign/sharedclosejvmti/libSharedCloseAgent.cpp +++ b/test/jdk/java/foreign/sharedclosejvmti/libSharedCloseAgent.cpp @@ -102,7 +102,8 @@ Agent_OnLoad(JavaVM *vm, char *options, void *reserved) { return jni_err; } - jvmtiCapabilities capabilities{}; + jvmtiCapabilities capabilities; + memset(&capabilities, 0, sizeof(jvmtiCapabilities)); capabilities.can_generate_method_exit_events = 1; jvmtiError err = env->AddCapabilities(&capabilities); From 4b774cb46d9355015a6bfcf53b47233d6f235239 Mon Sep 17 00:00:00 2001 From: Saranya Natarajan Date: Thu, 11 Dec 2025 08:43:31 +0000 Subject: [PATCH 140/141] 8370489: Some compiler tests miss the @key randomness Reviewed-by: dfenacci, epeter, chagedorn --- .../jtreg/compiler/c2/TestMergeStores.java | 3 ++ .../c2/TestMergeStoresMemorySegment.java | 12 ++++++- .../jtreg/compiler/c2/TestMinMaxSubword.java | 1 + .../c2/aarch64/TestFloat16Replicate.java | 1 + .../compiler/c2/irTests/ModDNodeTests.java | 1 + .../compiler/c2/irTests/ModFNodeTests.java | 1 + .../c2/irTests/ModINodeIdealizationTests.java | 1 + .../c2/irTests/ModLNodeIdealizationTests.java | 1 + .../c2/irTests/TestMulNodeIdealization.java | 3 +- .../compiler/c2/irTests/TestShiftAndMask.java | 1 + .../irTests/UDivINodeIdealizationTests.java | 3 +- .../irTests/UDivLNodeIdealizationTests.java | 3 +- .../irTests/UModINodeIdealizationTests.java | 3 +- .../irTests/UModLNodeIdealizationTests.java | 3 +- .../TestDivDependentOnMainLoopGuard.java | 1 + .../jtreg/compiler/igvn/ExpressionFuzzer.java | 1 + .../TestFloat16MaxMinSpecialValues.java | 1 + .../InvariantCodeMotionReassociateAddSub.java | 1 + .../InvariantCodeMotionReassociateCmp.java | 1 + .../TestParallelIvInIntCountedLoop.java | 1 + .../loopopts/superword/MinMaxRed_Int.java | 1 + .../loopopts/superword/ReductionPerf.java | 3 +- .../loopopts/superword/TestAliasing.java | 1 + .../loopopts/superword/TestAlignVector.java | 1 + .../TestCompatibleUseDefTypeSize.java | 3 +- .../superword/TestDependencyOffsets.java | 33 +++++++++++++++++++ .../superword/TestEquivalentInvariants.java | 1 + .../loopopts/superword/TestMemorySegment.java | 1 + .../TestMemorySegmentUnalignedAddress.java | 1 + .../loopopts/superword/TestSplitPacks.java | 1 + .../jtreg/compiler/vectorapi/Test8278948.java | 3 +- .../vectorapi/TestVectorAddMulReduction.java | 1 + .../TestVectorCompressExpandBits.java | 1 + .../vectorapi/VectorMaskCastIdentityTest.java | 1 + .../compiler/vectorapi/VectorMultiplyOpt.java | 3 +- .../VectorSaturatedOperationsTest.java | 1 + .../vectorization/TestAutoVecIntMinMax.java | 1 + .../vectorization/TestEor3AArch64.java | 1 + .../vectorization/TestMacroLogicVector.java | 3 +- .../vectorization/TestVectorZeroCount.java | 12 +++---- 40 files changed, 99 insertions(+), 17 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java index 84329c4a9c8..5e6a757dd5f 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMergeStores.java +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStores.java @@ -34,6 +34,7 @@ import java.util.Random; /* * @test * @bug 8318446 8331054 8331311 8335392 8347405 + * @key randomness * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / @@ -43,6 +44,7 @@ import java.util.Random; /* * @test * @bug 8318446 8331054 8331311 8335392 8347405 + * @key randomness * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / @@ -52,6 +54,7 @@ import java.util.Random; /* * @test * @bug 8318446 8331054 8331311 8335392 8348959 8351414 + * @key randomness * @summary Test merging of consecutive stores * @modules java.base/jdk.internal.misc * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java b/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java index a5302d1b515..a275570747b 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.java +++ b/test/hotspot/jtreg/compiler/c2/TestMergeStoresMemorySegment.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 @@ -34,6 +34,7 @@ import java.lang.foreign.*; /* * @test id=byte-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment ByteArray @@ -42,6 +43,7 @@ import java.lang.foreign.*; /* * @test id=char-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment CharArray @@ -50,6 +52,7 @@ import java.lang.foreign.*; /* * @test id=short-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment ShortArray @@ -58,6 +61,7 @@ import java.lang.foreign.*; /* * @test id=int-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment IntArray @@ -66,6 +70,7 @@ import java.lang.foreign.*; /* * @test id=long-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment LongArray @@ -74,6 +79,7 @@ import java.lang.foreign.*; /* * @test id=float-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment FloatArray @@ -82,6 +88,7 @@ import java.lang.foreign.*; /* * @test id=double-array * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment DoubleArray @@ -90,6 +97,7 @@ import java.lang.foreign.*; /* * @test id=byte-buffer * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment ByteBuffer @@ -98,6 +106,7 @@ import java.lang.foreign.*; /* * @test id=byte-buffer-direct * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment ByteBufferDirect @@ -106,6 +115,7 @@ import java.lang.foreign.*; /* * @test id=native * @bug 8335392 + * @key randomness * @summary Test MergeStores optimization for MemorySegment * @library /test/lib / * @run driver compiler.c2.TestMergeStoresMemorySegment Native diff --git a/test/hotspot/jtreg/compiler/c2/TestMinMaxSubword.java b/test/hotspot/jtreg/compiler/c2/TestMinMaxSubword.java index 955aa4058f0..a7e90353f90 100644 --- a/test/hotspot/jtreg/compiler/c2/TestMinMaxSubword.java +++ b/test/hotspot/jtreg/compiler/c2/TestMinMaxSubword.java @@ -31,6 +31,7 @@ import java.util.Random; /* * @test * @bug 8294816 + * @key randomness * @summary Test Math.min/max vectorization miscompilation for integer subwords * @library /test/lib / * @requires vm.compiler2.enabled diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java index ab7808a0401..6be4286d2a0 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestFloat16Replicate.java @@ -23,6 +23,7 @@ /** * @test * @bug 8361582 +* @key randomness * @summary Ensure the correct backend replicate node is being generated for * half precision float constants on >16B SVE machines * @modules jdk.incubator.vector diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java index 3c28c936d31..7eed798871e 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModDNodeTests.java @@ -30,6 +30,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8345766 + * @key randomness * @summary Test that Ideal transformations of ModDNode are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.ModDNodeTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java index 1b5e14b4835..886efe57124 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModFNodeTests.java @@ -30,6 +30,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8345766 + * @key randomness * @summary Test that Ideal transformations of ModFNode are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.ModFNodeTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java index d19e2562779..1ba71584031 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModINodeIdealizationTests.java @@ -32,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8332268 + * @key randomness * @summary Test that Ideal transformations of ModINode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.ModINodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java index fc08ef60603..719cc596215 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/ModLNodeIdealizationTests.java @@ -32,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8267265 + * @key randomness * @summary Test that Ideal transformations of ModLNode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.ModLNodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestMulNodeIdealization.java b/test/hotspot/jtreg/compiler/c2/irTests/TestMulNodeIdealization.java index ca6d5fbe118..e0307f2eb98 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestMulNodeIdealization.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestMulNodeIdealization.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 @@ -31,6 +31,7 @@ import jdk.test.lib.Utils; /* * @test * @bug 8291336 + * @key randomness * @summary Test that transformation of multiply-by-2 is appropriately turned into additions. * @library /test/lib / * @requires vm.compiler2.enabled diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java b/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java index 2cdc6414685..1413ee0cafa 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java @@ -31,6 +31,7 @@ import java.util.Objects; /* * @test * @bug 8277850 8278949 8285793 8346664 + * @key randomness * @summary C2: optimize mask checks in counted loops * @library /test/lib / * @run driver compiler.c2.irTests.TestShiftAndMask diff --git a/test/hotspot/jtreg/compiler/c2/irTests/UDivINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/UDivINodeIdealizationTests.java index 7183e0b311a..dd135c93e0d 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/UDivINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/UDivINodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8332268 + * @key randomness * @summary Test that Ideal transformations of UDivINode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.UDivINodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/UDivLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/UDivLNodeIdealizationTests.java index a5cfc2cddc5..bc80805cabd 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/UDivLNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/UDivLNodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8332268 + * @key randomness * @summary Test that Ideal transformations of UDivLNode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.UDivLNodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/UModINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/UModINodeIdealizationTests.java index fa24033ab46..99982c70b6e 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/UModINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/UModINodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8332268 + * @key randomness * @summary Test that Ideal transformations of UModINode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.UModINodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/c2/irTests/UModLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/UModLNodeIdealizationTests.java index 93ae861cfaa..9bbded327e0 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/UModLNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/UModLNodeIdealizationTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ import compiler.lib.ir_framework.*; /* * @test * @bug 8332268 + * @key randomness * @summary Test that Ideal transformations of UModLNode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.UModLNodeIdealizationTests diff --git a/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java b/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java index a6b7a462743..27fdc6b9e34 100644 --- a/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java +++ b/test/hotspot/jtreg/compiler/controldependency/TestDivDependentOnMainLoopGuard.java @@ -24,6 +24,7 @@ /* * @test * @bug 8349139 + * @key randomness * @summary C2: Div looses dependency on condition that guarantees divisor not null in counted loop * @library /test/lib / * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestDivDependentOnMainLoopGuard::* diff --git a/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java b/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java index 40bfb2e4319..570c59f0da2 100644 --- a/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java +++ b/test/hotspot/jtreg/compiler/igvn/ExpressionFuzzer.java @@ -24,6 +24,7 @@ /* * @test * @bug 8359412 + * @key randomness * @summary Use the template framework library to generate random expressions. * @modules java.base/jdk.internal.misc * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16MaxMinSpecialValues.java b/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16MaxMinSpecialValues.java index f83ca307d84..f85297859f3 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16MaxMinSpecialValues.java +++ b/test/hotspot/jtreg/compiler/intrinsics/float16/TestFloat16MaxMinSpecialValues.java @@ -30,6 +30,7 @@ import jdk.test.lib.*; /** * @test * @bug 8352585 + * @key randomness * @library /test/lib / * @summary Add special case handling for Float16.max/min x86 backend * @modules jdk.incubator.vector diff --git a/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java b/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java index 11f37c1f7e7..e05cef8335b 100644 --- a/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java +++ b/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateAddSub.java @@ -31,6 +31,7 @@ import java.util.Random; /* * @test * @bug 8323220 + * @key randomness * @summary Test loop invariant code motion of add/sub through reassociation * @library /test/lib / * @run driver compiler.c2.loopopts.InvariantCodeMotionReassociateAddSub diff --git a/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateCmp.java b/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateCmp.java index 566e294b4bf..bf139befc98 100644 --- a/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateCmp.java +++ b/test/hotspot/jtreg/compiler/loopopts/InvariantCodeMotionReassociateCmp.java @@ -31,6 +31,7 @@ import java.util.Random; /* * @test * @bug 8323220 + * @key randomness * @summary Test loop invariant code motion for cmp nodes through reassociation * @library /test/lib / * @run driver compiler.c2.loopopts.InvariantCodeMotionReassociateCmp diff --git a/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java b/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java index 95ba9e6e795..f8abb716e42 100644 --- a/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java +++ b/test/hotspot/jtreg/compiler/loopopts/parallel_iv/TestParallelIvInIntCountedLoop.java @@ -32,6 +32,7 @@ import java.util.Random; /** * @test * @bug 8328528 + * @key randomness * @summary test the long typed parallel iv replacing transformation for int counted loop * @library /test/lib / * @requires vm.compiler2.enabled diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/MinMaxRed_Int.java b/test/hotspot/jtreg/compiler/loopopts/superword/MinMaxRed_Int.java index 4e15c0de6e9..08f5e200aa0 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/MinMaxRed_Int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/MinMaxRed_Int.java @@ -24,6 +24,7 @@ /** * @test * @bug 8302673 + * @key randomness * @summary [SuperWord] MaxReduction and MinReduction should vectorize for int * @library /test/lib / * @run driver compiler.loopopts.superword.MinMaxRed_Int diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java b/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java index 56acdd349f8..10181ab3da2 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.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 @@ -24,6 +24,7 @@ /* * @test * @bug 8074981 8302652 + * @key randomness * @summary Test SuperWord Reduction Perf. * @library /test/lib / * @run main/othervm -Xbatch diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java index 33cef6e5e6b..f5ad14871f9 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAliasing.java @@ -24,6 +24,7 @@ /* * @test * @bug 8324751 + * @key randomness * @summary Test Speculative Aliasing checks in SuperWord * @library /test/lib / * @run driver compiler.loopopts.superword.TestAliasing nCOH_nAV_ySAC diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java index 322c36c39e1..5a2d11ef2e1 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java @@ -36,6 +36,7 @@ import java.nio.ByteOrder; /* * @test id=NoAlignVector * @bug 8310190 + * @key randomness * @summary Test AlignVector with various loop init, stride, scale, invar, etc. * @modules java.base/jdk.internal.misc * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java index e6c373c4c87..0e17489e1c8 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestCompatibleUseDefTypeSize.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 @@ -35,6 +35,7 @@ import java.nio.ByteOrder; /* * @test * @bug 8325155 + * @key randomness * @summary Test some cases that vectorize after the removal of the alignment boundaries code. * Now, we instead check if use-def connections have compatible type size. * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java index e2aca036474..2678aab9c40 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java @@ -24,6 +24,7 @@ /* * @test id=vanilla-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java @@ -33,6 +34,7 @@ /* * @test id=vanilla-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @library /test/lib / * @compile ../../lib/ir_framework/TestFramework.java @@ -42,6 +44,7 @@ /* * @test id=sse4-v016-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -54,6 +57,7 @@ /* * @test id=sse4-v016-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -66,6 +70,7 @@ /* * @test id=sse4-v008-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -78,6 +83,7 @@ /* * @test id=sse4-v008-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -102,6 +108,7 @@ /* * @test id=sse4-v004-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -114,6 +121,7 @@ /* * @test id=avx1-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -126,6 +134,7 @@ /* * @test id=avx1-v032-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -138,6 +147,7 @@ /* * @test id=avx1-v016-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -150,6 +160,7 @@ /* * @test id=avx1-v016-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -162,6 +173,7 @@ /* * @test id=avx2-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -174,6 +186,7 @@ /* * @test id=avx2-v032-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -186,6 +199,7 @@ /* * @test id=avx2-v016-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -198,6 +212,7 @@ /* * @test id=avx2-v016-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -210,6 +225,7 @@ /* * @test id=avx512-v064-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -222,6 +238,7 @@ /* * @test id=avx512-v064-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -234,6 +251,7 @@ /* * @test id=avx512-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -246,6 +264,7 @@ /* * @test id=avx512-v032-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -258,6 +277,7 @@ /* * @test id=avx512bw-v064-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -270,6 +290,7 @@ /* * @test id=avx512bw-v064-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -282,6 +303,7 @@ /* * @test id=avx512bw-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -294,6 +316,7 @@ /* * @test id=avx512bw-v032-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") @@ -306,6 +329,7 @@ /* * @test id=vec-v064-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -317,6 +341,7 @@ /* * @test id=vec-v064-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -328,6 +353,7 @@ /* * @test id=vec-v032-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -339,6 +365,7 @@ /* * @test id=vec-v032-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -350,6 +377,7 @@ /* * @test id=vec-v016-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -361,6 +389,7 @@ /* * @test id=vec-v016-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -372,6 +401,7 @@ /* * @test id=vec-v008-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -383,6 +413,7 @@ /* * @test id=vec-v008-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -394,6 +425,7 @@ /* * @test id=vec-v004-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") @@ -405,6 +437,7 @@ /* * @test id=vec-v004-U * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch!="x86" & os.arch!="i386" & os.arch!="amd64" & os.arch!="x86_64") diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java index 91d1ee9666a..8677ae851cf 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestEquivalentInvariants.java @@ -35,6 +35,7 @@ import java.lang.foreign.*; /* * @test * @bug 8343685 8331659 + * @key randomness * @summary Test vectorization with various invariants that are equivalent, but not trivially so, * i.e. where the invariants have the same summands, but in a different order. * @modules java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java index a2b5434a5a2..20ba2638fc1 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegment.java @@ -34,6 +34,7 @@ import java.lang.foreign.*; /* * @test id=byte-array * @bug 8329273 + * @key randomness * @summary Test vectorization of loops over MemorySegment * @library /test/lib / * @run driver compiler.loopopts.superword.TestMemorySegment ByteArray diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java index 969014e2293..7354ba896d0 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMemorySegmentUnalignedAddress.java @@ -35,6 +35,7 @@ import java.lang.foreign.*; /* * @test id=byte-buffer-direct * @bug 8323582 + * @key randomness * @summary Test vectorization of loops over MemorySegment, with native memory where the address is not always aligned. * @library /test/lib / * @run driver compiler.loopopts.superword.TestMemorySegmentUnalignedAddress ByteBufferDirect diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java index 631b55fc65f..9a2e23e4530 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestSplitPacks.java @@ -35,6 +35,7 @@ import java.nio.ByteOrder; /* * @test * @bug 8326139 8348659 + * @key randomness * @summary Test splitting packs in SuperWord * @library /test/lib / * @run driver compiler.loopopts.superword.TestSplitPacks nCOH_nAV_ySAC diff --git a/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java b/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java index 5218e10c4af..5170c188133 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/Test8278948.java +++ b/test/hotspot/jtreg/compiler/vectorapi/Test8278948.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 @@ -33,6 +33,7 @@ import jdk.test.lib.Utils; /* * @test * @bug 8278948 + * @key randomness * @summary Intermediate integer promotion vector length encoding is calculated incorrectly on x86 * @modules jdk.incubator.vector * @library /test/lib diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java index 38a2753a7ed..ddf16ce185f 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java @@ -38,6 +38,7 @@ import jdk.test.lib.Utils; /** * @test * @bug 8320725 + * @key randomness * @library /test/lib / * @summary Verify non-strictly ordered AddReductionVF/VD and MulReductionVF/VD * nodes are generated in VectorAPI diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java index f5174b7e6dc..8889ccd0d26 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java @@ -38,6 +38,7 @@ import jdk.test.lib.Utils; /** * @test * @bug 8301012 + * @key randomness * @library /test/lib / * @requires os.arch == "aarch64" & vm.cpu.features ~= ".*sve2.*" & vm.cpu.features ~= ".*svebitperm.*" * @summary [vectorapi]: Intrinsify CompressBitsV/ExpandBitsV and add the AArch64 SVE backend implementation diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java index e66b16f053b..be9d8e6390c 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCastIdentityTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 8356760 +* @key randomness * @library /test/lib / * @summary Optimize VectorMask.fromLong for all-true/all-false cases * @modules jdk.incubator.vector diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMultiplyOpt.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMultiplyOpt.java index a48cd25e47f..a8394f41f8a 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMultiplyOpt.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMultiplyOpt.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 @@ -32,6 +32,7 @@ import java.lang.reflect.Array; /** * @test * @bug 8341137 + * @key randomness * @summary Optimize long vector multiplication using x86 VPMUL[U]DQ instruction. * @modules jdk.incubator.vector * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorSaturatedOperationsTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorSaturatedOperationsTest.java index 887c41efd48..e51e6d31cb5 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorSaturatedOperationsTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorSaturatedOperationsTest.java @@ -24,6 +24,7 @@ /** * @test * @bug 8338021 8342677 8349522 +* @key randomness * @summary Add IR validation tests for newly added saturated vector add / sub operations * @modules jdk.incubator.vector * @library /test/lib / diff --git a/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java b/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java index 6d868b48dd7..917d69876ce 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestAutoVecIntMinMax.java @@ -30,6 +30,7 @@ import jdk.test.lib.Utils; /* * @test * @bug 8288107 + * @key randomness * @summary Auto-vectorization enhancement for integer Math.max/Math.min operations * @library /test/lib / * @requires vm.compiler2.enabled diff --git a/test/hotspot/jtreg/compiler/vectorization/TestEor3AArch64.java b/test/hotspot/jtreg/compiler/vectorization/TestEor3AArch64.java index d5a3de09123..3fed3eda124 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestEor3AArch64.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestEor3AArch64.java @@ -33,6 +33,7 @@ import jdk.test.lib.Utils; /* * @test * @bug 8293488 + * @key randomness * @summary Test EOR3 Neon/SVE2 instruction for aarch64 SHA3 extension * @library /test/lib / * @requires os.arch == "aarch64" diff --git a/test/hotspot/jtreg/compiler/vectorization/TestMacroLogicVector.java b/test/hotspot/jtreg/compiler/vectorization/TestMacroLogicVector.java index d2486f0ed77..9ab5994f566 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestMacroLogicVector.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestMacroLogicVector.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,6 +24,7 @@ /** * @test * @bug 8241040 + * @key randomness * @library /test/lib * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions diff --git a/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java b/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java index c30a28c46f9..7d03bb52071 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestVectorZeroCount.java @@ -21,20 +21,20 @@ * questions. */ +package compiler.vectorization; + +import java.util.Random; +import jdk.test.lib.Utils; + /* @test * @bug 8349637 + * @key randomness * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @summary Ensure that vectorization of numberOfLeadingZeros and numberOfTrailingZeros outputs correct values * @library /test/lib / * @run main/othervm/timeout=480 compiler.vectorization.TestVectorZeroCount */ -package compiler.vectorization; - -import java.util.Random; - -import jdk.test.lib.Utils; - public class TestVectorZeroCount { private static final int SIZE = 1024; private static final Random RANDOM = Utils.getRandomInstance(); From 6a6ff876c515eba6cc89320e02dc5739d4540316 Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Thu, 11 Dec 2025 08:48:26 +0000 Subject: [PATCH 141/141] 8372860: TestCodeCacheUnloadDuringConcCycle fails on ARM32 Reviewed-by: tschatzl, shade --- .../hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java b/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java index a4fadc185d2..af746ad206d 100644 --- a/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java +++ b/test/hotspot/jtreg/gc/g1/TestCodeCacheUnloadDuringConcCycle.java @@ -140,7 +140,7 @@ class TestCodeCacheUnloadDuringConcCycleRunner { System.out.println("Compiled " + i + " classes"); } i++; - } while (i < 200); + } while (i < 1000); System.out.println("Compilation done, compiled " + i + " classes"); } catch (Throwable t) { }