From 120463dc90d717bffb2bd0d5e6b1ea707f5d1b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Wed, 25 Sep 2024 12:15:07 +0000 Subject: [PATCH 001/188] 8339541: CSS rule is not specific enough Reviewed-by: jjg --- .../internal/doclets/formats/html/resources/stylesheet.css | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index 1130f14dc35b4..97fcc91eadcfd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -360,8 +360,11 @@ main { padding:10px 20px; position:relative; } -section[id$=-description] :is(dl, ol, ul, p, div, blockquote, pre):last-child, -section[id$=-description] :is(dl, ol, ul):last-child > :is(li, dd):last-child { +/* Compensate for non-collapsing margins between element description and summary tables */ +div.horizontal-scroll > section[id$=-description] > :is(dl, ol, ul, p, div, blockquote, pre):last-child, +div.horizontal-scroll > section[id$=-description] > :last-child > :is(li, dd):last-child, +section.class-description > div.horizontal-scroll > :is(dl, ol, ul, p, div, blockquote, pre):last-child, +section.class-description > div.horizontal-scroll > :last-child > :is(li, dd):last-child { margin-bottom:4px; } dl.notes > dt { From d8790aa0489fe49b499535c31cdfb691003792ff Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Wed, 25 Sep 2024 13:04:46 +0000 Subject: [PATCH 002/188] 8340885: Desugar ZipCoder.Comparison Reviewed-by: lancea, eirbjo --- .../share/classes/java/util/zip/ZipCoder.java | 43 +++++++++---------- .../share/classes/java/util/zip/ZipFile.java | 6 +-- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipCoder.java b/src/java.base/share/classes/java/util/zip/ZipCoder.java index 6692703c1b3f0..8d4a05389eede 100644 --- a/src/java.base/share/classes/java/util/zip/ZipCoder.java +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java @@ -56,28 +56,27 @@ public static ZipCoder get(Charset charset) { } /** - * This enum represents the three possible return values for + * Constants representing the three possible return values for * {@link #compare(String, byte[], int, int, boolean)} when * this method compares a lookup name to a string encoded in the * CEN byte array. */ - enum Comparison { - /** + static final byte + /* * The lookup string is exactly equal * to the encoded string. - */ - EXACT_MATCH, - /** + */ + EXACT_MATCH = 0, + /* * The lookup string and the encoded string differs only * by the encoded string having a trailing '/' character. */ - DIRECTORY_MATCH, - /** + DIRECTORY_MATCH = 1, + /* * The lookup string and the encoded string do not match. * (They are neither an exact match or a directory match.) */ - NO_MATCH - } + NO_MATCH = 2; String toString(byte[] ba, int off, int length) { try { @@ -197,13 +196,13 @@ private CharsetEncoder encoder() { * The return values of this method are as follows: * * If the lookup name is exactly equal to the encoded string, return - * {@link Comparison#EXACT_MATCH}. + * {@link EXACT_MATCH}. * * If the parameter {@code matchDirectory} is {@code true} and the * two strings differ only by the encoded string having an extra - * trailing '/' character, then return {@link Comparison#DIRECTORY_MATCH}. + * trailing '/' character, then return {@link DIRECTORY_MATCH}. * - * Otherwise, return {@link Comparison#NO_MATCH} + * Otherwise, return {@link NO_MATCH} * * While a general implementation will need to decode bytes into a * String for comparison, this can be avoided if the String coder @@ -217,18 +216,18 @@ private CharsetEncoder encoder() { * a directory match will also be tested * */ - Comparison compare(String str, byte[] b, int off, int len, boolean matchDirectory) { + byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { String decoded = toString(b, off, len); if (decoded.startsWith(str)) { if (decoded.length() == str.length()) { - return Comparison.EXACT_MATCH; + return EXACT_MATCH; } else if (matchDirectory && decoded.length() == str.length() + 1 && decoded.endsWith("/") ) { - return Comparison.DIRECTORY_MATCH; + return DIRECTORY_MATCH; } } - return Comparison.NO_MATCH; + return NO_MATCH; } static final class UTF8ZipCoder extends ZipCoder { @@ -278,19 +277,19 @@ private boolean hasTrailingSlash(byte[] a, int end) { } @Override - Comparison compare(String str, byte[] b, int off, int len, boolean matchDirectory) { + byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { try { byte[] encoded = JLA.getBytesNoRepl(str, UTF_8.INSTANCE); int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len); if (mismatch == -1) { - return Comparison.EXACT_MATCH; + return EXACT_MATCH; } else if (matchDirectory && len == mismatch + 1 && hasTrailingSlash(b, off + len)) { - return Comparison.DIRECTORY_MATCH; + return DIRECTORY_MATCH; } else { - return Comparison.NO_MATCH; + return NO_MATCH; } } catch (CharacterCodingException e) { - return Comparison.NO_MATCH; + return NO_MATCH; } } } diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 333e3d0184976..d54e6c1e4fcb9 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1869,15 +1869,15 @@ private EntryPos getEntryPos(String name, boolean addSlash) { // Compare the lookup name with the name encoded in the CEN switch (zc.compare(name, cen, noff, nlen, addSlash)) { - case EXACT_MATCH: + case ZipCoder.EXACT_MATCH: // We found an exact match for "name" return new EntryPos(name, pos); - case DIRECTORY_MATCH: + case ZipCoder.DIRECTORY_MATCH: // We found the directory "name/" // Track its position, then continue the search for "name" dirPos = pos; break; - case NO_MATCH: + case ZipCoder.NO_MATCH: // Hash collision, continue searching } } From 083b98083136933fc51499181f85ca30a77da9e1 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Wed, 25 Sep 2024 13:12:47 +0000 Subject: [PATCH 003/188] 8340568: Incorrect escaping of single quotes when pretty-printing character literals Reviewed-by: mcimadamore --- .../com/sun/tools/javac/tree/Pretty.java | 2 +- .../tools/javac/tree/PrettyCharLiteral.java | 89 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 test/langtools/tools/javac/tree/PrettyCharLiteral.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java index e97d07b1d2bfa..919b2325ef669 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -1467,7 +1467,7 @@ public void visitLiteral(JCLiteral tree) { break; case CHAR: print('\''); - print(Convert.quote(String.valueOf((char)((Number)tree.value).intValue()))); + print(Convert.quote((char)((Number)tree.value).intValue(), true)); print('\''); break; case BOOLEAN: diff --git a/test/langtools/tools/javac/tree/PrettyCharLiteral.java b/test/langtools/tools/javac/tree/PrettyCharLiteral.java new file mode 100644 index 0000000000000..eced3209607ce --- /dev/null +++ b/test/langtools/tools/javac/tree/PrettyCharLiteral.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024, Google LLC. All rights reserved. + * 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 8340568 + * @summary Incorrect escaping of single quotes when pretty-printing character literals + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + */ + +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.tree.Pretty; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.util.Context; + +import java.io.IOException; +import java.io.StringWriter; + +public class PrettyCharLiteral { + public static void main(String... args) throws Exception { + new PrettyCharLiteral().run(); + } + + private final TreeMaker make; + + private PrettyCharLiteral() { + Context ctx = new Context(); + JavacFileManager.preRegister(ctx); + this.make = TreeMaker.instance(ctx); + } + + void run() throws Exception { + assertEquals( + prettyPrintLiteral('\''), + """ + '\\'' + """.trim()); + assertEquals( + prettyPrintLiteral('"'), + """ + '"' + """.trim()); + assertEquals( + prettyPrintLiteral("'"), + """ + "'" + """.trim()); + assertEquals( + prettyPrintLiteral("\""), + """ + "\\"" + """.trim()); + } + + private void assertEquals(String actual, String expected) { + if (!actual.equals(expected)) { + throw new AssertionError("expected: " + expected + ", actual: " + actual); + } + } + + private String prettyPrintLiteral(Object value) throws IOException { + StringWriter sw = new StringWriter(); + new Pretty(sw, true).printExpr(make.Literal(value)); + return sw.toString(); + } +} From fb703258774ca14a6a239fc6d47a37e021e6036a Mon Sep 17 00:00:00 2001 From: Leonov Kirill <91743110+kirleo2@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:18:25 +0000 Subject: [PATCH 004/188] 8338583: NMT: Malloc overhead is calculated incorrectly Reviewed-by: azafari, yan, gziemski --- src/hotspot/share/nmt/mallocHeader.hpp | 1 + src/hotspot/share/nmt/mallocTracker.hpp | 4 ++-- src/hotspot/share/nmt/memTracker.hpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/nmt/mallocHeader.hpp b/src/hotspot/share/nmt/mallocHeader.hpp index c76e61fb4b5a2..6711c2b993e6f 100644 --- a/src/hotspot/share/nmt/mallocHeader.hpp +++ b/src/hotspot/share/nmt/mallocHeader.hpp @@ -127,6 +127,7 @@ class MallocHeader { inline MallocHeader(size_t size, MemTag mem_tag, uint32_t mst_marker); + inline static size_t malloc_overhead() { return sizeof(MallocHeader) + sizeof(uint16_t); } inline size_t size() const { return _size; } inline MemTag mem_tag() const { return _mem_tag; } inline uint32_t mst_marker() const { return _mst_marker; } diff --git a/src/hotspot/share/nmt/mallocTracker.hpp b/src/hotspot/share/nmt/mallocTracker.hpp index 39d120433ef02..de30f32373edf 100644 --- a/src/hotspot/share/nmt/mallocTracker.hpp +++ b/src/hotspot/share/nmt/mallocTracker.hpp @@ -166,7 +166,7 @@ class MallocMemorySnapshot { } inline size_t malloc_overhead() const { - return _all_mallocs.count() * sizeof(MallocHeader); + return _all_mallocs.count() * MallocHeader::malloc_overhead(); } // Total malloc invocation count @@ -269,7 +269,7 @@ class MallocTracker : AllStatic { // The overhead that is incurred by switching on NMT (we need, per malloc allocation, // space for header and 16-bit footer) - static const size_t overhead_per_malloc = sizeof(MallocHeader) + sizeof(uint16_t); + static inline size_t overhead_per_malloc() { return MallocHeader::malloc_overhead(); } // Parameter name convention: // memblock : the beginning address for user data diff --git a/src/hotspot/share/nmt/memTracker.hpp b/src/hotspot/share/nmt/memTracker.hpp index 31b1e66b8a6b3..6ba1db2e7ffe6 100644 --- a/src/hotspot/share/nmt/memTracker.hpp +++ b/src/hotspot/share/nmt/memTracker.hpp @@ -72,7 +72,7 @@ class MemTracker : AllStatic { // Per-malloc overhead incurred by NMT, depending on the current NMT level static size_t overhead_per_malloc() { - return enabled() ? MallocTracker::overhead_per_malloc : 0; + return enabled() ? MallocTracker::overhead_per_malloc() : 0; } static inline void* record_malloc(void* mem_base, size_t size, MemTag mem_tag, From 0474f020bf276c761f46bc8ba0873ed90a8fd19b Mon Sep 17 00:00:00 2001 From: George Adams Date: Wed, 25 Sep 2024 16:25:23 +0000 Subject: [PATCH 005/188] 8340815: Add SECURITY.md file Reviewed-by: mr, jwaters, erikj --- SECURITY.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000000..f4c5e7e67cb46 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +# JDK Vulnerabilities + +Please follow the process outlined in the [OpenJDK Vulnerability Policy](https://openjdk.org/groups/vulnerability/report) to disclose vulnerabilities in the JDK. From 81b5f0974903accc738c07cdf7be09fa6ea8fbdd Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 25 Sep 2024 16:36:28 +0000 Subject: [PATCH 006/188] 8340946: Add vmTestbase/gc/memory/Nio/Nio.java and java/nio/Buffer/LimitDirectMemory.java to problem list Reviewed-by: liach, dcubed, alanb --- test/hotspot/jtreg/ProblemList.txt | 1 + test/jdk/ProblemList.txt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index bec3f64c7d8c2..aefe09fd3aec2 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -174,6 +174,7 @@ vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 807 vmTestbase/nsk/jvmti/InterruptThread/intrpthrd003/TestDescription.java 8288911 macosx-all vmTestbase/gc/lock/jni/jnilock002/TestDescription.java 8192647 generic-all +vmTestbase/gc/memory/Nio/Nio.java 8340728 generic-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening001.java 8148743 generic-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening002.java 8208259 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1727722335f67..36043645ca989 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -563,6 +563,8 @@ java/net/Socket/asyncClose/Race.java 8317801 aix-ppc6 # jdk_nio +java/nio/Buffer/LimitDirectMemory.java 8340728 generic-all + java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc64 java/nio/channels/Channels/SocketChannelStreams.java 8317838 aix-ppc64 From 0e0b0b0d2626cda032f1500e64f6729554e47038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Wed, 25 Sep 2024 16:36:44 +0000 Subject: [PATCH 007/188] 8340684: Reading from an input stream backed by a closed ZipFile has no test coverage Reviewed-by: lancea --- .../java/util/zip/ZipFile/ReadAfterClose.java | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 test/jdk/java/util/zip/ZipFile/ReadAfterClose.java diff --git a/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java b/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java new file mode 100644 index 0000000000000..a083daf766871 --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 8340684 + @summary Verify unspecified, but long-standing behavior when reading + from an input stream obtained using ZipFile::getInputStream after + the ZipFile has been closed. + @run junit ReadAfterClose + */ + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ReadAfterClose { + + // ZIP file used in this test + private Path zip = Path.of("read-after-close.zip"); + + /** + * Create a sample ZIP file for use by this test + * @throws IOException if an unexpected IOException occurs + */ + @BeforeEach + public void setUp() throws IOException { + byte[] content = "hello".repeat(1000).getBytes(StandardCharsets.UTF_8); + try (OutputStream out = Files.newOutputStream(zip); + ZipOutputStream zo = new ZipOutputStream(out)) { + { + zo.putNextEntry(new ZipEntry("deflated.txt")); + zo.write(content); + } + { + ZipEntry entry = new ZipEntry("stored.txt"); + entry.setMethod(ZipEntry.STORED); + CRC32 crc = new CRC32(); + crc.update(content); + entry.setCrc(crc.getValue()); + entry.setSize(content.length); + zo.putNextEntry(entry); + zo.write(content); + } + } + } + + /** + * Delete the ZIP file produced by this test + * @throws IOException if an unexpected IOException occurs + */ + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + } + + /** + * Produce arguments with a variation of stored / deflated entries, + * and read behavior before closing the ZipFile. + * @return + */ + public static Stream arguments() { + return Stream.of( + Arguments.of("stored.txt", true), + Arguments.of("stored.txt", false), + Arguments.of("deflated.txt", true), + Arguments.of("deflated.txt", false) + ); + } + /** + * Attempting to read from an InputStream obtained by ZipFile.getInputStream + * after the backing ZipFile is closed should throw IOException + * + * @throws IOException if an unexpected IOException occurs + */ + @ParameterizedTest + @MethodSource("arguments") + public void readAfterClose(String entryName, boolean readFirst) throws IOException { + // Retain a reference to an input stream backed by a closed ZipFile + InputStream in; + try (ZipFile zf = new ZipFile(zip.toFile())) { + in = zf.getInputStream(new ZipEntry(entryName)); + // Optionally consume a single byte from the stream before closing + if (readFirst) { + in.read(); + } + } + + assertThrows(IOException.class, () -> { + in.read(); + }); + } +} \ No newline at end of file From f7bc9ba552cf913eef2131b964c48f1b4b55131c Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Wed, 25 Sep 2024 16:46:49 +0000 Subject: [PATCH 008/188] 8340228: Open source couple more miscellaneous AWT tests Reviewed-by: prr --- .../EditAndPrintTest/EditAndPrintTest.java | 152 ++++++++++++++++++ .../TextField/GetTextTest/GetTextTest.java | 104 ++++++++++++ .../SetEchoCharTest3/SetEchoCharTest3.java | 65 ++++++++ 3 files changed, 321 insertions(+) create mode 100644 test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java create mode 100644 test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java create mode 100644 test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java diff --git a/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java b/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java new file mode 100644 index 0000000000000..3f161f7fcaf90 --- /dev/null +++ b/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key printer + * @bug 6255196 + * @summary Verifies the function of methods edit(java.io.File file) and + * print(java.io.File file) + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual EditAndPrintTest + */ + +import java.awt.Desktop; +import java.awt.Desktop.Action; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JPanel; + +public class EditAndPrintTest extends JPanel { + + static final String INSTRUCTIONS = """ + This test tries to edit and print a directory, which will expectedly raise IOException. + Then this test would edit and print a .txt file, which should be successful. + After test execution close the editor if it was launched by test. + If you see any EXCEPTION messages in the output press FAIL. + """; + + public EditAndPrintTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Further testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + + if (!desktop.isSupported(Action.PRINT) && !desktop.isSupported(Action.EDIT)) { + PassFailJFrame.log("Neither EDIT nor PRINT actions are supported. Nothing to test."); + PassFailJFrame.forcePass(); + } + + /* + * Part 1: print or edit a directory, which should throw an IOException. + */ + File userHome = new File(System.getProperty("user.home")); + try { + if (desktop.isSupported(Action.EDIT)) { + PassFailJFrame.log("Trying to edit " + userHome); + desktop.edit(userHome); + PassFailJFrame.log("No exception has been thrown for editing " + + "directory " + userHome.getPath()); + PassFailJFrame.log("Test failed."); + } else { + PassFailJFrame.log("Action EDIT is unsupported."); + } + } catch (IOException e) { + PassFailJFrame.log("Expected IOException is caught."); + } + + try { + if (desktop.isSupported(Action.PRINT)) { + PassFailJFrame.log("Trying to print " + userHome); + desktop.print(userHome); + PassFailJFrame.log("No exception has been thrown for printing " + + "directory " + userHome.getPath()); + PassFailJFrame.log("Test failed."); + } else { + PassFailJFrame.log("Action PRINT is unsupported.\n"); + } + } catch (IOException e) { + PassFailJFrame.log("Expected IOException is caught."); + } + + /* + * Part 2: print or edit a normal .txt file, which may succeed if there + * is associated application to print or edit the given file. It fails + * otherwise. + */ + // Create a temp .txt file for test. + String testFilePath = System.getProperty("java.io.tmpdir") + File.separator + "JDIC-test.txt"; + File testFile = null; + try { + PassFailJFrame.log("Creating temporary file."); + testFile = File.createTempFile("JDIC-test", ".txt", new File(System.getProperty("java.io.tmpdir"))); + testFile.deleteOnExit(); + FileWriter writer = new FileWriter(testFile); + writer.write("This is a temp file used to test print() method of Desktop."); + writer.flush(); + writer.close(); + } catch (java.io.IOException ioe){ + PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); + PassFailJFrame.forceFail("Failed to create temp file for testing."); + } + + try { + if (desktop.isSupported(Action.EDIT)) { + PassFailJFrame.log("Try to edit " + testFile); + desktop.edit(testFile); + PassFailJFrame.log("Succeed."); + } + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + try { + if (desktop.isSupported(Action.PRINT)) { + PassFailJFrame.log("Trying to print " + testFile); + desktop.print(testFile); + PassFailJFrame.log("Succeed."); + } + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + } + + public static void main(String args[]) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Edit and Print test") + .splitUI(EditAndPrintTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(60) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java b/test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java new file mode 100644 index 0000000000000..ab5aebc11d47a --- /dev/null +++ b/test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4100188 + * @key headful + * @summary Make sure that TextFields contain all of, + * and exactly, the text that was entered into them. + * @run main GetTextTest + */ + +import java.awt.AWTException; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Point; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.lang.reflect.InvocationTargetException; + +public class GetTextTest extends Frame implements ActionListener { + private final String s = "test string"; + private volatile String ac; + private TextField t; + private Point location; + private Dimension size; + + public void setupGUI() { + setLayout(new FlowLayout(FlowLayout.LEFT)); + + t = new TextField(s, 32); + add(new Label("Hit after text")); + add(t); + t.addActionListener(this); + setLocationRelativeTo(null); + pack(); + setVisible(true); + } + + public void actionPerformed(ActionEvent evt) { + ac = evt.getActionCommand(); + } + + public void performTest() throws AWTException, InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + location = t.getLocationOnScreen(); + size = t.getSize(); + }); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.delay(1000); + robot.waitForIdle(); + robot.mouseMove(location.x + size.width - 3, location.y + (size.height / 2)); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(1000); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.delay(1000); + if (!s.equals(ac)) { + throw new RuntimeException("Action command should be the same as text field content"); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + GetTextTest test = new GetTextTest(); + EventQueue.invokeAndWait(test::setupGUI); + try { + test.performTest(); + } finally { + EventQueue.invokeAndWait(test::dispose); + } + } +} diff --git a/test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java b/test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java new file mode 100644 index 0000000000000..10779365defc4 --- /dev/null +++ b/test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4222122 + * @summary TextField.setEchoCharacter() seems to be broken + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetEchoCharTest3 + */ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.TextField; +import java.lang.reflect.InvocationTargetException; + +public class SetEchoCharTest3 extends Frame { + static String INSTRUCTIONS = """ + Type in the text field and "*" characters should echo. + If only one "*" echoes and then the system beeps after + the second character is typed, then press Fail, otherwise press Pass. + """; + public SetEchoCharTest3() { + setLayout(new FlowLayout()); + add(new Label("Enter text:")); + TextField tf = new TextField(15); + tf.setEchoChar('*'); + add(tf); + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Set Echo Char Test 3") + .testUI(SetEchoCharTest3::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .build() + .awaitAndCheck(); + } +} From 1b2d40addfc5e32229418d29ae90fb440720479e Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Wed, 25 Sep 2024 17:19:02 +0000 Subject: [PATCH 009/188] 8340956: ProblemList 4 java/nio/channels/DatagramChannel tests on macosx-all Reviewed-by: liach, alanb, darcy, dfuchs --- test/jdk/ProblemList.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 36043645ca989..8060792a51f9a 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -569,10 +569,13 @@ java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc6 java/nio/channels/Channels/SocketChannelStreams.java 8317838 aix-ppc64 -java/nio/channels/DatagramChannel/AdaptorMulticasting.java 8308807 aix-ppc64 +java/nio/channels/DatagramChannel/AdaptorMulticasting.java 8308807,8144003 aix-ppc64,macosx-all java/nio/channels/DatagramChannel/AfterDisconnect.java 8308807 aix-ppc64 java/nio/channels/DatagramChannel/ManySourcesAndTargets.java 8264385 macosx-aarch64 java/nio/channels/DatagramChannel/Unref.java 8233437 generic-all +java/nio/channels/DatagramChannel/BasicMulticastTests.java 8144003 macosx-all +java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java 8144003 macosx-all +java/nio/channels/DatagramChannel/Promiscuous.java 8144003 macosx-all ############################################################################ From df1959fd7a57f11839d58858bab4ea61f5b2bb8d Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 25 Sep 2024 18:29:30 +0000 Subject: [PATCH 010/188] 8340838: Clean up MutableCallSite to use explicit release fence instead of AtomicInteger Reviewed-by: jrose, redestad, shade --- .../share/classes/java/lang/invoke/MutableCallSite.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java index 50ba77d8f96f9..65872e360a73f 100644 --- a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,8 @@ package java.lang.invoke; import java.util.Objects; -import java.util.concurrent.atomic.AtomicInteger; + +import static java.lang.invoke.MethodHandleStatics.UNSAFE; /** * A {@code MutableCallSite} is a {@link CallSite} whose target variable @@ -274,11 +275,10 @@ public final MethodHandle dynamicInvoker() { */ public static void syncAll(MutableCallSite[] sites) { if (sites.length == 0) return; - STORE_BARRIER.lazySet(0); + UNSAFE.storeFence(); for (MutableCallSite site : sites) { Objects.requireNonNull(site); // trigger NPE on first null } // FIXME: NYI } - private static final AtomicInteger STORE_BARRIER = new AtomicInteger(); } From 84751cbfddf69bd9ed6bc5c39f8e056009440331 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 25 Sep 2024 18:31:24 +0000 Subject: [PATCH 011/188] 8340831: Simplify simple validation for class definition in MethodHandles.Lookup Reviewed-by: redestad --- .../java/lang/invoke/MethodHandles.java | 185 ++++++++---------- .../share/classes/jdk/internal/misc/VM.java | 28 +-- 2 files changed, 85 insertions(+), 128 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 6a73266ae80a4..9e292373f9caf 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -39,7 +39,9 @@ import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; +import java.lang.classfile.ClassFile; import java.lang.classfile.ClassModel; +import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.invoke.LambdaForm.BasicType; import java.lang.invoke.MethodHandleImpl.Intrinsic; @@ -2242,85 +2244,70 @@ private static ClassFileDumper defaultDumper() { private static final ClassFileDumper DEFAULT_DUMPER = ClassFileDumper.getInstance( "jdk.invoke.MethodHandle.dumpClassFiles", "DUMP_CLASS_FILES"); - static class ClassFile { - final String name; // internal name - final int accessFlags; - final byte[] bytes; - ClassFile(String name, int accessFlags, byte[] bytes) { - this.name = name; - this.accessFlags = accessFlags; - this.bytes = bytes; + /** + * This method checks the class file version and the structure of `this_class`. + * and checks if the bytes is a class or interface (ACC_MODULE flag not set) + * that is in the named package. + * + * @throws IllegalArgumentException if ACC_MODULE flag is set in access flags + * or the class is not in the given package name. + */ + static String validateAndFindInternalName(byte[] bytes, String pkgName) { + int magic = readInt(bytes, 0); + if (magic != ClassFile.MAGIC_NUMBER) { + throw new ClassFormatError("Incompatible magic value: " + magic); } + // We have to read major and minor this way as ClassFile API throws IAE + // yet we want distinct ClassFormatError and UnsupportedClassVersionError + int minor = readUnsignedShort(bytes, 4); + int major = readUnsignedShort(bytes, 6); - static ClassFile newInstanceNoCheck(String name, byte[] bytes) { - return new ClassFile(name, 0, bytes); + if (!VM.isSupportedClassFileVersion(major, minor)) { + throw new UnsupportedClassVersionError("Unsupported class file version " + major + "." + minor); } - /** - * This method checks the class file version and the structure of `this_class`. - * and checks if the bytes is a class or interface (ACC_MODULE flag not set) - * that is in the named package. - * - * @throws IllegalArgumentException if ACC_MODULE flag is set in access flags - * or the class is not in the given package name. - */ - static ClassFile newInstance(byte[] bytes, String pkgName) { - var cf = readClassFile(bytes); - - // check if it's in the named package - int index = cf.name.lastIndexOf('/'); - String pn = (index == -1) ? "" : cf.name.substring(0, index).replace('/', '.'); - if (!pn.equals(pkgName)) { - throw newIllegalArgumentException(cf.name + " not in same package as lookup class"); - } - return cf; + String name; + ClassDesc sym; + int accessFlags; + try { + ClassModel cm = ClassFile.of().parse(bytes); + var thisClass = cm.thisClass(); + name = thisClass.asInternalName(); + sym = thisClass.asSymbol(); + accessFlags = cm.flags().flagsMask(); + } catch (IllegalArgumentException e) { + ClassFormatError cfe = new ClassFormatError(); + cfe.initCause(e); + throw cfe; + } + // must be a class or interface + if ((accessFlags & ACC_MODULE) != 0) { + throw newIllegalArgumentException("Not a class or interface: ACC_MODULE flag is set"); } - private static ClassFile readClassFile(byte[] bytes) { - int magic = readInt(bytes, 0); - if (magic != 0xCAFEBABE) { - throw new ClassFormatError("Incompatible magic value: " + magic); - } - int minor = readUnsignedShort(bytes, 4); - int major = readUnsignedShort(bytes, 6); - if (!VM.isSupportedClassFileVersion(major, minor)) { - throw new UnsupportedClassVersionError("Unsupported class file version " + major + "." + minor); - } - - String name; - int accessFlags; - try { - ClassModel cm = java.lang.classfile.ClassFile.of().parse(bytes); - name = cm.thisClass().asInternalName(); - accessFlags = cm.flags().flagsMask(); - } catch (IllegalArgumentException e) { - ClassFormatError cfe = new ClassFormatError(); - cfe.initCause(e); - throw cfe; - } - // must be a class or interface - if ((accessFlags & ACC_MODULE) != 0) { - throw newIllegalArgumentException("Not a class or interface: ACC_MODULE flag is set"); - } - return new ClassFile(name, accessFlags, bytes); + String pn = sym.packageName(); + if (!pn.equals(pkgName)) { + throw newIllegalArgumentException(name + " not in same package as lookup class"); } - private static int readInt(byte[] bytes, int offset) { - if ((offset+4) > bytes.length) { - throw new ClassFormatError("Invalid ClassFile structure"); - } - return ((bytes[offset] & 0xFF) << 24) - | ((bytes[offset + 1] & 0xFF) << 16) - | ((bytes[offset + 2] & 0xFF) << 8) - | (bytes[offset + 3] & 0xFF); + return name; + } + + private static int readInt(byte[] bytes, int offset) { + if ((offset + 4) > bytes.length) { + throw new ClassFormatError("Invalid ClassFile structure"); } + return ((bytes[offset] & 0xFF) << 24) + | ((bytes[offset + 1] & 0xFF) << 16) + | ((bytes[offset + 2] & 0xFF) << 8) + | (bytes[offset + 3] & 0xFF); + } - private static int readUnsignedShort(byte[] bytes, int offset) { - if ((offset+2) > bytes.length) { - throw new ClassFormatError("Invalid ClassFile structure"); - } - return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF); + private static int readUnsignedShort(byte[] bytes, int offset) { + if ((offset+2) > bytes.length) { + throw new ClassFormatError("Invalid ClassFile structure"); } + return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF); } /* @@ -2334,23 +2321,22 @@ private static int readUnsignedShort(byte[] bytes, int offset) { * {@code bytes} denotes a class in a different package than the lookup class */ private ClassDefiner makeClassDefiner(byte[] bytes) { - ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return new ClassDefiner(this, cf, STRONG_LOADER_LINK, defaultDumper()); + var internalName = validateAndFindInternalName(bytes, lookupClass().getPackageName()); + return new ClassDefiner(this, internalName, bytes, STRONG_LOADER_LINK, defaultDumper()); } /** * Returns a ClassDefiner that creates a {@code Class} object of a normal class * from the given bytes. No package name check on the given bytes. * - * @param name internal name + * @param internalName internal name * @param bytes class bytes * @param dumper dumper to write the given bytes to the dumper's output directory * @return ClassDefiner that defines a normal class of the given bytes. */ - ClassDefiner makeClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) { + ClassDefiner makeClassDefiner(String internalName, byte[] bytes, ClassFileDumper dumper) { // skip package name validation - ClassFile cf = ClassFile.newInstanceNoCheck(name, bytes); - return new ClassDefiner(this, cf, STRONG_LOADER_LINK, dumper); + return new ClassDefiner(this, internalName, bytes, STRONG_LOADER_LINK, dumper); } /** @@ -2368,8 +2354,8 @@ ClassDefiner makeClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) * {@code bytes} denotes a class in a different package than the lookup class */ ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) { - ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return makeHiddenClassDefiner(cf, false, dumper, 0); + var internalName = validateAndFindInternalName(bytes, lookupClass().getPackageName()); + return makeHiddenClassDefiner(internalName, bytes, false, dumper, 0); } /** @@ -2391,51 +2377,53 @@ ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) { private ClassDefiner makeHiddenClassDefiner(byte[] bytes, boolean accessVmAnnotations, int flags) { - ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return makeHiddenClassDefiner(cf, accessVmAnnotations, defaultDumper(), flags); + var internalName = validateAndFindInternalName(bytes, lookupClass().getPackageName()); + return makeHiddenClassDefiner(internalName, bytes, accessVmAnnotations, defaultDumper(), flags); } /** * Returns a ClassDefiner that creates a {@code Class} object of a hidden class * from the given bytes and the given options. No package name check on the given bytes. * - * @param name internal name that specifies the prefix of the hidden class + * @param internalName internal name that specifies the prefix of the hidden class * @param bytes class bytes * @param dumper dumper to write the given bytes to the dumper's output directory * @return ClassDefiner that defines a hidden class of the given bytes and options. */ - ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) { + ClassDefiner makeHiddenClassDefiner(String internalName, byte[] bytes, ClassFileDumper dumper) { Objects.requireNonNull(dumper); // skip name and access flags validation - return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), false, dumper, 0); + return makeHiddenClassDefiner(internalName, bytes, false, dumper, 0); } /** * Returns a ClassDefiner that creates a {@code Class} object of a hidden class * from the given bytes and the given options. No package name check on the given bytes. * - * @param name internal name that specifies the prefix of the hidden class + * @param internalName internal name that specifies the prefix of the hidden class * @param bytes class bytes * @param flags class options flag mask * @param dumper dumper to write the given bytes to the dumper's output directory * @return ClassDefiner that defines a hidden class of the given bytes and options. */ - ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, ClassFileDumper dumper, int flags) { + ClassDefiner makeHiddenClassDefiner(String internalName, byte[] bytes, ClassFileDumper dumper, int flags) { Objects.requireNonNull(dumper); // skip name and access flags validation - return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), false, dumper, flags); + return makeHiddenClassDefiner(internalName, bytes, false, dumper, flags); } /** * Returns a ClassDefiner that creates a {@code Class} object of a hidden class * from the given class file and options. * - * @param cf ClassFile + * @param internalName internal name + * @param bytes Class byte array * @param flags class option flag mask * @param accessVmAnnotations true to give the hidden class access to VM annotations * @param dumper dumper to write the given bytes to the dumper's output directory */ - private ClassDefiner makeHiddenClassDefiner(ClassFile cf, + private ClassDefiner makeHiddenClassDefiner(String internalName, + byte[] bytes, boolean accessVmAnnotations, ClassFileDumper dumper, int flags) { @@ -2446,27 +2434,12 @@ private ClassDefiner makeHiddenClassDefiner(ClassFile cf, flags |= ACCESS_VM_ANNOTATIONS; } - return new ClassDefiner(this, cf, flags, dumper); + return new ClassDefiner(this, internalName, bytes, flags, dumper); } - static class ClassDefiner { - private final Lookup lookup; - private final String name; // internal name - private final byte[] bytes; - private final int classFlags; - private final ClassFileDumper dumper; - - private ClassDefiner(Lookup lookup, ClassFile cf, int flags, ClassFileDumper dumper) { - assert ((flags & HIDDEN_CLASS) != 0 || (flags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK); - this.lookup = lookup; - this.bytes = cf.bytes; - this.name = cf.name; - this.classFlags = flags; - this.dumper = dumper; - } - - String internalName() { - return name; + record ClassDefiner(Lookup lookup, String internalName, byte[] bytes, int classFlags, ClassFileDumper dumper) { + ClassDefiner { + assert ((classFlags & HIDDEN_CLASS) != 0 || (classFlags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK); } Class defineClass(boolean initialize) { @@ -2495,7 +2468,7 @@ Class defineClass(boolean initialize, Object classData) { Class c = null; try { c = SharedSecrets.getJavaLangAccess() - .defineClass(loader, lookupClass, name, bytes, pd, initialize, classFlags, classData); + .defineClass(loader, lookupClass, internalName, bytes, pd, initialize, classFlags, classData); assert !isNestmate() || c.getNestHost() == lookupClass.getNestHost(); return c; } finally { diff --git a/src/java.base/share/classes/jdk/internal/misc/VM.java b/src/java.base/share/classes/jdk/internal/misc/VM.java index de6f011fe8ffd..1c31ef5a184e2 100644 --- a/src/java.base/share/classes/jdk/internal/misc/VM.java +++ b/src/java.base/share/classes/jdk/internal/misc/VM.java @@ -28,6 +28,7 @@ import static java.lang.Thread.State.*; import java.io.PrintStream; +import java.lang.classfile.ClassFile; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -158,10 +159,6 @@ public static boolean isDirectMemoryPageAligned() { return pageAlignDirectMemory; } - private static int classFileMajorVersion; - private static int classFileMinorVersion; - private static final int PREVIEW_MINOR_VERSION = 65535; - /** * Tests if the given version is a supported {@code class} * file version. @@ -175,11 +172,11 @@ public static boolean isDirectMemoryPageAligned() { * @jvms 4.1 Table 4.1-A. class file format major versions */ public static boolean isSupportedClassFileVersion(int major, int minor) { - if (major < 45 || major > classFileMajorVersion) return false; + if (major < ClassFile.JAVA_1_VERSION || major > ClassFile.latestMajorVersion()) return false; // for major version is between 45 and 55 inclusive, the minor version may be any value - if (major < 56) return true; + if (major < ClassFile.JAVA_12_VERSION) return true; // otherwise, the minor version must be 0 or 65535 - return minor == 0 || minor == PREVIEW_MINOR_VERSION; + return minor == 0 || (minor == ClassFile.PREVIEW_MINOR_VERSION && major == ClassFile.latestMajorVersion()); } /** @@ -189,12 +186,8 @@ public static boolean isSupportedClassFileVersion(int major, int minor) { * major.minor version >= 53.0 */ public static boolean isSupportedModuleDescriptorVersion(int major, int minor) { - if (major < 53 || major > classFileMajorVersion) return false; - // for major version is between 45 and 55 inclusive, the minor version may be any value - if (major < 56) return true; - // otherwise, the minor version must be 0 or 65535 - // preview features do not apply to module-info.class but JVMS allows it - return minor == 0 || minor == PREVIEW_MINOR_VERSION; + if (major < ClassFile.JAVA_9_VERSION) return false; + return isSupportedClassFileVersion(major, minor); } /** @@ -271,15 +264,6 @@ public static void saveProperties(Map props) { s = props.get("sun.nio.PageAlignDirectMemory"); if ("true".equals(s)) pageAlignDirectMemory = true; - - s = props.get("java.class.version"); - int index = s.indexOf('.'); - try { - classFileMajorVersion = Integer.parseInt(s.substring(0, index)); - classFileMinorVersion = Integer.parseInt(s.substring(index + 1)); - } catch (NumberFormatException e) { - throw new InternalError(e); - } } // Initialize any miscellaneous operating system settings that need to be From 8f756196b430af67a8e31a13811a183d52df8497 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 25 Sep 2024 18:51:16 +0000 Subject: [PATCH 012/188] 8340864: Remove unused lines related to vmClasses Reviewed-by: shade, kvn --- src/hotspot/share/classfile/systemDictionary.hpp | 7 ------- src/hotspot/share/classfile/vmClasses.cpp | 10 ---------- src/hotspot/share/classfile/vmClasses.hpp | 4 +--- 3 files changed, 1 insertion(+), 20 deletions(-) diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index ee50aa38dd0cf..04980291716c7 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -293,13 +293,6 @@ class SystemDictionary : AllStatic { const char* message); static const char* find_nest_host_error(const constantPoolHandle& pool, int which); -protected: - static InstanceKlass* _well_known_klasses[]; - -private: - // table of box klasses (int_klass, etc.) - static InstanceKlass* _box_klasses[T_VOID+1]; - static OopHandle _java_system_loader; static OopHandle _java_platform_loader; diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index 0b9b437c67b78..b62d699dfe20e 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -45,14 +45,6 @@ InstanceKlass* vmClasses::_klasses[static_cast(vmClassID::LIMIT)] = { nullptr /*, nullptr...*/ }; InstanceKlass* vmClasses::_box_klasses[T_VOID+1] = { nullptr /*, nullptr...*/ }; - -// CDS: scan and relocate all classes referenced by _klasses[]. -void vmClasses::metaspace_pointers_do(MetaspaceClosure* it) { - for (auto id : EnumRange{}) { - it->push(klass_addr_at(id)); - } -} - bool vmClasses::is_loaded(InstanceKlass* klass) { return klass != nullptr && klass->is_loaded(); } @@ -205,8 +197,6 @@ void vmClasses::resolve_all(TRAPS) { _box_klasses[T_SHORT] = vmClasses::Short_klass(); _box_klasses[T_INT] = vmClasses::Integer_klass(); _box_klasses[T_LONG] = vmClasses::Long_klass(); - //_box_klasses[T_OBJECT] = vmClasses::object_klass(); - //_box_klasses[T_ARRAY] = vmClasses::object_klass(); #ifdef ASSERT if (CDSConfig::is_using_archive()) { diff --git a/src/hotspot/share/classfile/vmClasses.hpp b/src/hotspot/share/classfile/vmClasses.hpp index f2b8c5666eeb1..4fa078c50cd80 100644 --- a/src/hotspot/share/classfile/vmClasses.hpp +++ b/src/hotspot/share/classfile/vmClasses.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ class ClassLoaderData; class InstanceKlass; -class MetaspaceClosure; class vmClasses : AllStatic { friend class VMStructs; @@ -95,7 +94,6 @@ class vmClasses : AllStatic { return &_klasses[as_int(id)]; } - static void metaspace_pointers_do(MetaspaceClosure* it); static void resolve_all(TRAPS); static BasicType box_klass_type(Klass* k); // inverse of box_klass From 66f1639846645f1d3b4096ef6d62f2b301cf7ed2 Mon Sep 17 00:00:00 2001 From: Alisen Chung Date: Thu, 26 Sep 2024 01:16:13 +0000 Subject: [PATCH 013/188] 8339271: giflib attribution correction Reviewed-by: dnguyen, prr --- src/java.desktop/share/legal/giflib.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/java.desktop/share/legal/giflib.md b/src/java.desktop/share/legal/giflib.md index 8b8fde8706d92..5697dc7ca9ab2 100644 --- a/src/java.desktop/share/legal/giflib.md +++ b/src/java.desktop/share/legal/giflib.md @@ -23,8 +23,13 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +--------------------------------- +The below applies to the following file(s): +giflib/openbsd-reallocarray.c + +Copyright (C) 2008 Otto Moerbeek +SPDX-License-Identifier: MIT -tree/README == Authors == @@ -38,13 +43,4 @@ former maintainer Eric Raymond current as well as long time former maintainer of giflib code -There have been many other contributors; see the attributions in the -version-control history to learn more. - - -tree/openbsd-reallocarray.c - -Copyright (C) 2008 Otto Moerbeek -SPDX-License-Identifier: MIT - ``` From 47c10694c66bc131c8a5e1572340415b8daaba08 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Thu, 26 Sep 2024 06:03:29 +0000 Subject: [PATCH 014/188] 8340812: LambdaForm customization via MethodHandle::updateForm is not thread safe Reviewed-by: liach, shade, jvernee --- .../java/lang/invoke/MethodHandle.java | 5 +- .../invoke/TestLambdaFormCustomization.java | 70 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 test/jdk/java/lang/invoke/TestLambdaFormCustomization.java diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index edcecce37e05d..104248c27e61a 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1879,8 +1879,7 @@ void updateForm(Function updater) { if (oldForm != newForm) { assert (newForm.customized == null || newForm.customized == this); newForm.prepare(); // as in MethodHandle. - UNSAFE.putReference(this, FORM_OFFSET, newForm); - UNSAFE.fullFence(); + UNSAFE.putReferenceRelease(this, FORM_OFFSET, newForm); // properly publish newForm } } finally { updateInProgress = false; diff --git a/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java b/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java new file mode 100644 index 0000000000000..60ba4af590e78 --- /dev/null +++ b/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.ArrayList; + +/** + * @test + * @bug 8340812 + * @summary Verify that LambdaForm customization via MethodHandle::updateForm is thread safe. + * @run main TestLambdaFormCustomization + * @run main/othervm -Djava.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD=0 TestLambdaFormCustomization + */ +public class TestLambdaFormCustomization { + + String str = "test"; + static final String value = "test" + 42; + + // Trigger concurrent LambdaForm customization for VarHandle invokers + void test() throws NoSuchFieldException, IllegalAccessException { + VarHandle varHandle = MethodHandles.lookup().in(getClass()).findVarHandle(getClass(), "str", String.class); + + ArrayList threads = new ArrayList<>(); + for (int threadIdx = 0; threadIdx < 10; threadIdx++) { + threads.add(new Thread(() -> { + for (int i = 0; i < 1000; i++) { + varHandle.compareAndExchange(this, value, value); + varHandle.compareAndExchange(this, value, value); + varHandle.compareAndExchange(this, value, value); + } + })); + } + threads.forEach(Thread::start); + threads.forEach(t -> { + try { + t.join(); + } catch (Throwable e) { + throw new IllegalStateException(e); + } + }); + } + + public static void main(String[] args) throws Exception { + TestLambdaFormCustomization t = new TestLambdaFormCustomization(); + for (int i = 0; i < 4000; ++i) { + t.test(); + } + } +} From 8c8f0d85ce30e45c34d4b096f7f1430cd9e7fd70 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Thu, 26 Sep 2024 06:34:18 +0000 Subject: [PATCH 015/188] 8339260: Move rarely used constants out of ClassFile Reviewed-by: asotona --- .../java/lang/classfile/AnnotationValue.java | 69 +- .../java/lang/classfile/ClassFile.java | 874 +----------------- .../classes/java/lang/classfile/Opcode.java | 433 ++++----- .../java/lang/classfile/TypeAnnotation.java | 214 ++++- .../attribute/CharacterRangeInfo.java | 23 +- .../attribute/StackMapFrameInfo.java | 50 +- .../classfile/constantpool/PoolEntry.java | 55 ++ .../classfile/instruction/CharacterRange.java | 49 +- .../classfile/impl/AbstractInstruction.java | 4 +- .../classfile/impl/AbstractPoolEntry.java | 53 +- .../classfile/impl/AnnotationImpl.java | 28 +- .../classfile/impl/AnnotationReader.java | 83 +- .../classfile/impl/BytecodeHelpers.java | 2 +- .../classfile/impl/ClassHierarchyImpl.java | 9 +- .../classfile/impl/ClassPrinterImpl.java | 28 +- .../classfile/impl/ClassReaderImpl.java | 52 +- .../jdk/internal/classfile/impl/CodeImpl.java | 2 +- .../classfile/impl/DirectClassBuilder.java | 4 +- .../classfile/impl/DirectCodeBuilder.java | 8 +- .../classfile/impl/RawBytecodeHelper.java | 208 ++++- .../classfile/impl/SplitConstantPool.java | 44 +- .../internal/classfile/impl/StackCounter.java | 10 +- .../classfile/impl/StackMapDecoder.java | 40 +- .../classfile/impl/StackMapGenerator.java | 9 +- .../classfile/impl/TargetInfoImpl.java | 14 +- .../impl/verifier/VerificationBytecodes.java | 478 +++++----- .../classfile/impl/verifier/VerifierImpl.java | 479 +++++----- .../com/sun/tools/javap/AttributeWriter.java | 33 +- .../com/sun/tools/javap/ClassWriter.java | 4 +- .../com/sun/tools/javap/ConstantWriter.java | 27 +- .../com/sun/tools/javap/StackMapWriter.java | 14 +- .../plugins/IncludeLocalesPlugin.java | 16 +- .../internal/plugins/StringSharingPlugin.java | 8 +- test/jdk/jdk/classfile/LimitsTest.java | 7 +- test/jdk/jdk/classfile/StackMapsTest.java | 4 +- test/jdk/jdk/classfile/VerifierSelfTest.java | 3 +- .../jdk/classfile/helpers/ClassRecord.java | 23 +- 37 files changed, 1545 insertions(+), 1916 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index c4474a248b520..50bfa0b7aa6fb 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -60,7 +60,7 @@ public sealed interface AnnotationValue { /** * Models an annotation value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ANNOTATION}. + * The {@linkplain #tag tag} of this value is {@value TAG_ANNOTATION}. * * @since 22 */ @@ -73,7 +73,7 @@ sealed interface OfAnnotation extends AnnotationValue /** * Models an array value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ARRAY}. + * The {@linkplain #tag tag} of this value is {@value TAG_ARRAY}. * * @since 22 */ @@ -131,7 +131,7 @@ sealed interface OfConstant extends AnnotationValue { /** * Models a string value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_STRING}. + * The {@linkplain #tag tag} of this value is {@value TAG_STRING}. * * @since 22 */ @@ -159,7 +159,7 @@ default String resolvedValue() { /** * Models a double value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_DOUBLE}. + * The {@linkplain #tag tag} of this value is {@value TAG_DOUBLE}. * * @since 22 */ @@ -187,7 +187,7 @@ default Double resolvedValue() { /** * Models a float value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_FLOAT}. + * The {@linkplain #tag tag} of this value is {@value TAG_FLOAT}. * * @since 22 */ @@ -215,7 +215,7 @@ default Float resolvedValue() { /** * Models a long value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_LONG}. + * The {@linkplain #tag tag} of this value is {@value TAG_LONG}. * * @since 22 */ @@ -243,7 +243,7 @@ default Long resolvedValue() { /** * Models an int value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_INT}. + * The {@linkplain #tag tag} of this value is {@value TAG_INT}. * * @since 22 */ @@ -271,7 +271,7 @@ default Integer resolvedValue() { /** * Models a short value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_SHORT}. + * The {@linkplain #tag tag} of this value is {@value TAG_SHORT}. * * @since 22 */ @@ -302,7 +302,7 @@ default Short resolvedValue() { /** * Models a char value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_CHAR}. + * The {@linkplain #tag tag} of this value is {@value TAG_CHAR}. * * @since 22 */ @@ -333,7 +333,7 @@ default Character resolvedValue() { /** * Models a byte value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_BYTE}. + * The {@linkplain #tag tag} of this value is {@value TAG_BYTE}. * * @since 22 */ @@ -364,7 +364,7 @@ default Byte resolvedValue() { /** * Models a boolean value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_BOOLEAN}. + * The {@linkplain #tag tag} of this value is {@value TAG_BOOLEAN}. * * @since 22 */ @@ -395,7 +395,7 @@ default Boolean resolvedValue() { /** * Models a class value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_CLASS}. + * The {@linkplain #tag tag} of this value is {@value TAG_CLASS}. * * @since 22 */ @@ -413,7 +413,7 @@ default ClassDesc classSymbol() { /** * Models an enum value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ENUM}. + * The {@linkplain #tag tag} of this value is {@value TAG_ENUM}. * * @since 22 */ @@ -432,9 +432,52 @@ default ClassDesc classSymbol() { Utf8Entry constantName(); } + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfByte}. */ + int TAG_BYTE = 'B'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfChar}. */ + int TAG_CHAR = 'C'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfDouble}. */ + int TAG_DOUBLE = 'D'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfFloat}. */ + int TAG_FLOAT = 'F'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfInt}. */ + int TAG_INT = 'I'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfLong}. */ + int TAG_LONG = 'J'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfShort}. */ + int TAG_SHORT = 'S'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfBoolean}. */ + int TAG_BOOLEAN = 'Z'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfString}. */ + int TAG_STRING = 's'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfEnum}. */ + int TAG_ENUM = 'e'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfClass}. */ + int TAG_CLASS = 'c'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfAnnotation}. */ + int TAG_ANNOTATION = '@'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfArray}. */ + int TAG_ARRAY = '['; + /** * {@return the tag character for this value as per JVMS {@jvms 4.7.16.1}} * The tag characters have a one-to-one mapping to the types of annotation element values. + * + * @apiNote + * {@code TAG_}-prefixed constants in this class, such as {@link #TAG_INT}, + * describe the possible return values of this method. */ char tag(); 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 a305878d3ebf2..284503ee62714 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -512,903 +512,75 @@ default List verify(Path path) throws IOException { /** 0xCAFEBABE */ int MAGIC_NUMBER = 0xCAFEBABE; - /** The integer value used to encode the NOP instruction. */ - int NOP = 0; - - /** The integer value used to encode the ACONST_NULL instruction. */ - int ACONST_NULL = 1; - - /** The integer value used to encode the ICONST_M1 instruction. */ - int ICONST_M1 = 2; - - /** The integer value used to encode the ICONST_0 instruction. */ - int ICONST_0 = 3; - - /** The integer value used to encode the ICONST_1 instruction. */ - int ICONST_1 = 4; - - /** The integer value used to encode the ICONST_2 instruction. */ - int ICONST_2 = 5; - - /** The integer value used to encode the ICONST_3 instruction. */ - int ICONST_3 = 6; - - /** The integer value used to encode the ICONST_4 instruction. */ - int ICONST_4 = 7; - - /** The integer value used to encode the ICONST_5 instruction. */ - int ICONST_5 = 8; - - /** The integer value used to encode the LCONST_0 instruction. */ - int LCONST_0 = 9; - - /** The integer value used to encode the LCONST_1 instruction. */ - int LCONST_1 = 10; - - /** The integer value used to encode the FCONST_0 instruction. */ - int FCONST_0 = 11; - - /** The integer value used to encode the FCONST_1 instruction. */ - int FCONST_1 = 12; - - /** The integer value used to encode the FCONST_2 instruction. */ - int FCONST_2 = 13; - - /** The integer value used to encode the DCONST_0 instruction. */ - int DCONST_0 = 14; - - /** The integer value used to encode the DCONST_1 instruction. */ - int DCONST_1 = 15; - - /** The integer value used to encode the BIPUSH instruction. */ - int BIPUSH = 16; - - /** The integer value used to encode the SIPUSH instruction. */ - int SIPUSH = 17; - - /** The integer value used to encode the LDC instruction. */ - int LDC = 18; - - /** The integer value used to encode the LDC_W instruction. */ - int LDC_W = 19; - - /** The integer value used to encode the LDC2_W instruction. */ - int LDC2_W = 20; - - /** The integer value used to encode the ILOAD instruction. */ - int ILOAD = 21; - - /** The integer value used to encode the LLOAD instruction. */ - int LLOAD = 22; - - /** The integer value used to encode the FLOAD instruction. */ - int FLOAD = 23; - - /** The integer value used to encode the DLOAD instruction. */ - int DLOAD = 24; - - /** The integer value used to encode the ALOAD instruction. */ - int ALOAD = 25; - - /** The integer value used to encode the ILOAD_0 instruction. */ - int ILOAD_0 = 26; - - /** The integer value used to encode the ILOAD_1 instruction. */ - int ILOAD_1 = 27; - - /** The integer value used to encode the ILOAD_2 instruction. */ - int ILOAD_2 = 28; - - /** The integer value used to encode the ILOAD_3 instruction. */ - int ILOAD_3 = 29; - - /** The integer value used to encode the LLOAD_0 instruction. */ - int LLOAD_0 = 30; - - /** The integer value used to encode the LLOAD_1 instruction. */ - int LLOAD_1 = 31; - - /** The integer value used to encode the LLOAD_2 instruction. */ - int LLOAD_2 = 32; - - /** The integer value used to encode the LLOAD_3 instruction. */ - int LLOAD_3 = 33; - - /** The integer value used to encode the FLOAD_0 instruction. */ - int FLOAD_0 = 34; - - /** The integer value used to encode the FLOAD_1 instruction. */ - int FLOAD_1 = 35; - - /** The integer value used to encode the FLOAD_2 instruction. */ - int FLOAD_2 = 36; - - /** The integer value used to encode the FLOAD_3 instruction. */ - int FLOAD_3 = 37; - - /** The integer value used to encode the DLOAD_0 instruction. */ - int DLOAD_0 = 38; - - /** The integer value used to encode the DLOAD_1 instruction. */ - int DLOAD_1 = 39; - - /** The integer value used to encode the DLOAD_2 instruction. */ - int DLOAD_2 = 40; - - /** The integer value used to encode the DLOAD_3 instruction. */ - int DLOAD_3 = 41; - - /** The integer value used to encode the ALOAD_0 instruction. */ - int ALOAD_0 = 42; - - /** The integer value used to encode the ALOAD_1 instruction. */ - int ALOAD_1 = 43; - - /** The integer value used to encode the ALOAD_2 instruction. */ - int ALOAD_2 = 44; - - /** The integer value used to encode the ALOAD_3 instruction. */ - int ALOAD_3 = 45; - - /** The integer value used to encode the IALOAD instruction. */ - int IALOAD = 46; - - /** The integer value used to encode the LALOAD instruction. */ - int LALOAD = 47; - - /** The integer value used to encode the FALOAD instruction. */ - int FALOAD = 48; - - /** The integer value used to encode the DALOAD instruction. */ - int DALOAD = 49; - - /** The integer value used to encode the AALOAD instruction. */ - int AALOAD = 50; - - /** The integer value used to encode the BALOAD instruction. */ - int BALOAD = 51; - - /** The integer value used to encode the CALOAD instruction. */ - int CALOAD = 52; - - /** The integer value used to encode the SALOAD instruction. */ - int SALOAD = 53; - - /** The integer value used to encode the ISTORE instruction. */ - int ISTORE = 54; - - /** The integer value used to encode the LSTORE instruction. */ - int LSTORE = 55; - - /** The integer value used to encode the FSTORE instruction. */ - int FSTORE = 56; - - /** The integer value used to encode the DSTORE instruction. */ - int DSTORE = 57; - - /** The integer value used to encode the ASTORE instruction. */ - int ASTORE = 58; - - /** The integer value used to encode the ISTORE_0 instruction. */ - int ISTORE_0 = 59; - - /** The integer value used to encode the ISTORE_1 instruction. */ - int ISTORE_1 = 60; - - /** The integer value used to encode the ISTORE_2 instruction. */ - int ISTORE_2 = 61; - - /** The integer value used to encode the ISTORE_3 instruction. */ - int ISTORE_3 = 62; - - /** The integer value used to encode the LSTORE_0 instruction. */ - int LSTORE_0 = 63; - - /** The integer value used to encode the LSTORE_1 instruction. */ - int LSTORE_1 = 64; - - /** The integer value used to encode the LSTORE_2 instruction. */ - int LSTORE_2 = 65; - - /** The integer value used to encode the LSTORE_3 instruction. */ - int LSTORE_3 = 66; - - /** The integer value used to encode the FSTORE_0 instruction. */ - int FSTORE_0 = 67; - - /** The integer value used to encode the FSTORE_1 instruction. */ - int FSTORE_1 = 68; - - /** The integer value used to encode the FSTORE_2 instruction. */ - int FSTORE_2 = 69; - - /** The integer value used to encode the FSTORE_3 instruction. */ - int FSTORE_3 = 70; - - /** The integer value used to encode the DSTORE_0 instruction. */ - int DSTORE_0 = 71; - - /** The integer value used to encode the DSTORE_1 instruction. */ - int DSTORE_1 = 72; - - /** The integer value used to encode the DSTORE_2 instruction. */ - int DSTORE_2 = 73; - - /** The integer value used to encode the DSTORE_3 instruction. */ - int DSTORE_3 = 74; - - /** The integer value used to encode the ASTORE_0 instruction. */ - int ASTORE_0 = 75; - - /** The integer value used to encode the ASTORE_1 instruction. */ - int ASTORE_1 = 76; - - /** The integer value used to encode the ASTORE_2 instruction. */ - int ASTORE_2 = 77; - - /** The integer value used to encode the ASTORE_3 instruction. */ - int ASTORE_3 = 78; - - /** The integer value used to encode the IASTORE instruction. */ - int IASTORE = 79; - - /** The integer value used to encode the LASTORE instruction. */ - int LASTORE = 80; - - /** The integer value used to encode the FASTORE instruction. */ - int FASTORE = 81; - - /** The integer value used to encode the DASTORE instruction. */ - int DASTORE = 82; - - /** The integer value used to encode the AASTORE instruction. */ - int AASTORE = 83; - - /** The integer value used to encode the BASTORE instruction. */ - int BASTORE = 84; - - /** The integer value used to encode the CASTORE instruction. */ - int CASTORE = 85; - - /** The integer value used to encode the SASTORE instruction. */ - int SASTORE = 86; - - /** The integer value used to encode the POP instruction. */ - int POP = 87; - - /** The integer value used to encode the POP2 instruction. */ - int POP2 = 88; - - /** The integer value used to encode the DUP instruction. */ - int DUP = 89; - - /** The integer value used to encode the DUP_X1 instruction. */ - int DUP_X1 = 90; - - /** The integer value used to encode the DUP_X2 instruction. */ - int DUP_X2 = 91; - - /** The integer value used to encode the DUP2 instruction. */ - int DUP2 = 92; - - /** The integer value used to encode the DUP2_X1 instruction. */ - int DUP2_X1 = 93; - - /** The integer value used to encode the DUP2_X2 instruction. */ - int DUP2_X2 = 94; - - /** The integer value used to encode the SWAP instruction. */ - int SWAP = 95; - - /** The integer value used to encode the IADD instruction. */ - int IADD = 96; - - /** The integer value used to encode the LADD instruction. */ - int LADD = 97; - - /** The integer value used to encode the FADD instruction. */ - int FADD = 98; - - /** The integer value used to encode the DADD instruction. */ - int DADD = 99; - - /** The integer value used to encode the ISUB instruction. */ - int ISUB = 100; - - /** The integer value used to encode the LSUB instruction. */ - int LSUB = 101; - - /** The integer value used to encode the FSUB instruction. */ - int FSUB = 102; - - /** The integer value used to encode the DSUB instruction. */ - int DSUB = 103; - - /** The integer value used to encode the IMUL instruction. */ - int IMUL = 104; - - /** The integer value used to encode the LMUL instruction. */ - int LMUL = 105; - - /** The integer value used to encode the FMUL instruction. */ - int FMUL = 106; - - /** The integer value used to encode the DMUL instruction. */ - int DMUL = 107; - - /** The integer value used to encode the IDIV instruction. */ - int IDIV = 108; - - /** The integer value used to encode the LDIV instruction. */ - int LDIV = 109; - - /** The integer value used to encode the FDIV instruction. */ - int FDIV = 110; - - /** The integer value used to encode the DDIV instruction. */ - int DDIV = 111; - - /** The integer value used to encode the IREM instruction. */ - int IREM = 112; - - /** The integer value used to encode the LREM instruction. */ - int LREM = 113; - - /** The integer value used to encode the FREM instruction. */ - int FREM = 114; - - /** The integer value used to encode the DREM instruction. */ - int DREM = 115; - - /** The integer value used to encode the INEG instruction. */ - int INEG = 116; - - /** The integer value used to encode the LNEG instruction. */ - int LNEG = 117; - - /** The integer value used to encode the FNEG instruction. */ - int FNEG = 118; - - /** The integer value used to encode the DNEG instruction. */ - int DNEG = 119; - - /** The integer value used to encode the ISHL instruction. */ - int ISHL = 120; - - /** The integer value used to encode the LSHL instruction. */ - int LSHL = 121; - - /** The integer value used to encode the ISHR instruction. */ - int ISHR = 122; - - /** The integer value used to encode the LSHR instruction. */ - int LSHR = 123; - - /** The integer value used to encode the IUSHR instruction. */ - int IUSHR = 124; - - /** The integer value used to encode the LUSHR instruction. */ - int LUSHR = 125; - - /** The integer value used to encode the IAND instruction. */ - int IAND = 126; - - /** The integer value used to encode the LAND instruction. */ - int LAND = 127; - - /** The integer value used to encode the IOR instruction. */ - int IOR = 128; - - /** The integer value used to encode the LOR instruction. */ - int LOR = 129; - - /** The integer value used to encode the IXOR instruction. */ - int IXOR = 130; - - /** The integer value used to encode the LXOR instruction. */ - int LXOR = 131; - - /** The integer value used to encode the IINC instruction. */ - int IINC = 132; - - /** The integer value used to encode the I2L instruction. */ - int I2L = 133; - - /** The integer value used to encode the I2F instruction. */ - int I2F = 134; - - /** The integer value used to encode the I2D instruction. */ - int I2D = 135; - - /** The integer value used to encode the L2I instruction. */ - int L2I = 136; - - /** The integer value used to encode the L2F instruction. */ - int L2F = 137; - - /** The integer value used to encode the L2D instruction. */ - int L2D = 138; - - /** The integer value used to encode the F2I instruction. */ - int F2I = 139; - - /** The integer value used to encode the F2L instruction. */ - int F2L = 140; - - /** The integer value used to encode the F2D instruction. */ - int F2D = 141; - - /** The integer value used to encode the D2I instruction. */ - int D2I = 142; - - /** The integer value used to encode the D2L instruction. */ - int D2L = 143; - - /** The integer value used to encode the D2F instruction. */ - int D2F = 144; - - /** The integer value used to encode the I2B instruction. */ - int I2B = 145; - - /** The integer value used to encode the I2C instruction. */ - int I2C = 146; - - /** The integer value used to encode the I2S instruction. */ - int I2S = 147; - - /** The integer value used to encode the LCMP instruction. */ - int LCMP = 148; - - /** The integer value used to encode the FCMPL instruction. */ - int FCMPL = 149; - - /** The integer value used to encode the FCMPG instruction. */ - int FCMPG = 150; - - /** The integer value used to encode the DCMPL instruction. */ - int DCMPL = 151; - - /** The integer value used to encode the DCMPG instruction. */ - int DCMPG = 152; - - /** The integer value used to encode the IFEQ instruction. */ - int IFEQ = 153; - - /** The integer value used to encode the IFNE instruction. */ - int IFNE = 154; - - /** The integer value used to encode the IFLT instruction. */ - int IFLT = 155; - - /** The integer value used to encode the IFGE instruction. */ - int IFGE = 156; - - /** The integer value used to encode the IFGT instruction. */ - int IFGT = 157; - - /** The integer value used to encode the IFLE instruction. */ - int IFLE = 158; - - /** The integer value used to encode the IF_ICMPEQ instruction. */ - int IF_ICMPEQ = 159; - - /** The integer value used to encode the IF_ICMPNE instruction. */ - int IF_ICMPNE = 160; - - /** The integer value used to encode the IF_ICMPLT instruction. */ - int IF_ICMPLT = 161; - - /** The integer value used to encode the IF_ICMPGE instruction. */ - int IF_ICMPGE = 162; - - /** The integer value used to encode the IF_ICMPGT instruction. */ - int IF_ICMPGT = 163; - - /** The integer value used to encode the IF_ICMPLE instruction. */ - int IF_ICMPLE = 164; - - /** The integer value used to encode the IF_ACMPEQ instruction. */ - int IF_ACMPEQ = 165; - - /** The integer value used to encode the IF_ACMPNE instruction. */ - int IF_ACMPNE = 166; - - /** The integer value used to encode the GOTO instruction. */ - int GOTO = 167; - - /** The integer value used to encode the JSR instruction. */ - int JSR = 168; - - /** The integer value used to encode the RET instruction. */ - int RET = 169; - - /** The integer value used to encode the TABLESWITCH instruction. */ - int TABLESWITCH = 170; - - /** The integer value used to encode the LOOKUPSWITCH instruction. */ - int LOOKUPSWITCH = 171; - - /** The integer value used to encode the IRETURN instruction. */ - int IRETURN = 172; - - /** The integer value used to encode the LRETURN instruction. */ - int LRETURN = 173; - - /** The integer value used to encode the FRETURN instruction. */ - int FRETURN = 174; - - /** The integer value used to encode the DRETURN instruction. */ - int DRETURN = 175; - - /** The integer value used to encode the ARETURN instruction. */ - int ARETURN = 176; - - /** The integer value used to encode the RETURN instruction. */ - int RETURN = 177; - - /** The integer value used to encode the GETSTATIC instruction. */ - int GETSTATIC = 178; - - /** The integer value used to encode the PUTSTATIC instruction. */ - int PUTSTATIC = 179; - - /** The integer value used to encode the GETFIELD instruction. */ - int GETFIELD = 180; - - /** The integer value used to encode the PUTFIELD instruction. */ - int PUTFIELD = 181; - - /** The integer value used to encode the INVOKEVIRTUAL instruction. */ - int INVOKEVIRTUAL = 182; - - /** The integer value used to encode the INVOKESPECIAL instruction. */ - int INVOKESPECIAL = 183; - - /** The integer value used to encode the INVOKESTATIC instruction. */ - int INVOKESTATIC = 184; - - /** The integer value used to encode the INVOKEINTERFACE instruction. */ - int INVOKEINTERFACE = 185; - - /** The integer value used to encode the INVOKEDYNAMIC instruction. */ - int INVOKEDYNAMIC = 186; - - /** The integer value used to encode the NEW instruction. */ - int NEW = 187; - - /** The integer value used to encode the NEWARRAY instruction. */ - int NEWARRAY = 188; - - /** The integer value used to encode the ANEWARRAY instruction. */ - int ANEWARRAY = 189; - - /** The integer value used to encode the ARRAYLENGTH instruction. */ - int ARRAYLENGTH = 190; - - /** The integer value used to encode the ATHROW instruction. */ - int ATHROW = 191; - - /** The integer value used to encode the CHECKCAST instruction. */ - int CHECKCAST = 192; - - /** The integer value used to encode the INSTANCEOF instruction. */ - int INSTANCEOF = 193; - - /** The integer value used to encode the MONITORENTER instruction. */ - int MONITORENTER = 194; - - /** The integer value used to encode the MONITOREXIT instruction. */ - int MONITOREXIT = 195; - - /** The integer value used to encode the WIDE instruction. */ - int WIDE = 196; - - /** The integer value used to encode the MULTIANEWARRAY instruction. */ - int MULTIANEWARRAY = 197; - - /** The integer value used to encode the IFNULL instruction. */ - int IFNULL = 198; - - /** The integer value used to encode the IFNONNULL instruction. */ - int IFNONNULL = 199; - - /** The integer value used to encode the GOTO_W instruction. */ - int GOTO_W = 200; - - /** The integer value used to encode the JSR_W instruction. */ - int JSR_W = 201; - - /** The value of PUBLIC access and property modifier. */ + /** The bit mask of PUBLIC access and property modifier. */ int ACC_PUBLIC = 0x0001; - /** The value of PROTECTED access and property modifier. */ + /** The bit mask of PROTECTED access and property modifier. */ int ACC_PROTECTED = 0x0004; - /** The value of PRIVATE access and property modifier. */ + /** The bit mask of PRIVATE access and property modifier. */ int ACC_PRIVATE = 0x0002; - /** The value of INTERFACE access and property modifier. */ + /** The bit mask of INTERFACE access and property modifier. */ int ACC_INTERFACE = 0x0200; - /** The value of ENUM access and property modifier. */ + /** The bit mask of ENUM access and property modifier. */ int ACC_ENUM = 0x4000; - /** The value of ANNOTATION access and property modifier. */ + /** The bit mask of ANNOTATION access and property modifier. */ int ACC_ANNOTATION = 0x2000; - /** The value of SUPER access and property modifier. */ + /** The bit mask of SUPER access and property modifier. */ int ACC_SUPER = 0x0020; - /** The value of ABSTRACT access and property modifier. */ + /** The bit mask of ABSTRACT access and property modifier. */ int ACC_ABSTRACT = 0x0400; - /** The value of VOLATILE access and property modifier. */ + /** The bit mask of VOLATILE access and property modifier. */ int ACC_VOLATILE = 0x0040; - /** The value of TRANSIENT access and property modifier. */ + /** The bit mask of TRANSIENT access and property modifier. */ int ACC_TRANSIENT = 0x0080; - /** The value of SYNTHETIC access and property modifier. */ + /** The bit mask of SYNTHETIC access and property modifier. */ int ACC_SYNTHETIC = 0x1000; - /** The value of STATIC access and property modifier. */ + /** The bit mask of STATIC access and property modifier. */ int ACC_STATIC = 0x0008; - /** The value of FINAL access and property modifier. */ + /** The bit mask of FINAL access and property modifier. */ int ACC_FINAL = 0x0010; - /** The value of SYNCHRONIZED access and property modifier. */ + /** The bit mask of SYNCHRONIZED access and property modifier. */ int ACC_SYNCHRONIZED = 0x0020; - /** The value of BRIDGE access and property modifier. */ + /** The bit mask of BRIDGE access and property modifier. */ int ACC_BRIDGE = 0x0040; - /** The value of VARARGS access and property modifier. */ + /** The bit mask of VARARGS access and property modifier. */ int ACC_VARARGS = 0x0080; - /** The value of NATIVE access and property modifier. */ + /** The bit mask of NATIVE access and property modifier. */ int ACC_NATIVE = 0x0100; - /** The value of STRICT access and property modifier. */ + /** The bit mask of STRICT access and property modifier. */ int ACC_STRICT = 0x0800; - /** The value of MODULE access and property modifier. */ + /** The bit mask of MODULE access and property modifier. */ int ACC_MODULE = 0x8000; - /** The value of OPEN access and property modifier. */ + /** The bit mask of OPEN access and property modifier. */ int ACC_OPEN = 0x20; - /** The value of MANDATED access and property modifier. */ + /** The bit mask of MANDATED access and property modifier. */ int ACC_MANDATED = 0x8000; - /** The value of TRANSITIVE access and property modifier. */ + /** The bit mask of TRANSITIVE access and property modifier. */ int ACC_TRANSITIVE = 0x20; - /** The value of STATIC_PHASE access and property modifier. */ + /** The bit mask of STATIC_PHASE access and property modifier. */ int ACC_STATIC_PHASE = 0x40; - /** The value of STATEMENT {@link CharacterRangeInfo} kind. */ - int CRT_STATEMENT = 0x0001; - - /** The value of BLOCK {@link CharacterRangeInfo} kind. */ - int CRT_BLOCK = 0x0002; - - /** The value of ASSIGNMENT {@link CharacterRangeInfo} kind. */ - int CRT_ASSIGNMENT = 0x0004; - - /** The value of FLOW_CONTROLLER {@link CharacterRangeInfo} kind. */ - int CRT_FLOW_CONTROLLER = 0x0008; - - /** The value of FLOW_TARGET {@link CharacterRangeInfo} kind. */ - int CRT_FLOW_TARGET = 0x0010; - - /** The value of INVOKE {@link CharacterRangeInfo} kind. */ - int CRT_INVOKE = 0x0020; - - /** The value of CREATE {@link CharacterRangeInfo} kind. */ - int CRT_CREATE = 0x0040; - - /** The value of BRANCH_TRUE {@link CharacterRangeInfo} kind. */ - int CRT_BRANCH_TRUE = 0x0080; - - /** The value of BRANCH_FALSE {@link CharacterRangeInfo} kind. */ - int CRT_BRANCH_FALSE = 0x0100; - - /** The value of constant pool tag CLASS. */ - int TAG_CLASS = 7; - - /** The value of constant pool tag CONSTANTDYNAMIC. */ - int TAG_CONSTANTDYNAMIC = 17; - - /** The value of constant pool tag DOUBLE. */ - int TAG_DOUBLE = 6; - - /** The value of constant pool tag FIELDREF. */ - int TAG_FIELDREF = 9; - - /** The value of constant pool tag FLOAT. */ - int TAG_FLOAT = 4; - - /** The value of constant pool tag INTEGER. */ - int TAG_INTEGER = 3; - - /** The value of constant pool tag INTERFACEMETHODREF. */ - int TAG_INTERFACEMETHODREF = 11; - - /** The value of constant pool tag INVOKEDYNAMIC. */ - int TAG_INVOKEDYNAMIC = 18; - - /** The value of constant pool tag LONG. */ - int TAG_LONG = 5; - - /** The value of constant pool tag METHODHANDLE. */ - int TAG_METHODHANDLE = 15; - - /** The value of constant pool tag METHODREF. */ - int TAG_METHODREF = 10; - - /** The value of constant pool tag METHODTYPE. */ - int TAG_METHODTYPE = 16; - - /** The value of constant pool tag MODULE. */ - int TAG_MODULE = 19; - - /** The value of constant pool tag NAMEANDTYPE. */ - int TAG_NAMEANDTYPE = 12; - - /** The value of constant pool tag PACKAGE. */ - int TAG_PACKAGE = 20; - - /** The value of constant pool tag STRING. */ - int TAG_STRING = 8; - - /** The value of constant pool tag UNICODE. */ - int TAG_UNICODE = 2; - - /** The value of constant pool tag UTF8. */ - int TAG_UTF8 = 1; - - // annotation element values - - /** The value of annotation element value type AEV_BYTE. */ - int AEV_BYTE = 'B'; - - /** The value of annotation element value type AEV_CHAR. */ - int AEV_CHAR = 'C'; - - /** The value of annotation element value type AEV_DOUBLE. */ - int AEV_DOUBLE = 'D'; - - /** The value of annotation element value type AEV_FLOAT. */ - int AEV_FLOAT = 'F'; - - /** The value of annotation element value type AEV_INT. */ - int AEV_INT = 'I'; - - /** The value of annotation element value type AEV_LONG. */ - int AEV_LONG = 'J'; - - /** The value of annotation element value type AEV_SHORT. */ - int AEV_SHORT = 'S'; - - /** The value of annotation element value type AEV_BOOLEAN. */ - int AEV_BOOLEAN = 'Z'; - - /** The value of annotation element value type AEV_STRING. */ - int AEV_STRING = 's'; - - /** The value of annotation element value type AEV_ENUM. */ - int AEV_ENUM = 'e'; - - /** The value of annotation element value type AEV_CLASS. */ - int AEV_CLASS = 'c'; - - /** The value of annotation element value type AEV_ANNOTATION. */ - int AEV_ANNOTATION = '@'; - - /** The value of annotation element value type AEV_ARRAY. */ - int AEV_ARRAY = '['; - - //type annotations - - /** The value of type annotation target type CLASS_TYPE_PARAMETER. */ - int TAT_CLASS_TYPE_PARAMETER = 0x00; - - /** The value of type annotation target type METHOD_TYPE_PARAMETER. */ - int TAT_METHOD_TYPE_PARAMETER = 0x01; - - /** The value of type annotation target type CLASS_EXTENDS. */ - int TAT_CLASS_EXTENDS = 0x10; - - /** The value of type annotation target type CLASS_TYPE_PARAMETER_BOUND. */ - int TAT_CLASS_TYPE_PARAMETER_BOUND = 0x11; - - /** The value of type annotation target type METHOD_TYPE_PARAMETER_BOUND. */ - int TAT_METHOD_TYPE_PARAMETER_BOUND = 0x12; - - /** The value of type annotation target type FIELD. */ - int TAT_FIELD = 0x13; - - /** The value of type annotation target type METHOD_RETURN. */ - int TAT_METHOD_RETURN = 0x14; - - /** The value of type annotation target type METHOD_RECEIVER. */ - int TAT_METHOD_RECEIVER = 0x15; - - /** The value of type annotation target type METHOD_FORMAL_PARAMETER. */ - int TAT_METHOD_FORMAL_PARAMETER = 0x16; - - /** The value of type annotation target type THROWS. */ - int TAT_THROWS = 0x17; - - /** The value of type annotation target type LOCAL_VARIABLE. */ - int TAT_LOCAL_VARIABLE = 0x40; - - /** The value of type annotation target type RESOURCE_VARIABLE. */ - int TAT_RESOURCE_VARIABLE = 0x41; - - /** The value of type annotation target type EXCEPTION_PARAMETER. */ - int TAT_EXCEPTION_PARAMETER = 0x42; - - /** The value of type annotation target type INSTANCEOF. */ - int TAT_INSTANCEOF = 0x43; - - /** The value of type annotation target type NEW. */ - int TAT_NEW = 0x44; - - /** The value of type annotation target type CONSTRUCTOR_REFERENCE. */ - int TAT_CONSTRUCTOR_REFERENCE = 0x45; - - /** The value of type annotation target type METHOD_REFERENCE. */ - int TAT_METHOD_REFERENCE = 0x46; - - /** The value of type annotation target type CAST. */ - int TAT_CAST = 0x47; - - /** The value of type annotation target type CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT. */ - int TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; - - /** The value of type annotation target type METHOD_INVOCATION_TYPE_ARGUMENT. */ - int TAT_METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; - - /** The value of type annotation target type CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT. */ - int TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; - - /** The value of type annotation target type METHOD_REFERENCE_TYPE_ARGUMENT. */ - int TAT_METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; - - //stackmap verification types - - /** The value of verification type TOP. */ - int VT_TOP = 0; - - /** The value of verification type INTEGER. */ - int VT_INTEGER = 1; - - /** The value of verification type FLOAT. */ - int VT_FLOAT = 2; - - /** The value of verification type DOUBLE. */ - int VT_DOUBLE = 3; - - /** The value of verification type LONG. */ - int VT_LONG = 4; - - /** The value of verification type NULL. */ - int VT_NULL = 5; - - /** The value of verification type UNINITIALIZED_THIS. */ - int VT_UNINITIALIZED_THIS = 6; - - /** The value of verification type OBJECT. */ - int VT_OBJECT = 7; - - /** The value of verification type UNINITIALIZED. */ - int VT_UNINITIALIZED = 8; - - /** The value of default class access flags */ - int DEFAULT_CLASS_FLAGS = ACC_PUBLIC; - /** The class major version of JAVA_1. */ int JAVA_1_VERSION = 45; diff --git a/src/java.base/share/classes/java/lang/classfile/Opcode.java b/src/java.base/share/classes/java/lang/classfile/Opcode.java index ab991d983453d..735510dbcea3b 100644 --- a/src/java.base/share/classes/java/lang/classfile/Opcode.java +++ b/src/java.base/share/classes/java/lang/classfile/Opcode.java @@ -24,6 +24,7 @@ */ package java.lang.classfile; +import jdk.internal.classfile.impl.RawBytecodeHelper; import jdk.internal.javac.PreviewFeature; /** @@ -40,658 +41,658 @@ public enum Opcode { /** Do nothing */ - NOP(ClassFile.NOP, 1, Kind.NOP), + NOP(RawBytecodeHelper.NOP, 1, Kind.NOP), /** Push null */ - ACONST_NULL(ClassFile.ACONST_NULL, 1, Kind.CONSTANT), + ACONST_NULL(RawBytecodeHelper.ACONST_NULL, 1, Kind.CONSTANT), /** Push int constant -1 */ - ICONST_M1(ClassFile.ICONST_M1, 1, Kind.CONSTANT), + ICONST_M1(RawBytecodeHelper.ICONST_M1, 1, Kind.CONSTANT), /** Push int constant 0 */ - ICONST_0(ClassFile.ICONST_0, 1, Kind.CONSTANT), + ICONST_0(RawBytecodeHelper.ICONST_0, 1, Kind.CONSTANT), /** Push int constant 1 */ - ICONST_1(ClassFile.ICONST_1, 1, Kind.CONSTANT), + ICONST_1(RawBytecodeHelper.ICONST_1, 1, Kind.CONSTANT), /** Push int constant 2 */ - ICONST_2(ClassFile.ICONST_2, 1, Kind.CONSTANT), + ICONST_2(RawBytecodeHelper.ICONST_2, 1, Kind.CONSTANT), /** Push int constant 3 */ - ICONST_3(ClassFile.ICONST_3, 1, Kind.CONSTANT), + ICONST_3(RawBytecodeHelper.ICONST_3, 1, Kind.CONSTANT), /** Push int constant 4 */ - ICONST_4(ClassFile.ICONST_4, 1, Kind.CONSTANT), + ICONST_4(RawBytecodeHelper.ICONST_4, 1, Kind.CONSTANT), /** Push int constant 5 */ - ICONST_5(ClassFile.ICONST_5, 1, Kind.CONSTANT), + ICONST_5(RawBytecodeHelper.ICONST_5, 1, Kind.CONSTANT), /** Push long constant 0 */ - LCONST_0(ClassFile.LCONST_0, 1, Kind.CONSTANT), + LCONST_0(RawBytecodeHelper.LCONST_0, 1, Kind.CONSTANT), /** Push long constant 1 */ - LCONST_1(ClassFile.LCONST_1, 1, Kind.CONSTANT), + LCONST_1(RawBytecodeHelper.LCONST_1, 1, Kind.CONSTANT), /** Push float constant 0 */ - FCONST_0(ClassFile.FCONST_0, 1, Kind.CONSTANT), + FCONST_0(RawBytecodeHelper.FCONST_0, 1, Kind.CONSTANT), /** Push float constant 1 */ - FCONST_1(ClassFile.FCONST_1, 1, Kind.CONSTANT), + FCONST_1(RawBytecodeHelper.FCONST_1, 1, Kind.CONSTANT), /** Push float constant 2 */ - FCONST_2(ClassFile.FCONST_2, 1, Kind.CONSTANT), + FCONST_2(RawBytecodeHelper.FCONST_2, 1, Kind.CONSTANT), /** Push double constant 0 */ - DCONST_0(ClassFile.DCONST_0, 1, Kind.CONSTANT), + DCONST_0(RawBytecodeHelper.DCONST_0, 1, Kind.CONSTANT), /** Push double constant 1 */ - DCONST_1(ClassFile.DCONST_1, 1, Kind.CONSTANT), + DCONST_1(RawBytecodeHelper.DCONST_1, 1, Kind.CONSTANT), /** Push byte */ - BIPUSH(ClassFile.BIPUSH, 2, Kind.CONSTANT), + BIPUSH(RawBytecodeHelper.BIPUSH, 2, Kind.CONSTANT), /** Push short */ - SIPUSH(ClassFile.SIPUSH, 3, Kind.CONSTANT), + SIPUSH(RawBytecodeHelper.SIPUSH, 3, Kind.CONSTANT), /** Push item from run-time constant pool */ - LDC(ClassFile.LDC, 2, Kind.CONSTANT), + LDC(RawBytecodeHelper.LDC, 2, Kind.CONSTANT), /** Push item from run-time constant pool (wide index) */ - LDC_W(ClassFile.LDC_W, 3, Kind.CONSTANT), + LDC_W(RawBytecodeHelper.LDC_W, 3, Kind.CONSTANT), /** Push long or double from run-time constant pool (wide index) */ - LDC2_W(ClassFile.LDC2_W, 3, Kind.CONSTANT), + LDC2_W(RawBytecodeHelper.LDC2_W, 3, Kind.CONSTANT), /** Load int from local variable */ - ILOAD(ClassFile.ILOAD, 2, Kind.LOAD), + ILOAD(RawBytecodeHelper.ILOAD, 2, Kind.LOAD), /** Load long from local variable */ - LLOAD(ClassFile.LLOAD, 2, Kind.LOAD), + LLOAD(RawBytecodeHelper.LLOAD, 2, Kind.LOAD), /** Load float from local variable */ - FLOAD(ClassFile.FLOAD, 2, Kind.LOAD), + FLOAD(RawBytecodeHelper.FLOAD, 2, Kind.LOAD), /** Load double from local variable */ - DLOAD(ClassFile.DLOAD, 2, Kind.LOAD), + DLOAD(RawBytecodeHelper.DLOAD, 2, Kind.LOAD), /** Load reference from local variable */ - ALOAD(ClassFile.ALOAD, 2, Kind.LOAD), + ALOAD(RawBytecodeHelper.ALOAD, 2, Kind.LOAD), /** Load int from local variable 0 */ - ILOAD_0(ClassFile.ILOAD_0, 1, Kind.LOAD), + ILOAD_0(RawBytecodeHelper.ILOAD_0, 1, Kind.LOAD), /** Load int from local variable 1 */ - ILOAD_1(ClassFile.ILOAD_1, 1, Kind.LOAD), + ILOAD_1(RawBytecodeHelper.ILOAD_1, 1, Kind.LOAD), /** Load int from local variable 2 */ - ILOAD_2(ClassFile.ILOAD_2, 1, Kind.LOAD), + ILOAD_2(RawBytecodeHelper.ILOAD_2, 1, Kind.LOAD), /** Load int from local variable3 */ - ILOAD_3(ClassFile.ILOAD_3, 1, Kind.LOAD), + ILOAD_3(RawBytecodeHelper.ILOAD_3, 1, Kind.LOAD), /** Load long from local variable 0 */ - LLOAD_0(ClassFile.LLOAD_0, 1, Kind.LOAD), + LLOAD_0(RawBytecodeHelper.LLOAD_0, 1, Kind.LOAD), /** Load long from local variable 1 */ - LLOAD_1(ClassFile.LLOAD_1, 1, Kind.LOAD), + LLOAD_1(RawBytecodeHelper.LLOAD_1, 1, Kind.LOAD), /** Load long from local variable 2 */ - LLOAD_2(ClassFile.LLOAD_2, 1, Kind.LOAD), + LLOAD_2(RawBytecodeHelper.LLOAD_2, 1, Kind.LOAD), /** Load long from local variable 3 */ - LLOAD_3(ClassFile.LLOAD_3, 1, Kind.LOAD), + LLOAD_3(RawBytecodeHelper.LLOAD_3, 1, Kind.LOAD), /** Load float from local variable 0 */ - FLOAD_0(ClassFile.FLOAD_0, 1, Kind.LOAD), + FLOAD_0(RawBytecodeHelper.FLOAD_0, 1, Kind.LOAD), /** Load float from local variable 1 */ - FLOAD_1(ClassFile.FLOAD_1, 1, Kind.LOAD), + FLOAD_1(RawBytecodeHelper.FLOAD_1, 1, Kind.LOAD), /** Load float from local variable 2 */ - FLOAD_2(ClassFile.FLOAD_2, 1, Kind.LOAD), + FLOAD_2(RawBytecodeHelper.FLOAD_2, 1, Kind.LOAD), /** Load float from local variable 3 */ - FLOAD_3(ClassFile.FLOAD_3, 1, Kind.LOAD), + FLOAD_3(RawBytecodeHelper.FLOAD_3, 1, Kind.LOAD), /** Load double from local variable 0 */ - DLOAD_0(ClassFile.DLOAD_0, 1, Kind.LOAD), + DLOAD_0(RawBytecodeHelper.DLOAD_0, 1, Kind.LOAD), /** Load double from local variable 1 */ - DLOAD_1(ClassFile.DLOAD_1, 1, Kind.LOAD), + DLOAD_1(RawBytecodeHelper.DLOAD_1, 1, Kind.LOAD), /** Load double from local variable 2 */ - DLOAD_2(ClassFile.DLOAD_2, 1, Kind.LOAD), + DLOAD_2(RawBytecodeHelper.DLOAD_2, 1, Kind.LOAD), /** Load double from local variable 3 */ - DLOAD_3(ClassFile.DLOAD_3, 1, Kind.LOAD), + DLOAD_3(RawBytecodeHelper.DLOAD_3, 1, Kind.LOAD), /** Load reference from local variable 0 */ - ALOAD_0(ClassFile.ALOAD_0, 1, Kind.LOAD), + ALOAD_0(RawBytecodeHelper.ALOAD_0, 1, Kind.LOAD), /** Load reference from local variable 1 */ - ALOAD_1(ClassFile.ALOAD_1, 1, Kind.LOAD), + ALOAD_1(RawBytecodeHelper.ALOAD_1, 1, Kind.LOAD), /** Load reference from local variable 2 */ - ALOAD_2(ClassFile.ALOAD_2, 1, Kind.LOAD), + ALOAD_2(RawBytecodeHelper.ALOAD_2, 1, Kind.LOAD), /** Load reference from local variable 3 */ - ALOAD_3(ClassFile.ALOAD_3, 1, Kind.LOAD), + ALOAD_3(RawBytecodeHelper.ALOAD_3, 1, Kind.LOAD), /** Load int from array */ - IALOAD(ClassFile.IALOAD, 1, Kind.ARRAY_LOAD), + IALOAD(RawBytecodeHelper.IALOAD, 1, Kind.ARRAY_LOAD), /** Load long from array */ - LALOAD(ClassFile.LALOAD, 1, Kind.ARRAY_LOAD), + LALOAD(RawBytecodeHelper.LALOAD, 1, Kind.ARRAY_LOAD), /** Load float from array */ - FALOAD(ClassFile.FALOAD, 1, Kind.ARRAY_LOAD), + FALOAD(RawBytecodeHelper.FALOAD, 1, Kind.ARRAY_LOAD), /** Load double from array */ - DALOAD(ClassFile.DALOAD, 1, Kind.ARRAY_LOAD), + DALOAD(RawBytecodeHelper.DALOAD, 1, Kind.ARRAY_LOAD), /** Load reference from array */ - AALOAD(ClassFile.AALOAD, 1, Kind.ARRAY_LOAD), + AALOAD(RawBytecodeHelper.AALOAD, 1, Kind.ARRAY_LOAD), /** Load byte from array */ - BALOAD(ClassFile.BALOAD, 1, Kind.ARRAY_LOAD), + BALOAD(RawBytecodeHelper.BALOAD, 1, Kind.ARRAY_LOAD), /** Load char from array */ - CALOAD(ClassFile.CALOAD, 1, Kind.ARRAY_LOAD), + CALOAD(RawBytecodeHelper.CALOAD, 1, Kind.ARRAY_LOAD), /** Load short from array */ - SALOAD(ClassFile.SALOAD, 1, Kind.ARRAY_LOAD), + SALOAD(RawBytecodeHelper.SALOAD, 1, Kind.ARRAY_LOAD), /** Store int into local variable */ - ISTORE(ClassFile.ISTORE, 2, Kind.STORE), + ISTORE(RawBytecodeHelper.ISTORE, 2, Kind.STORE), /** Store long into local variable */ - LSTORE(ClassFile.LSTORE, 2, Kind.STORE), + LSTORE(RawBytecodeHelper.LSTORE, 2, Kind.STORE), /** Store float into local variable */ - FSTORE(ClassFile.FSTORE, 2, Kind.STORE), + FSTORE(RawBytecodeHelper.FSTORE, 2, Kind.STORE), /** Store double into local variable */ - DSTORE(ClassFile.DSTORE, 2, Kind.STORE), + DSTORE(RawBytecodeHelper.DSTORE, 2, Kind.STORE), /** Store reference into local variable */ - ASTORE(ClassFile.ASTORE, 2, Kind.STORE), + ASTORE(RawBytecodeHelper.ASTORE, 2, Kind.STORE), /** Store int into local variable 0 */ - ISTORE_0(ClassFile.ISTORE_0, 1, Kind.STORE), + ISTORE_0(RawBytecodeHelper.ISTORE_0, 1, Kind.STORE), /** Store int into local variable 1 */ - ISTORE_1(ClassFile.ISTORE_1, 1, Kind.STORE), + ISTORE_1(RawBytecodeHelper.ISTORE_1, 1, Kind.STORE), /** Store int into local variable 2 */ - ISTORE_2(ClassFile.ISTORE_2, 1, Kind.STORE), + ISTORE_2(RawBytecodeHelper.ISTORE_2, 1, Kind.STORE), /** Store int into local variable 3 */ - ISTORE_3(ClassFile.ISTORE_3, 1, Kind.STORE), + ISTORE_3(RawBytecodeHelper.ISTORE_3, 1, Kind.STORE), /** Store long into local variable 0 */ - LSTORE_0(ClassFile.LSTORE_0, 1, Kind.STORE), + LSTORE_0(RawBytecodeHelper.LSTORE_0, 1, Kind.STORE), /** Store long into local variable 1 */ - LSTORE_1(ClassFile.LSTORE_1, 1, Kind.STORE), + LSTORE_1(RawBytecodeHelper.LSTORE_1, 1, Kind.STORE), /** Store long into local variable 2 */ - LSTORE_2(ClassFile.LSTORE_2, 1, Kind.STORE), + LSTORE_2(RawBytecodeHelper.LSTORE_2, 1, Kind.STORE), /** Store long into local variable 3 */ - LSTORE_3(ClassFile.LSTORE_3, 1, Kind.STORE), + LSTORE_3(RawBytecodeHelper.LSTORE_3, 1, Kind.STORE), /** Store float into local variable 0 */ - FSTORE_0(ClassFile.FSTORE_0, 1, Kind.STORE), + FSTORE_0(RawBytecodeHelper.FSTORE_0, 1, Kind.STORE), /** Store float into local variable 1 */ - FSTORE_1(ClassFile.FSTORE_1, 1, Kind.STORE), + FSTORE_1(RawBytecodeHelper.FSTORE_1, 1, Kind.STORE), /** Store float into local variable 2 */ - FSTORE_2(ClassFile.FSTORE_2, 1, Kind.STORE), + FSTORE_2(RawBytecodeHelper.FSTORE_2, 1, Kind.STORE), /** Store float into local variable 3 */ - FSTORE_3(ClassFile.FSTORE_3, 1, Kind.STORE), + FSTORE_3(RawBytecodeHelper.FSTORE_3, 1, Kind.STORE), /** Store double into local variable 0 */ - DSTORE_0(ClassFile.DSTORE_0, 1, Kind.STORE), + DSTORE_0(RawBytecodeHelper.DSTORE_0, 1, Kind.STORE), /** Store double into local variable 1 */ - DSTORE_1(ClassFile.DSTORE_1, 1, Kind.STORE), + DSTORE_1(RawBytecodeHelper.DSTORE_1, 1, Kind.STORE), /** Store double into local variable 2 */ - DSTORE_2(ClassFile.DSTORE_2, 1, Kind.STORE), + DSTORE_2(RawBytecodeHelper.DSTORE_2, 1, Kind.STORE), /** Store double into local variable 3 */ - DSTORE_3(ClassFile.DSTORE_3, 1, Kind.STORE), + DSTORE_3(RawBytecodeHelper.DSTORE_3, 1, Kind.STORE), /** Store reference into local variable 0 */ - ASTORE_0(ClassFile.ASTORE_0, 1, Kind.STORE), + ASTORE_0(RawBytecodeHelper.ASTORE_0, 1, Kind.STORE), /** Store reference into local variable 1 */ - ASTORE_1(ClassFile.ASTORE_1, 1, Kind.STORE), + ASTORE_1(RawBytecodeHelper.ASTORE_1, 1, Kind.STORE), /** Store reference into local variable 2 */ - ASTORE_2(ClassFile.ASTORE_2, 1, Kind.STORE), + ASTORE_2(RawBytecodeHelper.ASTORE_2, 1, Kind.STORE), /** Store reference into local variable 3 */ - ASTORE_3(ClassFile.ASTORE_3, 1, Kind.STORE), + ASTORE_3(RawBytecodeHelper.ASTORE_3, 1, Kind.STORE), /** Store into int array */ - IASTORE(ClassFile.IASTORE, 1, Kind.ARRAY_STORE), + IASTORE(RawBytecodeHelper.IASTORE, 1, Kind.ARRAY_STORE), /** Store into long array */ - LASTORE(ClassFile.LASTORE, 1, Kind.ARRAY_STORE), + LASTORE(RawBytecodeHelper.LASTORE, 1, Kind.ARRAY_STORE), /** Store into float array */ - FASTORE(ClassFile.FASTORE, 1, Kind.ARRAY_STORE), + FASTORE(RawBytecodeHelper.FASTORE, 1, Kind.ARRAY_STORE), /** Store into double array */ - DASTORE(ClassFile.DASTORE, 1, Kind.ARRAY_STORE), + DASTORE(RawBytecodeHelper.DASTORE, 1, Kind.ARRAY_STORE), /** Store into reference array */ - AASTORE(ClassFile.AASTORE, 1, Kind.ARRAY_STORE), + AASTORE(RawBytecodeHelper.AASTORE, 1, Kind.ARRAY_STORE), /** Store into byte array */ - BASTORE(ClassFile.BASTORE, 1, Kind.ARRAY_STORE), + BASTORE(RawBytecodeHelper.BASTORE, 1, Kind.ARRAY_STORE), /** Store into char array */ - CASTORE(ClassFile.CASTORE, 1, Kind.ARRAY_STORE), + CASTORE(RawBytecodeHelper.CASTORE, 1, Kind.ARRAY_STORE), /** Store into short array */ - SASTORE(ClassFile.SASTORE, 1, Kind.ARRAY_STORE), + SASTORE(RawBytecodeHelper.SASTORE, 1, Kind.ARRAY_STORE), /** Pop the top operand stack value */ - POP(ClassFile.POP, 1, Kind.STACK), + POP(RawBytecodeHelper.POP, 1, Kind.STACK), /** Pop the top one or two operand stack values */ - POP2(ClassFile.POP2, 1, Kind.STACK), + POP2(RawBytecodeHelper.POP2, 1, Kind.STACK), /** Duplicate the top operand stack value */ - DUP(ClassFile.DUP, 1, Kind.STACK), + DUP(RawBytecodeHelper.DUP, 1, Kind.STACK), /** Duplicate the top operand stack value and insert two values down */ - DUP_X1(ClassFile.DUP_X1, 1, Kind.STACK), + DUP_X1(RawBytecodeHelper.DUP_X1, 1, Kind.STACK), /** Duplicate the top operand stack value and insert two or three values down */ - DUP_X2(ClassFile.DUP_X2, 1, Kind.STACK), + DUP_X2(RawBytecodeHelper.DUP_X2, 1, Kind.STACK), /** Duplicate the top one or two operand stack values */ - DUP2(ClassFile.DUP2, 1, Kind.STACK), + DUP2(RawBytecodeHelper.DUP2, 1, Kind.STACK), /** Duplicate the top one or two operand stack values and insert two or three values down */ - DUP2_X1(ClassFile.DUP2_X1, 1, Kind.STACK), + DUP2_X1(RawBytecodeHelper.DUP2_X1, 1, Kind.STACK), /** Duplicate the top one or two operand stack values and insert two, three, or four values down */ - DUP2_X2(ClassFile.DUP2_X2, 1, Kind.STACK), + DUP2_X2(RawBytecodeHelper.DUP2_X2, 1, Kind.STACK), /** Swap the top two operand stack values */ - SWAP(ClassFile.SWAP, 1, Kind.STACK), + SWAP(RawBytecodeHelper.SWAP, 1, Kind.STACK), /** Add int */ - IADD(ClassFile.IADD, 1, Kind.OPERATOR), + IADD(RawBytecodeHelper.IADD, 1, Kind.OPERATOR), /** Add long */ - LADD(ClassFile.LADD, 1, Kind.OPERATOR), + LADD(RawBytecodeHelper.LADD, 1, Kind.OPERATOR), /** Add float */ - FADD(ClassFile.FADD, 1, Kind.OPERATOR), + FADD(RawBytecodeHelper.FADD, 1, Kind.OPERATOR), /** Add double */ - DADD(ClassFile.DADD, 1, Kind.OPERATOR), + DADD(RawBytecodeHelper.DADD, 1, Kind.OPERATOR), /** Subtract int */ - ISUB(ClassFile.ISUB, 1, Kind.OPERATOR), + ISUB(RawBytecodeHelper.ISUB, 1, Kind.OPERATOR), /** Subtract long */ - LSUB(ClassFile.LSUB, 1, Kind.OPERATOR), + LSUB(RawBytecodeHelper.LSUB, 1, Kind.OPERATOR), /** Subtract float */ - FSUB(ClassFile.FSUB, 1, Kind.OPERATOR), + FSUB(RawBytecodeHelper.FSUB, 1, Kind.OPERATOR), /** Subtract double */ - DSUB(ClassFile.DSUB, 1, Kind.OPERATOR), + DSUB(RawBytecodeHelper.DSUB, 1, Kind.OPERATOR), /** Multiply int */ - IMUL(ClassFile.IMUL, 1, Kind.OPERATOR), + IMUL(RawBytecodeHelper.IMUL, 1, Kind.OPERATOR), /** Multiply long */ - LMUL(ClassFile.LMUL, 1, Kind.OPERATOR), + LMUL(RawBytecodeHelper.LMUL, 1, Kind.OPERATOR), /** Multiply float */ - FMUL(ClassFile.FMUL, 1, Kind.OPERATOR), + FMUL(RawBytecodeHelper.FMUL, 1, Kind.OPERATOR), /** Multiply double */ - DMUL(ClassFile.DMUL, 1, Kind.OPERATOR), + DMUL(RawBytecodeHelper.DMUL, 1, Kind.OPERATOR), /** Divide int */ - IDIV(ClassFile.IDIV, 1, Kind.OPERATOR), + IDIV(RawBytecodeHelper.IDIV, 1, Kind.OPERATOR), /** Divide long */ - LDIV(ClassFile.LDIV, 1, Kind.OPERATOR), + LDIV(RawBytecodeHelper.LDIV, 1, Kind.OPERATOR), /** Divide float */ - FDIV(ClassFile.FDIV, 1, Kind.OPERATOR), + FDIV(RawBytecodeHelper.FDIV, 1, Kind.OPERATOR), /** Divide double */ - DDIV(ClassFile.DDIV, 1, Kind.OPERATOR), + DDIV(RawBytecodeHelper.DDIV, 1, Kind.OPERATOR), /** Remainder int */ - IREM(ClassFile.IREM, 1, Kind.OPERATOR), + IREM(RawBytecodeHelper.IREM, 1, Kind.OPERATOR), /** Remainder long */ - LREM(ClassFile.LREM, 1, Kind.OPERATOR), + LREM(RawBytecodeHelper.LREM, 1, Kind.OPERATOR), /** Remainder float */ - FREM(ClassFile.FREM, 1, Kind.OPERATOR), + FREM(RawBytecodeHelper.FREM, 1, Kind.OPERATOR), /** Remainder double */ - DREM(ClassFile.DREM, 1, Kind.OPERATOR), + DREM(RawBytecodeHelper.DREM, 1, Kind.OPERATOR), /** Negate int */ - INEG(ClassFile.INEG, 1, Kind.OPERATOR), + INEG(RawBytecodeHelper.INEG, 1, Kind.OPERATOR), /** Negate long */ - LNEG(ClassFile.LNEG, 1, Kind.OPERATOR), + LNEG(RawBytecodeHelper.LNEG, 1, Kind.OPERATOR), /** Negate float */ - FNEG(ClassFile.FNEG, 1, Kind.OPERATOR), + FNEG(RawBytecodeHelper.FNEG, 1, Kind.OPERATOR), /** Negate double */ - DNEG(ClassFile.DNEG, 1, Kind.OPERATOR), + DNEG(RawBytecodeHelper.DNEG, 1, Kind.OPERATOR), /** Shift left int */ - ISHL(ClassFile.ISHL, 1, Kind.OPERATOR), + ISHL(RawBytecodeHelper.ISHL, 1, Kind.OPERATOR), /** Shift left long */ - LSHL(ClassFile.LSHL, 1, Kind.OPERATOR), + LSHL(RawBytecodeHelper.LSHL, 1, Kind.OPERATOR), /** Shift right int */ - ISHR(ClassFile.ISHR, 1, Kind.OPERATOR), + ISHR(RawBytecodeHelper.ISHR, 1, Kind.OPERATOR), /** Shift right long */ - LSHR(ClassFile.LSHR, 1, Kind.OPERATOR), + LSHR(RawBytecodeHelper.LSHR, 1, Kind.OPERATOR), /** Logical shift right int */ - IUSHR(ClassFile.IUSHR, 1, Kind.OPERATOR), + IUSHR(RawBytecodeHelper.IUSHR, 1, Kind.OPERATOR), /** Logical shift right long */ - LUSHR(ClassFile.LUSHR, 1, Kind.OPERATOR), + LUSHR(RawBytecodeHelper.LUSHR, 1, Kind.OPERATOR), /** Boolean AND int */ - IAND(ClassFile.IAND, 1, Kind.OPERATOR), + IAND(RawBytecodeHelper.IAND, 1, Kind.OPERATOR), /** Boolean AND long */ - LAND(ClassFile.LAND, 1, Kind.OPERATOR), + LAND(RawBytecodeHelper.LAND, 1, Kind.OPERATOR), /** Boolean OR int */ - IOR(ClassFile.IOR, 1, Kind.OPERATOR), + IOR(RawBytecodeHelper.IOR, 1, Kind.OPERATOR), /** Boolean OR long */ - LOR(ClassFile.LOR, 1, Kind.OPERATOR), + LOR(RawBytecodeHelper.LOR, 1, Kind.OPERATOR), /** Boolean XOR int */ - IXOR(ClassFile.IXOR, 1, Kind.OPERATOR), + IXOR(RawBytecodeHelper.IXOR, 1, Kind.OPERATOR), /** Boolean XOR long */ - LXOR(ClassFile.LXOR, 1, Kind.OPERATOR), + LXOR(RawBytecodeHelper.LXOR, 1, Kind.OPERATOR), /** Increment local variable by constant */ - IINC(ClassFile.IINC, 3, Kind.INCREMENT), + IINC(RawBytecodeHelper.IINC, 3, Kind.INCREMENT), /** Convert int to long */ - I2L(ClassFile.I2L, 1, Kind.CONVERT), + I2L(RawBytecodeHelper.I2L, 1, Kind.CONVERT), /** Convert int to float */ - I2F(ClassFile.I2F, 1, Kind.CONVERT), + I2F(RawBytecodeHelper.I2F, 1, Kind.CONVERT), /** Convert int to double */ - I2D(ClassFile.I2D, 1, Kind.CONVERT), + I2D(RawBytecodeHelper.I2D, 1, Kind.CONVERT), /** Convert long to int */ - L2I(ClassFile.L2I, 1, Kind.CONVERT), + L2I(RawBytecodeHelper.L2I, 1, Kind.CONVERT), /** Convert long to float */ - L2F(ClassFile.L2F, 1, Kind.CONVERT), + L2F(RawBytecodeHelper.L2F, 1, Kind.CONVERT), /** Convert long to double */ - L2D(ClassFile.L2D, 1, Kind.CONVERT), + L2D(RawBytecodeHelper.L2D, 1, Kind.CONVERT), /** Convert float to int */ - F2I(ClassFile.F2I, 1, Kind.CONVERT), + F2I(RawBytecodeHelper.F2I, 1, Kind.CONVERT), /** Convert float to long */ - F2L(ClassFile.F2L, 1, Kind.CONVERT), + F2L(RawBytecodeHelper.F2L, 1, Kind.CONVERT), /** Convert float to double */ - F2D(ClassFile.F2D, 1, Kind.CONVERT), + F2D(RawBytecodeHelper.F2D, 1, Kind.CONVERT), /** Convert double to int */ - D2I(ClassFile.D2I, 1, Kind.CONVERT), + D2I(RawBytecodeHelper.D2I, 1, Kind.CONVERT), /** Convert double to long */ - D2L(ClassFile.D2L, 1, Kind.CONVERT), + D2L(RawBytecodeHelper.D2L, 1, Kind.CONVERT), /** Convert double to float */ - D2F(ClassFile.D2F, 1, Kind.CONVERT), + D2F(RawBytecodeHelper.D2F, 1, Kind.CONVERT), /** Convert int to byte */ - I2B(ClassFile.I2B, 1, Kind.CONVERT), + I2B(RawBytecodeHelper.I2B, 1, Kind.CONVERT), /** Convert int to char */ - I2C(ClassFile.I2C, 1, Kind.CONVERT), + I2C(RawBytecodeHelper.I2C, 1, Kind.CONVERT), /** Convert int to short */ - I2S(ClassFile.I2S, 1, Kind.CONVERT), + I2S(RawBytecodeHelper.I2S, 1, Kind.CONVERT), /** Compare long */ - LCMP(ClassFile.LCMP, 1, Kind.OPERATOR), + LCMP(RawBytecodeHelper.LCMP, 1, Kind.OPERATOR), /** Compare float */ - FCMPL(ClassFile.FCMPL, 1, Kind.OPERATOR), + FCMPL(RawBytecodeHelper.FCMPL, 1, Kind.OPERATOR), /** Compare float */ - FCMPG(ClassFile.FCMPG, 1, Kind.OPERATOR), + FCMPG(RawBytecodeHelper.FCMPG, 1, Kind.OPERATOR), /** Compare double */ - DCMPL(ClassFile.DCMPL, 1, Kind.OPERATOR), + DCMPL(RawBytecodeHelper.DCMPL, 1, Kind.OPERATOR), /** Compare double */ - DCMPG(ClassFile.DCMPG, 1, Kind.OPERATOR), + DCMPG(RawBytecodeHelper.DCMPG, 1, Kind.OPERATOR), /** Branch if int comparison with zero succeeds */ - IFEQ(ClassFile.IFEQ, 3, Kind.BRANCH), + IFEQ(RawBytecodeHelper.IFEQ, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFNE(ClassFile.IFNE, 3, Kind.BRANCH), + IFNE(RawBytecodeHelper.IFNE, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFLT(ClassFile.IFLT, 3, Kind.BRANCH), + IFLT(RawBytecodeHelper.IFLT, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFGE(ClassFile.IFGE, 3, Kind.BRANCH), + IFGE(RawBytecodeHelper.IFGE, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFGT(ClassFile.IFGT, 3, Kind.BRANCH), + IFGT(RawBytecodeHelper.IFGT, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFLE(ClassFile.IFLE, 3, Kind.BRANCH), + IFLE(RawBytecodeHelper.IFLE, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPEQ(ClassFile.IF_ICMPEQ, 3, Kind.BRANCH), + IF_ICMPEQ(RawBytecodeHelper.IF_ICMPEQ, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPNE(ClassFile.IF_ICMPNE, 3, Kind.BRANCH), + IF_ICMPNE(RawBytecodeHelper.IF_ICMPNE, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPLT(ClassFile.IF_ICMPLT, 3, Kind.BRANCH), + IF_ICMPLT(RawBytecodeHelper.IF_ICMPLT, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPGE(ClassFile.IF_ICMPGE, 3, Kind.BRANCH), + IF_ICMPGE(RawBytecodeHelper.IF_ICMPGE, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPGT(ClassFile.IF_ICMPGT, 3, Kind.BRANCH), + IF_ICMPGT(RawBytecodeHelper.IF_ICMPGT, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPLE(ClassFile.IF_ICMPLE, 3, Kind.BRANCH), + IF_ICMPLE(RawBytecodeHelper.IF_ICMPLE, 3, Kind.BRANCH), /** Branch if reference comparison succeeds */ - IF_ACMPEQ(ClassFile.IF_ACMPEQ, 3, Kind.BRANCH), + IF_ACMPEQ(RawBytecodeHelper.IF_ACMPEQ, 3, Kind.BRANCH), /** Branch if reference comparison succeeds */ - IF_ACMPNE(ClassFile.IF_ACMPNE, 3, Kind.BRANCH), + IF_ACMPNE(RawBytecodeHelper.IF_ACMPNE, 3, Kind.BRANCH), /** Branch always */ - GOTO(ClassFile.GOTO, 3, Kind.BRANCH), + GOTO(RawBytecodeHelper.GOTO, 3, Kind.BRANCH), /** * Jump subroutine is discontinued opcode * @see java.lang.classfile.instruction.DiscontinuedInstruction */ - JSR(ClassFile.JSR, 3, Kind.DISCONTINUED_JSR), + JSR(RawBytecodeHelper.JSR, 3, Kind.DISCONTINUED_JSR), /** * Return from subroutine is discontinued opcode * @see java.lang.classfile.instruction.DiscontinuedInstruction */ - RET(ClassFile.RET, 2, Kind.DISCONTINUED_RET), + RET(RawBytecodeHelper.RET, 2, Kind.DISCONTINUED_RET), /** Access jump table by index and jump */ - TABLESWITCH(ClassFile.TABLESWITCH, -1, Kind.TABLE_SWITCH), + TABLESWITCH(RawBytecodeHelper.TABLESWITCH, -1, Kind.TABLE_SWITCH), /** Access jump table by key match and jump */ - LOOKUPSWITCH(ClassFile.LOOKUPSWITCH, -1, Kind.LOOKUP_SWITCH), + LOOKUPSWITCH(RawBytecodeHelper.LOOKUPSWITCH, -1, Kind.LOOKUP_SWITCH), /** Return int from method */ - IRETURN(ClassFile.IRETURN, 1, Kind.RETURN), + IRETURN(RawBytecodeHelper.IRETURN, 1, Kind.RETURN), /** Return long from method */ - LRETURN(ClassFile.LRETURN, 1, Kind.RETURN), + LRETURN(RawBytecodeHelper.LRETURN, 1, Kind.RETURN), /** Return float from method */ - FRETURN(ClassFile.FRETURN, 1, Kind.RETURN), + FRETURN(RawBytecodeHelper.FRETURN, 1, Kind.RETURN), /** Return double from method */ - DRETURN(ClassFile.DRETURN, 1, Kind.RETURN), + DRETURN(RawBytecodeHelper.DRETURN, 1, Kind.RETURN), /** Return reference from method */ - ARETURN(ClassFile.ARETURN, 1, Kind.RETURN), + ARETURN(RawBytecodeHelper.ARETURN, 1, Kind.RETURN), /** Return void from method */ - RETURN(ClassFile.RETURN, 1, Kind.RETURN), + RETURN(RawBytecodeHelper.RETURN, 1, Kind.RETURN), /** Get static field from class */ - GETSTATIC(ClassFile.GETSTATIC, 3, Kind.FIELD_ACCESS), + GETSTATIC(RawBytecodeHelper.GETSTATIC, 3, Kind.FIELD_ACCESS), /** Set static field in class */ - PUTSTATIC(ClassFile.PUTSTATIC, 3, Kind.FIELD_ACCESS), + PUTSTATIC(RawBytecodeHelper.PUTSTATIC, 3, Kind.FIELD_ACCESS), /** Fetch field from object */ - GETFIELD(ClassFile.GETFIELD, 3, Kind.FIELD_ACCESS), + GETFIELD(RawBytecodeHelper.GETFIELD, 3, Kind.FIELD_ACCESS), /** Set field in object */ - PUTFIELD(ClassFile.PUTFIELD, 3, Kind.FIELD_ACCESS), + PUTFIELD(RawBytecodeHelper.PUTFIELD, 3, Kind.FIELD_ACCESS), /** Invoke instance method; dispatch based on class */ - INVOKEVIRTUAL(ClassFile.INVOKEVIRTUAL, 3, Kind.INVOKE), + INVOKEVIRTUAL(RawBytecodeHelper.INVOKEVIRTUAL, 3, Kind.INVOKE), /** * Invoke instance method; direct invocation of instance initialization * methods and methods of the current class and its supertypes */ - INVOKESPECIAL(ClassFile.INVOKESPECIAL, 3, Kind.INVOKE), + INVOKESPECIAL(RawBytecodeHelper.INVOKESPECIAL, 3, Kind.INVOKE), /** Invoke a class (static) method */ - INVOKESTATIC(ClassFile.INVOKESTATIC, 3, Kind.INVOKE), + INVOKESTATIC(RawBytecodeHelper.INVOKESTATIC, 3, Kind.INVOKE), /** Invoke interface method */ - INVOKEINTERFACE(ClassFile.INVOKEINTERFACE, 5, Kind.INVOKE), + INVOKEINTERFACE(RawBytecodeHelper.INVOKEINTERFACE, 5, Kind.INVOKE), /** Invoke a dynamically-computed call site */ - INVOKEDYNAMIC(ClassFile.INVOKEDYNAMIC, 5, Kind.INVOKE_DYNAMIC), + INVOKEDYNAMIC(RawBytecodeHelper.INVOKEDYNAMIC, 5, Kind.INVOKE_DYNAMIC), /** Create new object */ - NEW(ClassFile.NEW, 3, Kind.NEW_OBJECT), + NEW(RawBytecodeHelper.NEW, 3, Kind.NEW_OBJECT), /** Create new array */ - NEWARRAY(ClassFile.NEWARRAY, 2, Kind.NEW_PRIMITIVE_ARRAY), + NEWARRAY(RawBytecodeHelper.NEWARRAY, 2, Kind.NEW_PRIMITIVE_ARRAY), /** Create new array of reference */ - ANEWARRAY(ClassFile.ANEWARRAY, 3, Kind.NEW_REF_ARRAY), + ANEWARRAY(RawBytecodeHelper.ANEWARRAY, 3, Kind.NEW_REF_ARRAY), /** Get length of array */ - ARRAYLENGTH(ClassFile.ARRAYLENGTH, 1, Kind.OPERATOR), + ARRAYLENGTH(RawBytecodeHelper.ARRAYLENGTH, 1, Kind.OPERATOR), /** Throw exception or error */ - ATHROW(ClassFile.ATHROW, 1, Kind.THROW_EXCEPTION), + ATHROW(RawBytecodeHelper.ATHROW, 1, Kind.THROW_EXCEPTION), /** Check whether object is of given type */ - CHECKCAST(ClassFile.CHECKCAST, 3, Kind.TYPE_CHECK), + CHECKCAST(RawBytecodeHelper.CHECKCAST, 3, Kind.TYPE_CHECK), /** Determine if object is of given type */ - INSTANCEOF(ClassFile.INSTANCEOF, 3, Kind.TYPE_CHECK), + INSTANCEOF(RawBytecodeHelper.INSTANCEOF, 3, Kind.TYPE_CHECK), /** Enter monitor for object */ - MONITORENTER(ClassFile.MONITORENTER, 1, Kind.MONITOR), + MONITORENTER(RawBytecodeHelper.MONITORENTER, 1, Kind.MONITOR), /** Exit monitor for object */ - MONITOREXIT(ClassFile.MONITOREXIT, 1, Kind.MONITOR), + MONITOREXIT(RawBytecodeHelper.MONITOREXIT, 1, Kind.MONITOR), /** Create new multidimensional array */ - MULTIANEWARRAY(ClassFile.MULTIANEWARRAY, 4, Kind.NEW_MULTI_ARRAY), + MULTIANEWARRAY(RawBytecodeHelper.MULTIANEWARRAY, 4, Kind.NEW_MULTI_ARRAY), /** Branch if reference is null */ - IFNULL(ClassFile.IFNULL, 3, Kind.BRANCH), + IFNULL(RawBytecodeHelper.IFNULL, 3, Kind.BRANCH), /** Branch if reference not null */ - IFNONNULL(ClassFile.IFNONNULL, 3, Kind.BRANCH), + IFNONNULL(RawBytecodeHelper.IFNONNULL, 3, Kind.BRANCH), /** Branch always (wide index) */ - GOTO_W(ClassFile.GOTO_W, 5, Kind.BRANCH), + GOTO_W(RawBytecodeHelper.GOTO_W, 5, Kind.BRANCH), /** * Jump subroutine (wide index) is discontinued opcode * @see java.lang.classfile.instruction.DiscontinuedInstruction */ - JSR_W(ClassFile.JSR_W, 5, Kind.DISCONTINUED_JSR), + JSR_W(RawBytecodeHelper.JSR_W, 5, Kind.DISCONTINUED_JSR), /** Load int from local variable (wide index) */ - ILOAD_W((ClassFile.WIDE << 8) | ClassFile.ILOAD, 4, Kind.LOAD), + ILOAD_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.ILOAD, 4, Kind.LOAD), /** Load long from local variable (wide index) */ - LLOAD_W((ClassFile.WIDE << 8) | ClassFile.LLOAD, 4, Kind.LOAD), + LLOAD_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.LLOAD, 4, Kind.LOAD), /** Load float from local variable (wide index) */ - FLOAD_W((ClassFile.WIDE << 8) | ClassFile.FLOAD, 4, Kind.LOAD), + FLOAD_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.FLOAD, 4, Kind.LOAD), /** Load double from local variable (wide index) */ - DLOAD_W((ClassFile.WIDE << 8) | ClassFile.DLOAD, 4, Kind.LOAD), + DLOAD_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.DLOAD, 4, Kind.LOAD), /** Load reference from local variable (wide index) */ - ALOAD_W((ClassFile.WIDE << 8) | ClassFile.ALOAD, 4, Kind.LOAD), + ALOAD_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.ALOAD, 4, Kind.LOAD), /** Store int into local variable (wide index) */ - ISTORE_W((ClassFile.WIDE << 8) | ClassFile.ISTORE, 4, Kind.STORE), + ISTORE_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.ISTORE, 4, Kind.STORE), /** Store long into local variable (wide index) */ - LSTORE_W((ClassFile.WIDE << 8) | ClassFile.LSTORE, 4, Kind.STORE), + LSTORE_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.LSTORE, 4, Kind.STORE), /** Store float into local variable (wide index) */ - FSTORE_W((ClassFile.WIDE << 8) | ClassFile.FSTORE, 4, Kind.STORE), + FSTORE_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.FSTORE, 4, Kind.STORE), /** Store double into local variable (wide index) */ - DSTORE_W((ClassFile.WIDE << 8) | ClassFile.DSTORE, 4, Kind.STORE), + DSTORE_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.DSTORE, 4, Kind.STORE), /** Store reference into local variable (wide index) */ - ASTORE_W((ClassFile.WIDE << 8) | ClassFile.ASTORE, 4, Kind.STORE), + ASTORE_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.ASTORE, 4, Kind.STORE), /** * Return from subroutine (wide index) is discontinued opcode * @see java.lang.classfile.instruction.DiscontinuedInstruction */ - RET_W((ClassFile.WIDE << 8) | ClassFile.RET, 4, Kind.DISCONTINUED_RET), + RET_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.RET, 4, Kind.DISCONTINUED_RET), /** Increment local variable by constant (wide index) */ - IINC_W((ClassFile.WIDE << 8) | ClassFile.IINC, 6, Kind.INCREMENT); + IINC_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.IINC, 6, Kind.INCREMENT); /** * Kinds of opcodes. @@ -1085,13 +1086,13 @@ public static enum Kind { /** * {@return the opcode value} For {@linkplain #isWide() wide} pseudo-opcodes, returns the - * first 2 bytes of the instruction, which are the {@code wide} opcode and the functional - * local variable opcode, as a U2 value. + * first 2 bytes of the instruction, which are the wide opcode {@code 196} ({@code 0xC4}) + * and the functional opcode, as a U2 value. */ public int bytecode() { return bytecode; } /** - * {@return true if this is a pseudo-opcode modified by {@code wide}} + * {@return true if this is a pseudo-opcode modified by wide opcode} * * @see #ILOAD_W * @see #LLOAD_W diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index b6c9aec76a1a3..139c8eef835dc 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -31,31 +31,10 @@ import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; import jdk.internal.classfile.impl.TargetInfoImpl; import jdk.internal.classfile.impl.UnboundAttribute; - -import static java.lang.classfile.ClassFile.TAT_CAST; -import static java.lang.classfile.ClassFile.TAT_CLASS_EXTENDS; -import static java.lang.classfile.ClassFile.TAT_CLASS_TYPE_PARAMETER; -import static java.lang.classfile.ClassFile.TAT_CLASS_TYPE_PARAMETER_BOUND; -import static java.lang.classfile.ClassFile.TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT; -import static java.lang.classfile.ClassFile.TAT_CONSTRUCTOR_REFERENCE; -import static java.lang.classfile.ClassFile.TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT; -import static java.lang.classfile.ClassFile.TAT_EXCEPTION_PARAMETER; -import static java.lang.classfile.ClassFile.TAT_FIELD; -import static java.lang.classfile.ClassFile.TAT_INSTANCEOF; -import static java.lang.classfile.ClassFile.TAT_LOCAL_VARIABLE; -import static java.lang.classfile.ClassFile.TAT_METHOD_FORMAL_PARAMETER; -import static java.lang.classfile.ClassFile.TAT_METHOD_INVOCATION_TYPE_ARGUMENT; -import static java.lang.classfile.ClassFile.TAT_METHOD_RECEIVER; -import static java.lang.classfile.ClassFile.TAT_METHOD_REFERENCE; -import static java.lang.classfile.ClassFile.TAT_METHOD_REFERENCE_TYPE_ARGUMENT; -import static java.lang.classfile.ClassFile.TAT_METHOD_RETURN; -import static java.lang.classfile.ClassFile.TAT_METHOD_TYPE_PARAMETER; -import static java.lang.classfile.ClassFile.TAT_METHOD_TYPE_PARAMETER_BOUND; -import static java.lang.classfile.ClassFile.TAT_NEW; -import static java.lang.classfile.ClassFile.TAT_RESOURCE_VARIABLE; -import static java.lang.classfile.ClassFile.TAT_THROWS; import jdk.internal.javac.PreviewFeature; +import static java.lang.classfile.TypeAnnotation.TargetInfo.*; + /** * Models a {@code type_annotation} structure (JVMS {@jvms 4.7.20}). This model * indicates the annotated type within a declaration or expression and the part @@ -87,70 +66,70 @@ public sealed interface TypeAnnotation @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public enum TargetType { /** For annotations on a class type parameter declaration. */ - CLASS_TYPE_PARAMETER(TAT_CLASS_TYPE_PARAMETER, 1), + CLASS_TYPE_PARAMETER(TARGET_CLASS_TYPE_PARAMETER, 1), /** For annotations on a method type parameter declaration. */ - METHOD_TYPE_PARAMETER(TAT_METHOD_TYPE_PARAMETER, 1), + METHOD_TYPE_PARAMETER(TARGET_METHOD_TYPE_PARAMETER, 1), /** For annotations on the type of an "extends" or "implements" clause. */ - CLASS_EXTENDS(TAT_CLASS_EXTENDS, 2), + CLASS_EXTENDS(TARGET_CLASS_EXTENDS, 2), /** For annotations on a bound of a type parameter of a class. */ - CLASS_TYPE_PARAMETER_BOUND(TAT_CLASS_TYPE_PARAMETER_BOUND, 2), + CLASS_TYPE_PARAMETER_BOUND(TARGET_CLASS_TYPE_PARAMETER_BOUND, 2), /** For annotations on a bound of a type parameter of a method. */ - METHOD_TYPE_PARAMETER_BOUND(TAT_METHOD_TYPE_PARAMETER_BOUND, 2), + METHOD_TYPE_PARAMETER_BOUND(TARGET_METHOD_TYPE_PARAMETER_BOUND, 2), /** For annotations on a field. */ - FIELD(TAT_FIELD, 0), + FIELD(TARGET_FIELD, 0), /** For annotations on a method return type. */ - METHOD_RETURN(TAT_METHOD_RETURN, 0), + METHOD_RETURN(TARGET_METHOD_RETURN, 0), /** For annotations on the method receiver. */ - METHOD_RECEIVER(TAT_METHOD_RECEIVER, 0), + METHOD_RECEIVER(TARGET_METHOD_RECEIVER, 0), /** For annotations on a method parameter. */ - METHOD_FORMAL_PARAMETER(TAT_METHOD_FORMAL_PARAMETER, 1), + METHOD_FORMAL_PARAMETER(TARGET_METHOD_FORMAL_PARAMETER, 1), /** For annotations on a throws clause in a method declaration. */ - THROWS(TAT_THROWS, 2), + THROWS(TARGET_THROWS, 2), /** For annotations on a local variable. */ - LOCAL_VARIABLE(TAT_LOCAL_VARIABLE, -1), + LOCAL_VARIABLE(TARGET_LOCAL_VARIABLE, -1), /** For annotations on a resource variable. */ - RESOURCE_VARIABLE(TAT_RESOURCE_VARIABLE, -1), + RESOURCE_VARIABLE(TARGET_RESOURCE_VARIABLE, -1), /** For annotations on an exception parameter. */ - EXCEPTION_PARAMETER(TAT_EXCEPTION_PARAMETER, 2), + EXCEPTION_PARAMETER(TARGET_EXCEPTION_PARAMETER, 2), /** For annotations on a type test. */ - INSTANCEOF(TAT_INSTANCEOF, 2), + INSTANCEOF(TARGET_INSTANCEOF, 2), /** For annotations on an object creation expression. */ - NEW(TAT_NEW, 2), + NEW(TARGET_NEW, 2), /** For annotations on a constructor reference receiver. */ - CONSTRUCTOR_REFERENCE(TAT_CONSTRUCTOR_REFERENCE, 2), + CONSTRUCTOR_REFERENCE(TARGET_CONSTRUCTOR_REFERENCE, 2), /** For annotations on a method reference receiver. */ - METHOD_REFERENCE(TAT_METHOD_REFERENCE, 2), + METHOD_REFERENCE(TARGET_METHOD_REFERENCE, 2), /** For annotations on a typecast. */ - CAST(TAT_CAST, 3), + CAST(TARGET_CAST, 3), /** For annotations on a type argument of an object creation expression. */ - CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, 3), + CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, 3), /** For annotations on a type argument of a method call. */ - METHOD_INVOCATION_TYPE_ARGUMENT(TAT_METHOD_INVOCATION_TYPE_ARGUMENT, 3), + METHOD_INVOCATION_TYPE_ARGUMENT(TARGET_METHOD_INVOCATION_TYPE_ARGUMENT, 3), /** For annotations on a type argument of a constructor reference. */ - CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT, 3), + CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT, 3), /** For annotations on a type argument of a method reference. */ - METHOD_REFERENCE_TYPE_ARGUMENT(TAT_METHOD_REFERENCE_TYPE_ARGUMENT, 3); + METHOD_REFERENCE_TYPE_ARGUMENT(TARGET_METHOD_REFERENCE_TYPE_ARGUMENT, 3); private final int targetTypeValue; private final int sizeIfFixed; @@ -162,6 +141,11 @@ private TargetType(int targetTypeValue, int sizeIfFixed) { /** * {@return the target type value} + * + * @apiNote + * {@code TARGET_}-prefixed constants in {@link TargetInfo}, such as {@link + * TargetInfo#TARGET_CLASS_TYPE_PARAMETER}, describe the possible return + * values of this method. */ public int targetTypeValue() { return targetTypeValue; @@ -214,6 +198,146 @@ static TypeAnnotation of(TargetInfo targetInfo, List targetPa @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface TargetInfo { + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}. + */ + int TARGET_CLASS_TYPE_PARAMETER = 0x00; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. + */ + int TARGET_METHOD_TYPE_PARAMETER = 0x01; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CLASS_EXTENDS CLASS_EXTENDS}. + */ + int TARGET_CLASS_EXTENDS = 0x10; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CLASS_TYPE_PARAMETER_BOUND + * CLASS_TYPE_PARAMETER_BOUND}. + */ + int TARGET_CLASS_TYPE_PARAMETER_BOUND = 0x11; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_TYPE_PARAMETER_BOUND + * METHOD_TYPE_PARAMETER_BOUND}. + */ + int TARGET_METHOD_TYPE_PARAMETER_BOUND = 0x12; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#FIELD FIELD}. + */ + int TARGET_FIELD = 0x13; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_RETURN METHOD_RETURN}. + */ + int TARGET_METHOD_RETURN = 0x14; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_RECEIVER METHOD_RECEIVER}. + */ + int TARGET_METHOD_RECEIVER = 0x15; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_FORMAL_PARAMETER + * METHOD_FORMAL_PARAMETER}. + */ + int TARGET_METHOD_FORMAL_PARAMETER = 0x16; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#THROWS THROWS}. + */ + int TARGET_THROWS = 0x17; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#LOCAL_VARIABLE LOCAL_VARIABLE}. + */ + int TARGET_LOCAL_VARIABLE = 0x40; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#RESOURCE_VARIABLE RESOURCE_VARIABLE}. + */ + int TARGET_RESOURCE_VARIABLE = 0x41; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#EXCEPTION_PARAMETER EXCEPTION_PARAMETER}. + */ + int TARGET_EXCEPTION_PARAMETER = 0x42; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#INSTANCEOF INSTANCEOF}. + */ + int TARGET_INSTANCEOF = 0x43; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#NEW NEW}. + */ + int TARGET_NEW = 0x44; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CONSTRUCTOR_REFERENCE + * CONSTRUCTOR_REFERENCE}. + */ + int TARGET_CONSTRUCTOR_REFERENCE = 0x45; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_REFERENCE METHOD_REFERENCE}. + */ + int TARGET_METHOD_REFERENCE = 0x46; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CAST CAST}. + */ + int TARGET_CAST = 0x47; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT + * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}. + */ + int TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_INVOCATION_TYPE_ARGUMENT + * METHOD_INVOCATION_TYPE_ARGUMENT}. + */ + int TARGET_METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT + * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}. + */ + int TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_REFERENCE_TYPE_ARGUMENT + * METHOD_REFERENCE_TYPE_ARGUMENT}. + */ + int TARGET_METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; + /** * {@return the type of the target} */ diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java index 37abcb027132e..126ba1037cefb 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ */ package java.lang.classfile.attribute; +import java.lang.classfile.instruction.CharacterRange; + import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; @@ -70,17 +72,17 @@ public sealed interface CharacterRangeInfo * The value of the flags item describes the kind of range. Multiple flags * may be set within flags. *
    - *
  • {@link java.lang.classfile.ClassFile#CRT_STATEMENT} Range is a Statement + *
  • {@link CharacterRange#FLAG_STATEMENT} Range is a Statement * (except ExpressionStatement), StatementExpression {@jls 14.8}, as well as each * VariableDeclaratorId = VariableInitializer of * LocalVariableDeclarationStatement {@jls 14.4} or FieldDeclaration {@jls 8.3} in the * grammar. - *
  • {@link java.lang.classfile.ClassFile#CRT_BLOCK} Range is a Block in the + *
  • {@link CharacterRange#FLAG_BLOCK} Range is a Block in the * grammar. - *
  • {@link java.lang.classfile.ClassFile#CRT_ASSIGNMENT} Range is an assignment + *
  • {@link CharacterRange#FLAG_ASSIGNMENT} Range is an assignment * expression - Expression1 AssignmentOperator Expression1 in the grammar as * well as increment and decrement expressions (both prefix and postfix). - *
  • {@link java.lang.classfile.ClassFile#CRT_FLOW_CONTROLLER} An expression + *
  • {@link CharacterRange#FLAG_FLOW_CONTROLLER} An expression * whose value will effect control flow. {@code Flowcon} in the following: *
          * if ( Flowcon ) Statement [else Statement]
    @@ -92,7 +94,7 @@ public sealed interface CharacterRangeInfo
          * Flowcon && Expression3
          * Flowcon ? Expression : Expression1
          * 
    - *
  • {@link java.lang.classfile.ClassFile#CRT_FLOW_TARGET} Statement or + *
  • {@link CharacterRange#FLAG_FLOW_TARGET} Statement or * expression effected by a CRT_FLOW_CONTROLLER. {@code Flowtarg} in the following: *
          * if ( Flowcon ) Flowtarg [else Flowtarg]
    @@ -103,11 +105,11 @@ public sealed interface CharacterRangeInfo
          * Flowcon && Flowtarg
          * Flowcon ? Flowtarg : Flowtarg
          * 
    - *
  • {@link java.lang.classfile.ClassFile#CRT_INVOKE} Method invocation. For + *
  • {@link CharacterRange#FLAG_INVOKE} Method invocation. For * example: Identifier Arguments. - *
  • {@link java.lang.classfile.ClassFile#CRT_CREATE} New object creation. For + *
  • {@link CharacterRange#FLAG_CREATE} New object creation. For * example: new Creator. - *
  • {@link java.lang.classfile.ClassFile#CRT_BRANCH_TRUE} A condition encoded + *
  • {@link CharacterRange#FLAG_BRANCH_TRUE} A condition encoded * in the branch instruction immediately contained in the code range for * this item is not inverted towards the corresponding branch condition in * the source code. I.e. actual jump occurs if and only if the the source @@ -119,7 +121,7 @@ public sealed interface CharacterRangeInfo * if<cond>, ifnonull, ifnull or goto. CRT_BRANCH_TRUE and * CRT_BRANCH_FALSE are special kinds of entries that can be used to * determine what branch of a condition was chosen during the runtime. - *
  • {@link java.lang.classfile.ClassFile#CRT_BRANCH_FALSE} A condition encoded + *
  • {@link CharacterRange#FLAG_BRANCH_FALSE} A condition encoded * in the branch instruction immediately contained in the code range for * this item is inverted towards the corresponding branch condition in the * source code. I.e. actual jump occurs if and only if the the source code @@ -134,6 +136,7 @@ public sealed interface CharacterRangeInfo * All bits of the flags item not assigned above are reserved for future use. They should be set to zero in generated class files and should be ignored by Java virtual machine implementations. * * @return the flags + * @see CharacterRange#flags() */ int flags(); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java index 46caa66ef9adf..3415c89174ae9 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java @@ -32,7 +32,6 @@ import java.lang.classfile.constantpool.ClassEntry; import jdk.internal.classfile.impl.StackMapDecoder; import jdk.internal.classfile.impl.TemporaryConstantPool; -import static java.lang.classfile.ClassFile.*; import jdk.internal.javac.PreviewFeature; /** @@ -85,8 +84,39 @@ public static StackMapFrameInfo of(Label target, @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface VerificationTypeInfo { + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#TOP TOP}. */ + int ITEM_TOP = 0; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#INTEGER INTEGER}. */ + int ITEM_INTEGER = 1; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#FLOAT FLOAT}. */ + int ITEM_FLOAT = 2; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#DOUBLE DOUBLE}. */ + int ITEM_DOUBLE = 3; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#LONG LONG}. */ + int ITEM_LONG = 4; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#NULL NULL}. */ + int ITEM_NULL = 5; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#UNINITIALIZED_THIS UNINITIALIZED_THIS}. */ + int ITEM_UNINITIALIZED_THIS = 6; + + /** The {@link #tag() tag} for verification type info {@link ObjectVerificationTypeInfo OBJECT}. */ + int ITEM_OBJECT = 7; + + /** The {@link #tag() tag} for verification type info {@link UninitializedVerificationTypeInfo UNINITIALIZED}. */ + int ITEM_UNINITIALIZED = 8; + /** * {@return the tag of the type info} + * + * @apiNote + * {@code ITEM_}-prefixed constants in this class, such as {@link #ITEM_TOP}, describe the + * possible return values of this method. */ int tag(); } @@ -100,25 +130,25 @@ sealed interface VerificationTypeInfo { public enum SimpleVerificationTypeInfo implements VerificationTypeInfo { /** verification type top */ - ITEM_TOP(VT_TOP), + TOP(ITEM_TOP), /** verification type int */ - ITEM_INTEGER(VT_INTEGER), + INTEGER(ITEM_INTEGER), /** verification type float */ - ITEM_FLOAT(VT_FLOAT), + FLOAT(ITEM_FLOAT), /** verification type double */ - ITEM_DOUBLE(VT_DOUBLE), + DOUBLE(ITEM_DOUBLE), /** verification type long */ - ITEM_LONG(VT_LONG), + LONG(ITEM_LONG), /** verification type null */ - ITEM_NULL(VT_NULL), + NULL(ITEM_NULL), /** verification type uninitializedThis */ - ITEM_UNINITIALIZED_THIS(VT_UNINITIALIZED_THIS); + UNINITIALIZED_THIS(ITEM_UNINITIALIZED_THIS); private final int tag; @@ -134,7 +164,7 @@ public int tag() { } /** - * A stack value for an object type. + * A stack value for an object type. Its {@link #tag() tag} is {@value #ITEM_OBJECT}. * * @since 22 */ @@ -173,7 +203,7 @@ default ClassDesc classSymbol() { } /** - * An uninitialized stack value. + * An uninitialized stack value. Its {@link #tag() tag} is {@value #ITEM_UNINITIALIZED}. * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java index c8b74a139280e..d2af4c7c11ae5 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java @@ -38,6 +38,57 @@ public sealed interface PoolEntry LoadableConstantEntry, MemberRefEntry, ModuleEntry, NameAndTypeEntry, PackageEntry { + /** The {@linkplain #tag tag} for {@link ClassEntry CONSTANT_Class} constant kind. */ + int TAG_CLASS = 7; + + /** The {@linkplain #tag tag} for {@link DoubleEntry CONSTANT_Double} constant kind. */ + int TAG_DOUBLE = 6; + + /** The {@linkplain #tag tag} for {@link ConstantDynamicEntry CONSTANT_Dynamic} constant kind. */ + int TAG_DYNAMIC = 17; + + /** The {@linkplain #tag tag} for {@link FieldRefEntry CONSTANT_Fieldref} constant kind. */ + int TAG_FIELDREF = 9; + + /** The {@linkplain #tag tag} for {@link FloatEntry CONSTANT_Float} constant kind. */ + int TAG_FLOAT = 4; + + /** The {@linkplain #tag tag} for {@link IntegerEntry CONSTANT_Integer} constant kind. */ + int TAG_INTEGER = 3; + + /** The {@linkplain #tag tag} for {@link InterfaceMethodRefEntry CONSTANT_InterfaceMethodref} constant kind. */ + int TAG_INTERFACE_METHODREF = 11; + + /** The {@linkplain #tag tag} for {@link InvokeDynamicEntry CONSTANT_InvokeDynamic} constant kind. */ + int TAG_INVOKE_DYNAMIC = 18; + + /** The {@linkplain #tag tag} for {@link LongEntry CONSTANT_Long} constant kind. */ + int TAG_LONG = 5; + + /** The {@linkplain #tag tag} for {@link MethodHandleEntry CONSTANT_MethodHandle} constant kind. */ + int TAG_METHOD_HANDLE = 15; + + /** The {@linkplain #tag tag} for {@link MethodRefEntry CONSTANT_Methodref} constant kind. */ + int TAG_METHODREF = 10; + + /** The {@linkplain #tag tag} for {@link MethodTypeEntry CONSTANT_MethodType} constant kind. */ + int TAG_METHOD_TYPE = 16; + + /** The {@linkplain #tag tag} for {@link ModuleEntry CONSTANT_Module} constant kind. */ + int TAG_MODULE = 19; + + /** The {@linkplain #tag tag} for {@link NameAndTypeEntry CONSTANT_NameAndType} constant kind. */ + int TAG_NAME_AND_TYPE = 12; + + /** The {@linkplain #tag tag} for {@link PackageEntry CONSTANT_Package} constant kind. */ + int TAG_PACKAGE = 20; + + /** The {@linkplain #tag tag} for {@link StringEntry CONSTANT_String} constant kind. */ + int TAG_STRING = 8; + + /** The {@linkplain #tag tag} for {@link Utf8Entry CONSTANT_Utf8} constant kind. */ + int TAG_UTF8 = 1; + /** * {@return the constant pool this entry is from} */ @@ -45,6 +96,10 @@ public sealed interface PoolEntry /** * {@return the constant pool tag that describes the type of this entry} + * + * @apiNote + * {@code TAG_}-prefixed constants in this class, such as {@link #TAG_UTF8}, + * describe the possible return values of this method. */ byte tag(); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java index 89a54caeaf2fe..fca3279cd2228 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.lang.classfile.CodeModel; import java.lang.classfile.Label; import java.lang.classfile.PseudoInstruction; +import java.lang.classfile.attribute.CharacterRangeInfo; import java.lang.classfile.attribute.CharacterRangeTableAttribute; import jdk.internal.classfile.impl.AbstractPseudoInstruction; import jdk.internal.classfile.impl.BoundCharacterRange; @@ -45,6 +46,34 @@ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface CharacterRange extends PseudoInstruction permits AbstractPseudoInstruction.UnboundCharacterRange, BoundCharacterRange { + + /** The bit mask of STATEMENT {@link CharacterRangeInfo} kind. */ + int FLAG_STATEMENT = 0x0001; + + /** The bit mask of BLOCK {@link CharacterRangeInfo} kind. */ + int FLAG_BLOCK = 0x0002; + + /** The bit mask of ASSIGNMENT {@link CharacterRangeInfo} kind. */ + int FLAG_ASSIGNMENT = 0x0004; + + /** The bit mask of FLOW_CONTROLLER {@link CharacterRangeInfo} kind. */ + int FLAG_FLOW_CONTROLLER = 0x0008; + + /** The bit mask of FLOW_TARGET {@link CharacterRangeInfo} kind. */ + int FLAG_FLOW_TARGET = 0x0010; + + /** The bit mask of INVOKE {@link CharacterRangeInfo} kind. */ + int FLAG_INVOKE = 0x0020; + + /** The bit mask of CREATE {@link CharacterRangeInfo} kind. */ + int FLAG_CREATE = 0x0040; + + /** The bit mask of BRANCH_TRUE {@link CharacterRangeInfo} kind. */ + int FLAG_BRANCH_TRUE = 0x0080; + + /** The bit mask of BRANCH_FALSE {@link CharacterRangeInfo} kind. */ + int FLAG_BRANCH_FALSE = 0x0100; + /** * {@return the start of the instruction range} */ @@ -75,15 +104,15 @@ public sealed interface CharacterRange extends PseudoInstruction * A flags word, indicating the kind of range. Multiple flag bits * may be set. Valid flags include: *
      - *
    • {@link java.lang.classfile.ClassFile#CRT_STATEMENT} - *
    • {@link java.lang.classfile.ClassFile#CRT_BLOCK} - *
    • {@link java.lang.classfile.ClassFile#CRT_ASSIGNMENT} - *
    • {@link java.lang.classfile.ClassFile#CRT_FLOW_CONTROLLER} - *
    • {@link java.lang.classfile.ClassFile#CRT_FLOW_TARGET} - *
    • {@link java.lang.classfile.ClassFile#CRT_INVOKE} - *
    • {@link java.lang.classfile.ClassFile#CRT_CREATE} - *
    • {@link java.lang.classfile.ClassFile#CRT_BRANCH_TRUE} - *
    • {@link java.lang.classfile.ClassFile#CRT_BRANCH_FALSE} + *
    • {@link #FLAG_STATEMENT} + *
    • {@link #FLAG_BLOCK} + *
    • {@link #FLAG_ASSIGNMENT} + *
    • {@link #FLAG_FLOW_CONTROLLER} + *
    • {@link #FLAG_FLOW_TARGET} + *
    • {@link #FLAG_INVOKE} + *
    • {@link #FLAG_CREATE} + *
    • {@link #FLAG_BRANCH_TRUE} + *
    • {@link #FLAG_BRANCH_FALSE} *
    * * @see java.lang.classfile.attribute.CharacterRangeInfo#flags() diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index 48c0cb7685702..edcd6a7abff25 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java @@ -24,11 +24,11 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.constantpool.PoolEntry; import java.lang.constant.ConstantDesc; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.lang.classfile.ClassFile; import java.lang.classfile.Instruction; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.instruction.SwitchCase; @@ -421,7 +421,7 @@ public MemberRefEntry method() { @Override public boolean isInterface() { - return method().tag() == ClassFile.TAG_INTERFACEMETHODREF; + return method().tag() == PoolEntry.TAG_INTERFACE_METHODREF; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index 8498e77cb36bc..1d8d298857a7b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -30,7 +30,6 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.lang.classfile.ClassFile; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantDynamicEntry; import java.lang.classfile.constantpool.ConstantPool; @@ -57,8 +56,6 @@ import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.Stable; -import static java.lang.classfile.ClassFile.*; - public abstract sealed class AbstractPoolEntry { /* Invariant: a {CP,BSM} entry for pool P refer only to {CP,BSM} entries @@ -92,7 +89,7 @@ static int hashClassFromUtf8(boolean isArray, Utf8EntryImpl content) { } static int hashClassFromDescriptor(int descriptorHash) { - return hash1(ClassFile.TAG_CLASS, descriptorHash); + return hash1(PoolEntry.TAG_CLASS, descriptorHash); } static boolean isArrayDescriptor(Utf8EntryImpl cs) { @@ -570,17 +567,17 @@ public static final class ClassEntryImpl extends AbstractNamedEntry implements C super(cpm, TAG_CLASS, index, name); } - @Override - public byte tag() { - return TAG_CLASS; - } - ClassEntryImpl(ConstantPool cpm, int index, Utf8EntryImpl name, int hash, ClassDesc sym) { - super(cpm, ClassFile.TAG_CLASS, index, name); + super(cpm, TAG_CLASS, index, name); this.hash = hash; this.sym = sym; } + @Override + public byte tag() { + return TAG_CLASS; + } + @Override public ClassEntry clone(ConstantPoolBuilder cp) { return ((SplitConstantPool) cp).cloneClassEntry(this); @@ -696,12 +693,12 @@ public static final class NameAndTypeEntryImpl extends AbstractRefsEntry elements) implements Annotation { public AnnotationImpl { @@ -62,7 +60,7 @@ public record OfStringImpl(Utf8Entry constant) implements AnnotationValue.OfString { @Override public char tag() { - return AEV_STRING; + return TAG_STRING; } @Override @@ -75,7 +73,7 @@ public record OfDoubleImpl(DoubleEntry constant) implements AnnotationValue.OfDouble { @Override public char tag() { - return AEV_DOUBLE; + return TAG_DOUBLE; } @Override @@ -88,7 +86,7 @@ public record OfFloatImpl(FloatEntry constant) implements AnnotationValue.OfFloat { @Override public char tag() { - return AEV_FLOAT; + return TAG_FLOAT; } @Override @@ -101,7 +99,7 @@ public record OfLongImpl(LongEntry constant) implements AnnotationValue.OfLong { @Override public char tag() { - return AEV_LONG; + return TAG_LONG; } @Override @@ -114,7 +112,7 @@ public record OfIntImpl(IntegerEntry constant) implements AnnotationValue.OfInt { @Override public char tag() { - return AEV_INT; + return TAG_INT; } @Override @@ -127,7 +125,7 @@ public record OfShortImpl(IntegerEntry constant) implements AnnotationValue.OfShort { @Override public char tag() { - return AEV_SHORT; + return TAG_SHORT; } @Override @@ -140,7 +138,7 @@ public record OfCharImpl(IntegerEntry constant) implements AnnotationValue.OfChar { @Override public char tag() { - return AEV_CHAR; + return TAG_CHAR; } @Override @@ -153,7 +151,7 @@ public record OfByteImpl(IntegerEntry constant) implements AnnotationValue.OfByte { @Override public char tag() { - return AEV_BYTE; + return TAG_BYTE; } @Override @@ -166,7 +164,7 @@ public record OfBooleanImpl(IntegerEntry constant) implements AnnotationValue.OfBoolean { @Override public char tag() { - return AEV_BOOLEAN; + return TAG_BOOLEAN; } @Override @@ -183,7 +181,7 @@ public record OfArrayImpl(List values) @Override public char tag() { - return AEV_ARRAY; + return TAG_ARRAY; } } @@ -191,7 +189,7 @@ public record OfEnumImpl(Utf8Entry className, Utf8Entry constantName) implements AnnotationValue.OfEnum { @Override public char tag() { - return AEV_ENUM; + return TAG_ENUM; } } @@ -199,7 +197,7 @@ public record OfAnnotationImpl(Annotation annotation) implements AnnotationValue.OfAnnotation { @Override public char tag() { - return AEV_ANNOTATION; + return TAG_ANNOTATION; } } @@ -207,7 +205,7 @@ public record OfClassImpl(Utf8Entry className) implements AnnotationValue.OfClass { @Override public char tag() { - return AEV_CLASS; + return TAG_CLASS; } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index 69511131b3700..e33012ef18353 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -32,7 +32,8 @@ import java.lang.classfile.ClassReader; import java.lang.classfile.constantpool.*; import java.lang.classfile.TypeAnnotation; -import static java.lang.classfile.ClassFile.*; + +import static java.lang.classfile.AnnotationValue.*; import static java.lang.classfile.TypeAnnotation.TargetInfo.*; import java.util.List; @@ -59,20 +60,20 @@ public static AnnotationValue readElementValue(ClassReader classReader, int p) { char tag = (char) classReader.readU1(p); ++p; return switch (tag) { - case AEV_BYTE -> new AnnotationImpl.OfByteImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_CHAR -> new AnnotationImpl.OfCharImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_DOUBLE -> new AnnotationImpl.OfDoubleImpl(classReader.readEntry(p, DoubleEntry.class)); - case AEV_FLOAT -> new AnnotationImpl.OfFloatImpl(classReader.readEntry(p, FloatEntry.class)); - case AEV_INT -> new AnnotationImpl.OfIntImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class)); - case AEV_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_STRING -> new AnnotationImpl.OfStringImpl(classReader.readEntry(p, Utf8Entry.class)); - case AEV_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readEntry(p, Utf8Entry.class), + case TAG_BYTE -> new AnnotationImpl.OfByteImpl(classReader.readEntry(p, IntegerEntry.class)); + case TAG_CHAR -> new AnnotationImpl.OfCharImpl(classReader.readEntry(p, IntegerEntry.class)); + case TAG_DOUBLE -> new AnnotationImpl.OfDoubleImpl(classReader.readEntry(p, DoubleEntry.class)); + case TAG_FLOAT -> new AnnotationImpl.OfFloatImpl(classReader.readEntry(p, FloatEntry.class)); + case TAG_INT -> new AnnotationImpl.OfIntImpl(classReader.readEntry(p, IntegerEntry.class)); + case TAG_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class)); + case TAG_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class)); + case TAG_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class)); + case TAG_STRING -> new AnnotationImpl.OfStringImpl(classReader.readEntry(p, Utf8Entry.class)); + case TAG_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readEntry(p, Utf8Entry.class), classReader.readEntry(p + 2, Utf8Entry.class)); - case AEV_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readEntry(p, Utf8Entry.class)); - case AEV_ANNOTATION -> new AnnotationImpl.OfAnnotationImpl(readAnnotation(classReader, p)); - case AEV_ARRAY -> { + case TAG_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readEntry(p, Utf8Entry.class)); + case TAG_ANNOTATION -> new AnnotationImpl.OfAnnotationImpl(readAnnotation(classReader, p)); + case TAG_ARRAY -> { int numValues = classReader.readU2(p); p += 2; var values = new Object[numValues]; @@ -179,49 +180,49 @@ private static Label getLabel(LabelContext lc, int bciOffset, int targetType, in private static TypeAnnotation readTypeAnnotation(ClassReader classReader, int p, LabelContext lc) { int targetType = classReader.readU1(p++); var targetInfo = switch (targetType) { - case TAT_CLASS_TYPE_PARAMETER -> + case TARGET_CLASS_TYPE_PARAMETER -> ofClassTypeParameter(classReader.readU1(p)); - case TAT_METHOD_TYPE_PARAMETER -> + case TARGET_METHOD_TYPE_PARAMETER -> ofMethodTypeParameter(classReader.readU1(p)); - case TAT_CLASS_EXTENDS -> + case TARGET_CLASS_EXTENDS -> ofClassExtends(classReader.readU2(p)); - case TAT_CLASS_TYPE_PARAMETER_BOUND -> + case TARGET_CLASS_TYPE_PARAMETER_BOUND -> ofClassTypeParameterBound(classReader.readU1(p), classReader.readU1(p + 1)); - case TAT_METHOD_TYPE_PARAMETER_BOUND -> + case TARGET_METHOD_TYPE_PARAMETER_BOUND -> ofMethodTypeParameterBound(classReader.readU1(p), classReader.readU1(p + 1)); - case TAT_FIELD -> + case TARGET_FIELD -> ofField(); - case TAT_METHOD_RETURN -> + case TARGET_METHOD_RETURN -> ofMethodReturn(); - case TAT_METHOD_RECEIVER -> + case TARGET_METHOD_RECEIVER -> ofMethodReceiver(); - case TAT_METHOD_FORMAL_PARAMETER -> + case TARGET_METHOD_FORMAL_PARAMETER -> ofMethodFormalParameter(classReader.readU1(p)); - case TAT_THROWS -> + case TARGET_THROWS -> ofThrows(classReader.readU2(p)); - case TAT_LOCAL_VARIABLE -> + case TARGET_LOCAL_VARIABLE -> ofLocalVariable(readLocalVarEntries(classReader, p, lc, targetType)); - case TAT_RESOURCE_VARIABLE -> + case TARGET_RESOURCE_VARIABLE -> ofResourceVariable(readLocalVarEntries(classReader, p, lc, targetType)); - case TAT_EXCEPTION_PARAMETER -> + case TARGET_EXCEPTION_PARAMETER -> ofExceptionParameter(classReader.readU2(p)); - case TAT_INSTANCEOF -> + case TARGET_INSTANCEOF -> ofInstanceofExpr(getLabel(lc, classReader.readU2(p), targetType, p)); - case TAT_NEW -> + case TARGET_NEW -> ofNewExpr(getLabel(lc, classReader.readU2(p), targetType, p)); - case TAT_CONSTRUCTOR_REFERENCE -> + case TARGET_CONSTRUCTOR_REFERENCE -> ofConstructorReference(getLabel(lc, classReader.readU2(p), targetType, p)); - case TAT_METHOD_REFERENCE -> + case TARGET_METHOD_REFERENCE -> ofMethodReference(getLabel(lc, classReader.readU2(p), targetType, p)); - case TAT_CAST -> + case TARGET_CAST -> ofCastExpr(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); - case TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -> + case TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -> ofConstructorInvocationTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); - case TAT_METHOD_INVOCATION_TYPE_ARGUMENT -> + case TARGET_METHOD_INVOCATION_TYPE_ARGUMENT -> ofMethodInvocationTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); - case TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -> + case TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -> ofConstructorReferenceTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); - case TAT_METHOD_REFERENCE_TYPE_ARGUMENT -> + case TARGET_METHOD_REFERENCE_TYPE_ARGUMENT -> ofMethodReferenceTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); default -> throw new IllegalArgumentException("Unexpected targetType '%d' in TypeAnnotation, pos = %d".formatted(targetType, p - 1)); @@ -362,16 +363,16 @@ public static void writeAnnotationValue(BufWriterImpl buf, AnnotationValue value var tag = value.tag(); buf.writeU1(tag); switch (value.tag()) { - case AEV_BOOLEAN, AEV_BYTE, AEV_CHAR, AEV_DOUBLE, AEV_FLOAT, AEV_INT, AEV_LONG, AEV_SHORT, AEV_STRING -> + case TAG_BOOLEAN, TAG_BYTE, TAG_CHAR, TAG_DOUBLE, TAG_FLOAT, TAG_INT, TAG_LONG, TAG_SHORT, TAG_STRING -> buf.writeIndex(((AnnotationValue.OfConstant) value).constant()); - case AEV_CLASS -> buf.writeIndex(((AnnotationValue.OfClass) value).className()); - case AEV_ENUM -> { + case TAG_CLASS -> buf.writeIndex(((AnnotationValue.OfClass) value).className()); + case TAG_ENUM -> { var enumValue = (AnnotationValue.OfEnum) value; buf.writeIndex(enumValue.className()); buf.writeIndex(enumValue.constantName()); } - case AEV_ANNOTATION -> writeAnnotation(buf, ((AnnotationValue.OfAnnotation) value).annotation()); - case AEV_ARRAY -> { + case TAG_ANNOTATION -> writeAnnotation(buf, ((AnnotationValue.OfAnnotation) value).annotation()); + case TAG_ARRAY -> { var array = ((AnnotationValue.OfArray) value).values(); buf.writeU2(array.size()); for (var e : array) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index 75991531c319f..a5b4b55b05b27 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -46,7 +46,7 @@ import java.lang.classfile.constantpool.MethodHandleEntry; import java.lang.classfile.constantpool.NameAndTypeEntry; -import static java.lang.classfile.ClassFile.*; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; /** * Note: This class switches on opcode.bytecode for code size diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java index 6765bdee3bdac..34e6f5f7c1aa7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java @@ -40,6 +40,7 @@ import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.constantpool.PoolEntry.*; import static java.util.Objects.requireNonNull; import static jdk.internal.constant.ConstantUtils.referenceClassDesc; @@ -174,10 +175,10 @@ public ClassHierarchyResolver.ClassHierarchyInfo getClassInfo(ClassDesc classDes switch (tag = in.readUnsignedByte()) { case TAG_UTF8 -> cpStrings[i] = in.readUTF(); case TAG_CLASS -> cpClasses[i] = in.readUnsignedShort(); - case TAG_STRING, TAG_METHODTYPE, TAG_MODULE, TAG_PACKAGE -> in.skipBytes(2); - case TAG_METHODHANDLE -> in.skipBytes(3); - case TAG_INTEGER, TAG_FLOAT, TAG_FIELDREF, TAG_METHODREF, TAG_INTERFACEMETHODREF, - TAG_NAMEANDTYPE, TAG_CONSTANTDYNAMIC, TAG_INVOKEDYNAMIC -> in.skipBytes(4); + case TAG_STRING, TAG_METHOD_TYPE, TAG_MODULE, TAG_PACKAGE -> in.skipBytes(2); + case TAG_METHOD_HANDLE -> in.skipBytes(3); + case TAG_INTEGER, TAG_FLOAT, TAG_FIELDREF, TAG_METHODREF, TAG_INTERFACE_METHODREF, + TAG_NAME_AND_TYPE, TAG_DYNAMIC, TAG_INVOKE_DYNAMIC -> in.skipBytes(4); case TAG_LONG, TAG_DOUBLE -> { in.skipBytes(8); i++; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java index 837cf3366be83..02026b1acf33d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java @@ -58,9 +58,9 @@ import java.lang.classfile.constantpool.*; import java.lang.classfile.instruction.*; -import static java.lang.classfile.ClassFile.*; import java.lang.classfile.CompoundElement; import java.lang.classfile.FieldModel; +import static java.lang.classfile.constantpool.PoolEntry.*; import static jdk.internal.classfile.impl.ClassPrinterImpl.Style.*; public final class ClassPrinterImpl { @@ -536,21 +536,21 @@ private static Stream convertVTIs(CodeAttribute lr, List { switch (s) { - case ITEM_DOUBLE -> { + case DOUBLE -> { ret.accept("double"); ret.accept("double2"); } - case ITEM_FLOAT -> + case FLOAT -> ret.accept("float"); - case ITEM_INTEGER -> + case INTEGER -> ret.accept("int"); - case ITEM_LONG -> { + case LONG -> { ret.accept("long"); ret.accept("long2"); } - case ITEM_NULL -> ret.accept("null"); - case ITEM_TOP -> ret.accept("?"); - case ITEM_UNINITIALIZED_THIS -> ret.accept("THIS"); + case NULL -> ret.accept("null"); + case TOP -> ret.accept("?"); + case UNINITIALIZED_THIS -> ret.accept("THIS"); } } case ObjectVerificationTypeInfo o -> @@ -603,12 +603,12 @@ private static Node[] constantPoolToTree(ConstantPool cp, Verbosity verbosity) { case TAG_STRING -> "String"; case TAG_FIELDREF -> "Fieldref"; case TAG_METHODREF -> "Methodref"; - case TAG_INTERFACEMETHODREF -> "InterfaceMethodref"; - case TAG_NAMEANDTYPE -> "NameAndType"; - case TAG_METHODHANDLE -> "MethodHandle"; - case TAG_METHODTYPE -> "MethodType"; - case TAG_CONSTANTDYNAMIC -> "Dynamic"; - case TAG_INVOKEDYNAMIC -> "InvokeDynamic"; + case TAG_INTERFACE_METHODREF -> "InterfaceMethodref"; + case TAG_NAME_AND_TYPE -> "NameAndType"; + case TAG_METHOD_HANDLE -> "MethodHandle"; + case TAG_METHOD_TYPE -> "MethodType"; + case TAG_DYNAMIC -> "Dynamic"; + case TAG_INVOKE_DYNAMIC -> "InvokeDynamic"; case TAG_MODULE -> "Module"; case TAG_PACKAGE -> "Package"; default -> throw new AssertionError("Unknown CP tag: " + e.tag()); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java index 6a4b0cd486f07..2ef39504e9b74 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java @@ -36,23 +36,7 @@ import java.lang.classfile.attribute.BootstrapMethodsAttribute; import java.lang.classfile.constantpool.*; -import static java.lang.classfile.ClassFile.TAG_CLASS; -import static java.lang.classfile.ClassFile.TAG_CONSTANTDYNAMIC; -import static java.lang.classfile.ClassFile.TAG_DOUBLE; -import static java.lang.classfile.ClassFile.TAG_FIELDREF; -import static java.lang.classfile.ClassFile.TAG_FLOAT; -import static java.lang.classfile.ClassFile.TAG_INTEGER; -import static java.lang.classfile.ClassFile.TAG_INTERFACEMETHODREF; -import static java.lang.classfile.ClassFile.TAG_INVOKEDYNAMIC; -import static java.lang.classfile.ClassFile.TAG_LONG; -import static java.lang.classfile.ClassFile.TAG_METHODHANDLE; -import static java.lang.classfile.ClassFile.TAG_METHODREF; -import static java.lang.classfile.ClassFile.TAG_METHODTYPE; -import static java.lang.classfile.ClassFile.TAG_MODULE; -import static java.lang.classfile.ClassFile.TAG_NAMEANDTYPE; -import static java.lang.classfile.ClassFile.TAG_PACKAGE; -import static java.lang.classfile.ClassFile.TAG_STRING; -import static java.lang.classfile.ClassFile.TAG_UTF8; +import static java.lang.classfile.constantpool.PoolEntry.*; public final class ClassReaderImpl implements ClassReader { @@ -98,15 +82,15 @@ public final class ClassReaderImpl ++p; switch (tag) { // 2 - case TAG_CLASS, TAG_METHODTYPE, TAG_MODULE, TAG_STRING, TAG_PACKAGE -> p += 2; + case TAG_CLASS, TAG_METHOD_TYPE, TAG_MODULE, TAG_STRING, TAG_PACKAGE -> p += 2; // 3 - case TAG_METHODHANDLE -> p += 3; + case TAG_METHOD_HANDLE -> p += 3; // 4 - case TAG_CONSTANTDYNAMIC, TAG_FIELDREF, TAG_FLOAT, TAG_INTEGER, - TAG_INTERFACEMETHODREF, TAG_INVOKEDYNAMIC, TAG_METHODREF, - TAG_NAMEANDTYPE -> p += 4; + case TAG_DYNAMIC, TAG_FIELDREF, TAG_FLOAT, TAG_INTEGER, + TAG_INTERFACE_METHODREF, TAG_INVOKE_DYNAMIC, TAG_METHODREF, + TAG_NAME_AND_TYPE -> p += 4; // 8 case TAG_DOUBLE, TAG_LONG -> { @@ -354,12 +338,12 @@ private static boolean checkTag(int tag, Class cls) { case TAG_STRING -> AbstractPoolEntry.StringEntryImpl.class; case TAG_FIELDREF -> AbstractPoolEntry.FieldRefEntryImpl.class; case TAG_METHODREF -> AbstractPoolEntry.MethodRefEntryImpl.class; - case TAG_INTERFACEMETHODREF -> AbstractPoolEntry.InterfaceMethodRefEntryImpl.class; - case TAG_NAMEANDTYPE -> AbstractPoolEntry.NameAndTypeEntryImpl.class; - case TAG_METHODHANDLE -> AbstractPoolEntry.MethodHandleEntryImpl.class; - case TAG_METHODTYPE -> AbstractPoolEntry.MethodTypeEntryImpl.class; - case TAG_CONSTANTDYNAMIC -> AbstractPoolEntry.ConstantDynamicEntryImpl.class; - case TAG_INVOKEDYNAMIC -> AbstractPoolEntry.InvokeDynamicEntryImpl.class; + case TAG_INTERFACE_METHODREF -> AbstractPoolEntry.InterfaceMethodRefEntryImpl.class; + case TAG_NAME_AND_TYPE -> AbstractPoolEntry.NameAndTypeEntryImpl.class; + case TAG_METHOD_HANDLE -> AbstractPoolEntry.MethodHandleEntryImpl.class; + case TAG_METHOD_TYPE -> AbstractPoolEntry.MethodTypeEntryImpl.class; + case TAG_DYNAMIC -> AbstractPoolEntry.ConstantDynamicEntryImpl.class; + case TAG_INVOKE_DYNAMIC -> AbstractPoolEntry.InvokeDynamicEntryImpl.class; case TAG_MODULE -> AbstractPoolEntry.ModuleEntryImpl.class; case TAG_PACKAGE -> AbstractPoolEntry.PackageEntryImpl.class; default -> null; @@ -402,15 +386,15 @@ public T entryByIndex(int index, Class cls) { readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); case TAG_METHODREF -> new AbstractPoolEntry.MethodRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); - case TAG_INTERFACEMETHODREF -> new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), + case TAG_INTERFACE_METHODREF -> new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); - case TAG_NAMEANDTYPE -> new AbstractPoolEntry.NameAndTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class), + case TAG_NAME_AND_TYPE -> new AbstractPoolEntry.NameAndTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class), readEntry(q + 2, AbstractPoolEntry.Utf8EntryImpl.class)); - case TAG_METHODHANDLE -> new AbstractPoolEntry.MethodHandleEntryImpl(this, index, readU1(q), + case TAG_METHOD_HANDLE -> new AbstractPoolEntry.MethodHandleEntryImpl(this, index, readU1(q), readEntry(q + 1, AbstractPoolEntry.AbstractMemberRefEntry.class)); - case TAG_METHODTYPE -> new AbstractPoolEntry.MethodTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); - case TAG_CONSTANTDYNAMIC -> new AbstractPoolEntry.ConstantDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); - case TAG_INVOKEDYNAMIC -> new AbstractPoolEntry.InvokeDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_METHOD_TYPE -> new AbstractPoolEntry.MethodTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); + case TAG_DYNAMIC -> new AbstractPoolEntry.ConstantDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_INVOKE_DYNAMIC -> new AbstractPoolEntry.InvokeDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); case TAG_MODULE -> new AbstractPoolEntry.ModuleEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); case TAG_PACKAGE -> new AbstractPoolEntry.PackageEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); default -> throw new ConstantPoolException( diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index e08d2b76479be..48394d3da96c3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -39,7 +39,7 @@ import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.instruction.*; -import static java.lang.classfile.ClassFile.*; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; public final class CodeImpl extends BoundAttribute.BoundCodeAttribute diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index e92494e699258..5f02ae708ea7b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -52,6 +52,8 @@ public final class DirectClassBuilder extends AbstractDirectBuilder implements ClassBuilder { + /** The value of default class access flags */ + static final int DEFAULT_CLASS_FLAGS = ClassFile.ACC_PUBLIC; final ClassEntry thisClassEntry; private final List fields = new ArrayList<>(); private final List methods = new ArrayList<>(); @@ -67,7 +69,7 @@ public DirectClassBuilder(SplitConstantPool constantPool, ClassEntry thisClass) { super(constantPool, context); this.thisClassEntry = AbstractPoolEntry.maybeClone(constantPool, thisClass); - this.flags = ClassFile.DEFAULT_CLASS_FLAGS; + this.flags = DEFAULT_CLASS_FLAGS; this.superclassEntry = null; this.interfaceEntries = Collections.emptyList(); this.majorVersion = ClassFile.latestMajorVersion(); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index fd7a8e55bf840..301b61241f71e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -489,9 +489,11 @@ private void processDeferredLabels() { // Instruction writing public void writeBytecode(Opcode opcode) { - if (opcode.isWide()) - bytecodesBufWriter.writeU1(ClassFile.WIDE); - bytecodesBufWriter.writeU1(opcode.bytecode() & 0xFF); + if (opcode.isWide()) { + bytecodesBufWriter.writeU2(opcode.bytecode()); + } else { + bytecodesBufWriter.writeU1(opcode.bytecode()); + } } public void writeLocalVar(Opcode opcode, int localVar) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java index 860b7e74b4dde..2403ae150e9dd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java @@ -32,8 +32,6 @@ import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.Stable; -import static java.lang.classfile.ClassFile.*; - public final class RawBytecodeHelper { public static final BiFunction, IllegalArgumentException> @@ -43,6 +41,210 @@ public IllegalArgumentException apply(String s) { return new IllegalArgumentException(s); } }); + public static final int + ILLEGAL = -1, + NOP = 0, + ACONST_NULL = 1, + ICONST_M1 = 2, + ICONST_0 = 3, + ICONST_1 = 4, + ICONST_2 = 5, + ICONST_3 = 6, + ICONST_4 = 7, + ICONST_5 = 8, + LCONST_0 = 9, + LCONST_1 = 10, + FCONST_0 = 11, + FCONST_1 = 12, + FCONST_2 = 13, + DCONST_0 = 14, + DCONST_1 = 15, + BIPUSH = 16, + SIPUSH = 17, + LDC = 18, + LDC_W = 19, + LDC2_W = 20, + ILOAD = 21, + LLOAD = 22, + FLOAD = 23, + DLOAD = 24, + ALOAD = 25, + ILOAD_0 = 26, + ILOAD_1 = 27, + ILOAD_2 = 28, + ILOAD_3 = 29, + LLOAD_0 = 30, + LLOAD_1 = 31, + LLOAD_2 = 32, + LLOAD_3 = 33, + FLOAD_0 = 34, + FLOAD_1 = 35, + FLOAD_2 = 36, + FLOAD_3 = 37, + DLOAD_0 = 38, + DLOAD_1 = 39, + DLOAD_2 = 40, + DLOAD_3 = 41, + ALOAD_0 = 42, + ALOAD_1 = 43, + ALOAD_2 = 44, + ALOAD_3 = 45, + IALOAD = 46, + LALOAD = 47, + FALOAD = 48, + DALOAD = 49, + AALOAD = 50, + BALOAD = 51, + CALOAD = 52, + SALOAD = 53, + ISTORE = 54, + LSTORE = 55, + FSTORE = 56, + DSTORE = 57, + ASTORE = 58, + ISTORE_0 = 59, + ISTORE_1 = 60, + ISTORE_2 = 61, + ISTORE_3 = 62, + LSTORE_0 = 63, + LSTORE_1 = 64, + LSTORE_2 = 65, + LSTORE_3 = 66, + FSTORE_0 = 67, + FSTORE_1 = 68, + FSTORE_2 = 69, + FSTORE_3 = 70, + DSTORE_0 = 71, + DSTORE_1 = 72, + DSTORE_2 = 73, + DSTORE_3 = 74, + ASTORE_0 = 75, + ASTORE_1 = 76, + ASTORE_2 = 77, + ASTORE_3 = 78, + IASTORE = 79, + LASTORE = 80, + FASTORE = 81, + DASTORE = 82, + AASTORE = 83, + BASTORE = 84, + CASTORE = 85, + SASTORE = 86, + POP = 87, + POP2 = 88, + DUP = 89, + DUP_X1 = 90, + DUP_X2 = 91, + DUP2 = 92, + DUP2_X1 = 93, + DUP2_X2 = 94, + SWAP = 95, + IADD = 96, + LADD = 97, + FADD = 98, + DADD = 99, + ISUB = 100, + LSUB = 101, + FSUB = 102, + DSUB = 103, + IMUL = 104, + LMUL = 105, + FMUL = 106, + DMUL = 107, + IDIV = 108, + LDIV = 109, + FDIV = 110, + DDIV = 111, + IREM = 112, + LREM = 113, + FREM = 114, + DREM = 115, + INEG = 116, + LNEG = 117, + FNEG = 118, + DNEG = 119, + ISHL = 120, + LSHL = 121, + ISHR = 122, + LSHR = 123, + IUSHR = 124, + LUSHR = 125, + IAND = 126, + LAND = 127, + IOR = 128, + LOR = 129, + IXOR = 130, + LXOR = 131, + IINC = 132, + I2L = 133, + I2F = 134, + I2D = 135, + L2I = 136, + L2F = 137, + L2D = 138, + F2I = 139, + F2L = 140, + F2D = 141, + D2I = 142, + D2L = 143, + D2F = 144, + I2B = 145, + I2C = 146, + I2S = 147, + LCMP = 148, + FCMPL = 149, + FCMPG = 150, + DCMPL = 151, + DCMPG = 152, + IFEQ = 153, + IFNE = 154, + IFLT = 155, + IFGE = 156, + IFGT = 157, + IFLE = 158, + IF_ICMPEQ = 159, + IF_ICMPNE = 160, + IF_ICMPLT = 161, + IF_ICMPGE = 162, + IF_ICMPGT = 163, + IF_ICMPLE = 164, + IF_ACMPEQ = 165, + IF_ACMPNE = 166, + GOTO = 167, + JSR = 168, + RET = 169, + TABLESWITCH = 170, + LOOKUPSWITCH = 171, + IRETURN = 172, + LRETURN = 173, + FRETURN = 174, + DRETURN = 175, + ARETURN = 176, + RETURN = 177, + GETSTATIC = 178, + PUTSTATIC = 179, + GETFIELD = 180, + PUTFIELD = 181, + INVOKEVIRTUAL = 182, + INVOKESPECIAL = 183, + INVOKESTATIC = 184, + INVOKEINTERFACE = 185, + INVOKEDYNAMIC = 186, + NEW = 187, + NEWARRAY = 188, + ANEWARRAY = 189, + ARRAYLENGTH = 190, + ATHROW = 191, + CHECKCAST = 192, + INSTANCEOF = 193, + MONITORENTER = 194, + MONITOREXIT = 195, + WIDE = 196, + MULTIANEWARRAY = 197, + IFNULL = 198, + IFNONNULL = 199, + GOTO_W = 200, + JSR_W = 201; public record CodeRange(byte[] array, int length) { public RawBytecodeHelper start() { @@ -50,8 +252,6 @@ public RawBytecodeHelper start() { } } - public static final int ILLEGAL = -1; - /** * The length of opcodes, or -1 for no fixed length. * This is generated as if: diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index 0541e92e5c319..2193eb761081d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -31,7 +31,6 @@ import java.lang.classfile.Attributes; import java.lang.classfile.ClassReader; -import java.lang.classfile.ClassFile; import java.lang.classfile.BootstrapMethodEntry; import java.lang.classfile.attribute.BootstrapMethodsAttribute; import java.lang.classfile.constantpool.*; @@ -39,22 +38,7 @@ import jdk.internal.constant.ConstantUtils; -import static java.lang.classfile.ClassFile.TAG_CLASS; -import static java.lang.classfile.ClassFile.TAG_CONSTANTDYNAMIC; -import static java.lang.classfile.ClassFile.TAG_DOUBLE; -import static java.lang.classfile.ClassFile.TAG_FIELDREF; -import static java.lang.classfile.ClassFile.TAG_FLOAT; -import static java.lang.classfile.ClassFile.TAG_INTEGER; -import static java.lang.classfile.ClassFile.TAG_INTERFACEMETHODREF; -import static java.lang.classfile.ClassFile.TAG_INVOKEDYNAMIC; -import static java.lang.classfile.ClassFile.TAG_LONG; -import static java.lang.classfile.ClassFile.TAG_METHODHANDLE; -import static java.lang.classfile.ClassFile.TAG_METHODREF; -import static java.lang.classfile.ClassFile.TAG_METHODTYPE; -import static java.lang.classfile.ClassFile.TAG_MODULE; -import static java.lang.classfile.ClassFile.TAG_NAMEANDTYPE; -import static java.lang.classfile.ClassFile.TAG_PACKAGE; -import static java.lang.classfile.ClassFile.TAG_STRING; +import static java.lang.classfile.constantpool.PoolEntry.*; public final class SplitConstantPool implements ConstantPoolBuilder { @@ -371,7 +355,7 @@ private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8(int hash, String target) { for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { PoolEntry e = entryByIndex(map.getIndexByToken(token)); - if (e.tag() == ClassFile.TAG_UTF8 + if (e.tag() == TAG_UTF8 && e instanceof AbstractPoolEntry.Utf8EntryImpl ce && target.equals(ce.stringValue())) return ce; @@ -387,7 +371,7 @@ private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8(int hash, AbstractPoolEntry. EntryMap map = map(); for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { PoolEntry e = entryByIndex(map.getIndexByToken(token)); - if (e.tag() == ClassFile.TAG_UTF8 + if (e.tag() == TAG_UTF8 && e instanceof AbstractPoolEntry.Utf8EntryImpl ce && target.equalsUtf8(ce)) return ce; @@ -404,7 +388,7 @@ private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8OfRegion(int hash, String tar while (true) { for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { PoolEntry e = entryByIndex(map.getIndexByToken(token)); - if (e.tag() == ClassFile.TAG_UTF8 + if (e.tag() == TAG_UTF8 && e instanceof AbstractPoolEntry.Utf8EntryImpl ce && ce.equalsRegion(target, start, end)) return ce; @@ -471,7 +455,7 @@ private AbstractPoolEntry.ClassEntryImpl tryFindClassEntry(int hash, AbstractPoo EntryMap map = map(); for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { PoolEntry e = entryByIndex(map.getIndexByToken(token)); - if (e.tag() == ClassFile.TAG_CLASS + if (e.tag() == TAG_CLASS && e instanceof AbstractPoolEntry.ClassEntryImpl ce && ce.ref1.equalsUtf8(utf8)) return ce; @@ -567,7 +551,7 @@ public ModuleEntry moduleEntry(Utf8Entry nameEntry) { public AbstractPoolEntry.NameAndTypeEntryImpl nameAndTypeEntry(Utf8Entry nameEntry, Utf8Entry typeEntry) { AbstractPoolEntry.Utf8EntryImpl ne = maybeCloneUtf8Entry(nameEntry); AbstractPoolEntry.Utf8EntryImpl te = maybeCloneUtf8Entry(typeEntry); - var e = (AbstractPoolEntry.NameAndTypeEntryImpl) findEntry(TAG_NAMEANDTYPE, ne, te); + var e = (AbstractPoolEntry.NameAndTypeEntryImpl) findEntry(TAG_NAME_AND_TYPE, ne, te); return e == null ? internalAdd(new AbstractPoolEntry.NameAndTypeEntryImpl(this, size, ne, te)) : e; } @@ -591,7 +575,7 @@ public MethodRefEntry methodRefEntry(ClassEntry owner, NameAndTypeEntry nameAndT public InterfaceMethodRefEntry interfaceMethodRefEntry(ClassEntry owner, NameAndTypeEntry nameAndType) { var oe = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.ClassEntryImpl) owner); var ne = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType); - var e = (AbstractPoolEntry.InterfaceMethodRefEntryImpl) findEntry(TAG_INTERFACEMETHODREF, oe, ne); + var e = (AbstractPoolEntry.InterfaceMethodRefEntryImpl) findEntry(TAG_INTERFACE_METHODREF, oe, ne); return e == null ? internalAdd(new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, size, oe, ne)) : e; } @@ -603,18 +587,18 @@ public MethodTypeEntry methodTypeEntry(MethodTypeDesc descriptor) { @Override public MethodTypeEntry methodTypeEntry(Utf8Entry descriptor) { AbstractPoolEntry.Utf8EntryImpl de = maybeCloneUtf8Entry(descriptor); - var e = (AbstractPoolEntry.MethodTypeEntryImpl) findEntry(TAG_METHODTYPE, de); + var e = (AbstractPoolEntry.MethodTypeEntryImpl) findEntry(TAG_METHOD_TYPE, de); return e == null ? internalAdd(new AbstractPoolEntry.MethodTypeEntryImpl(this, size, de)) : e; } @Override public MethodHandleEntry methodHandleEntry(int refKind, MemberRefEntry reference) { reference = AbstractPoolEntry.maybeClone(this, reference); - int hash = AbstractPoolEntry.hash2(TAG_METHODHANDLE, refKind, reference.index()); + int hash = AbstractPoolEntry.hash2(TAG_METHOD_HANDLE, refKind, reference.index()); EntryMap map1 = map(); for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) { PoolEntry e = entryByIndex(map1.getIndexByToken(token)); - if (e.tag() == TAG_METHODHANDLE + if (e.tag() == TAG_METHOD_HANDLE && e instanceof AbstractPoolEntry.MethodHandleEntryImpl ce && ce.kind() == refKind && ce.reference() == reference) return ce; @@ -634,12 +618,12 @@ public InvokeDynamicEntry invokeDynamicEntry(BootstrapMethodEntry bootstrapMetho bootstrapMethodEntry = bsmEntry(bootstrapMethodEntry.bootstrapMethod(), bootstrapMethodEntry.arguments()); nameAndType = AbstractPoolEntry.maybeClone(this, nameAndType); - int hash = AbstractPoolEntry.hash2(TAG_INVOKEDYNAMIC, + int hash = AbstractPoolEntry.hash2(TAG_INVOKE_DYNAMIC, bootstrapMethodEntry.bsmIndex(), nameAndType.index()); EntryMap map1 = map(); for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) { PoolEntry e = entryByIndex(map1.getIndexByToken(token)); - if (e.tag() == TAG_INVOKEDYNAMIC + if (e.tag() == TAG_INVOKE_DYNAMIC && e instanceof AbstractPoolEntry.InvokeDynamicEntryImpl ce && ce.bootstrap() == bootstrapMethodEntry && ce.nameAndType() == nameAndType) return ce; @@ -664,12 +648,12 @@ public ConstantDynamicEntry constantDynamicEntry(BootstrapMethodEntry bootstrapM bootstrapMethodEntry = bsmEntry(bootstrapMethodEntry.bootstrapMethod(), bootstrapMethodEntry.arguments()); nameAndType = AbstractPoolEntry.maybeClone(this, nameAndType); - int hash = AbstractPoolEntry.hash2(TAG_CONSTANTDYNAMIC, + int hash = AbstractPoolEntry.hash2(TAG_DYNAMIC, bootstrapMethodEntry.bsmIndex(), nameAndType.index()); EntryMap map1 = map(); for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) { PoolEntry e = entryByIndex(map1.getIndexByToken(token)); - if (e.tag() == TAG_CONSTANTDYNAMIC + if (e.tag() == TAG_DYNAMIC && e instanceof AbstractPoolEntry.ConstantDynamicEntryImpl ce && ce.bootstrap() == bootstrapMethodEntry && ce.nameAndType() == nameAndType) return ce; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java index 783ff4bf106c2..49a06b3acc6e7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java @@ -41,6 +41,8 @@ import java.util.stream.Collectors; import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.constantpool.PoolEntry.*; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; public final class StackCounter { @@ -120,8 +122,8 @@ public StackCounter(LabelContext labelContext, for (var smfi : smta.entries()) { int frameStack = smfi.stack().size(); for (var vti : smfi.stack()) { - if (vti == StackMapFrameInfo.SimpleVerificationTypeInfo.ITEM_LONG - || vti == StackMapFrameInfo.SimpleVerificationTypeInfo.ITEM_DOUBLE) frameStack++; + if (vti == StackMapFrameInfo.SimpleVerificationTypeInfo.LONG + || vti == StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE) frameStack++; } if (maxStack < frameStack) maxStack = frameStack; targets.add(new Target(labelContext.labelToBci(smfi.target()), frameStack)); @@ -376,11 +378,11 @@ public int maxStack() { private void processLdc(int index) { switch (cp.entryByIndex(index).tag()) { - case TAG_UTF8, TAG_STRING, TAG_CLASS, TAG_INTEGER, TAG_FLOAT, TAG_METHODHANDLE, TAG_METHODTYPE -> + case TAG_UTF8, TAG_STRING, TAG_CLASS, TAG_INTEGER, TAG_FLOAT, TAG_METHOD_HANDLE, TAG_METHOD_TYPE -> addStackSlot(+1); case TAG_DOUBLE, TAG_LONG -> addStackSlot(+2); - case TAG_CONSTANTDYNAMIC -> + case TAG_DYNAMIC -> addStackSlot(cp.entryByIndex(index, ConstantDynamicEntry.class).typeKind().slotSize()); default -> throw error("CP entry #%d %s is not loadable constant".formatted(index, cp.entryByIndex(index).tag())); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index bdee788c9da77..884f7b8bbc8fa 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -41,6 +41,7 @@ import java.util.Objects; import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*; public class StackMapDecoder { @@ -75,7 +76,7 @@ public static List initFrameLocals(ClassEntry thisClass, S if (!isStatic) { vtis = new VerificationTypeInfo[methodType.parameterCount() + 1]; if ("".equals(methodName) && !ConstantDescs.CD_Object.equals(thisClass.asSymbol())) { - vtis[i++] = SimpleVerificationTypeInfo.ITEM_UNINITIALIZED_THIS; + vtis[i++] = SimpleVerificationTypeInfo.UNINITIALIZED_THIS; } else { vtis[i++] = new StackMapDecoder.ObjectVerificationTypeInfoImpl(thisClass); } @@ -85,10 +86,10 @@ public static List initFrameLocals(ClassEntry thisClass, S for (int pi = 0; pi < methodType.parameterCount(); pi++) { var arg = methodType.parameterType(pi); vtis[i++] = switch (arg.descriptorString().charAt(0)) { - case 'I', 'S', 'C' ,'B', 'Z' -> SimpleVerificationTypeInfo.ITEM_INTEGER; - case 'J' -> SimpleVerificationTypeInfo.ITEM_LONG; - case 'F' -> SimpleVerificationTypeInfo.ITEM_FLOAT; - case 'D' -> SimpleVerificationTypeInfo.ITEM_DOUBLE; + case 'I', 'S', 'C' ,'B', 'Z' -> SimpleVerificationTypeInfo.INTEGER; + case 'J' -> SimpleVerificationTypeInfo.LONG; + case 'F' -> SimpleVerificationTypeInfo.FLOAT; + case 'D' -> SimpleVerificationTypeInfo.DOUBLE; case 'V' -> throw new IllegalArgumentException("Illegal method argument type: " + arg); default -> new StackMapDecoder.ObjectVerificationTypeInfoImpl(TemporaryConstantPool.INSTANCE.classEntry(arg)); }; @@ -169,11 +170,12 @@ private static boolean equals(List l1, List + case ITEM_TOP, ITEM_INTEGER, ITEM_FLOAT, ITEM_DOUBLE, ITEM_LONG, ITEM_NULL, + ITEM_UNINITIALIZED_THIS -> {} - case VT_OBJECT -> + case ITEM_OBJECT -> bw.writeIndex(((ObjectVerificationTypeInfo)vti).className()); - case VT_UNINITIALIZED -> + case ITEM_UNINITIALIZED -> bw.writeU2(bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget())); default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag()); } @@ -232,15 +234,15 @@ List entries() { private VerificationTypeInfo readVerificationTypeInfo() { int tag = classReader.readU1(p++); return switch (tag) { - case VT_TOP -> SimpleVerificationTypeInfo.ITEM_TOP; - case VT_INTEGER -> SimpleVerificationTypeInfo.ITEM_INTEGER; - case VT_FLOAT -> SimpleVerificationTypeInfo.ITEM_FLOAT; - case VT_DOUBLE -> SimpleVerificationTypeInfo.ITEM_DOUBLE; - case VT_LONG -> SimpleVerificationTypeInfo.ITEM_LONG; - case VT_NULL -> SimpleVerificationTypeInfo.ITEM_NULL; - case VT_UNINITIALIZED_THIS -> SimpleVerificationTypeInfo.ITEM_UNINITIALIZED_THIS; - case VT_OBJECT -> new ObjectVerificationTypeInfoImpl(classReader.entryByIndex(u2(), ClassEntry.class)); - case VT_UNINITIALIZED -> new UninitializedVerificationTypeInfoImpl(ctx.getLabel(u2())); + case ITEM_TOP -> SimpleVerificationTypeInfo.TOP; + case ITEM_INTEGER -> SimpleVerificationTypeInfo.INTEGER; + case ITEM_FLOAT -> SimpleVerificationTypeInfo.FLOAT; + case ITEM_DOUBLE -> SimpleVerificationTypeInfo.DOUBLE; + case ITEM_LONG -> SimpleVerificationTypeInfo.LONG; + case ITEM_NULL -> SimpleVerificationTypeInfo.NULL; + case ITEM_UNINITIALIZED_THIS -> SimpleVerificationTypeInfo.UNINITIALIZED_THIS; + case ITEM_OBJECT -> new ObjectVerificationTypeInfoImpl(classReader.entryByIndex(u2(), ClassEntry.class)); + case ITEM_UNINITIALIZED -> new UninitializedVerificationTypeInfoImpl(ctx.getLabel(u2())); default -> throw new IllegalArgumentException("Invalid verification type tag: " + tag); }; } @@ -249,7 +251,7 @@ public static record ObjectVerificationTypeInfoImpl( ClassEntry className) implements ObjectVerificationTypeInfo { @Override - public int tag() { return VT_OBJECT; } + public int tag() { return ITEM_OBJECT; } @Override public boolean equals(Object o) { @@ -274,7 +276,7 @@ public String toString() { public static record UninitializedVerificationTypeInfoImpl(Label newTarget) implements UninitializedVerificationTypeInfo { @Override - public int tag() { return VT_UNINITIALIZED; } + public int tag() { return ITEM_UNINITIALIZED; } @Override public String toString() { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 964a0dc2b2727..ae9835206831e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -28,7 +28,6 @@ import java.lang.classfile.Attribute; import java.lang.classfile.Attributes; import java.lang.classfile.BufWriter; -import java.lang.classfile.ClassFile; import java.lang.classfile.Label; import java.lang.classfile.attribute.StackMapTableAttribute; import java.lang.classfile.constantpool.ClassEntry; @@ -48,7 +47,9 @@ import jdk.internal.util.Preconditions; import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.constantpool.PoolEntry.*; import static java.lang.constant.ConstantDescs.*; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; /** * StackMapGenerator is responsible for stack map frames generation. @@ -696,11 +697,11 @@ private void processLdc(int index) { currentFrame.pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case TAG_LONG -> currentFrame.pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); - case TAG_METHODHANDLE -> + case TAG_METHOD_HANDLE -> currentFrame.pushStack(Type.METHOD_HANDLE_TYPE); - case TAG_METHODTYPE -> + case TAG_METHOD_TYPE -> currentFrame.pushStack(Type.METHOD_TYPE); - case TAG_CONSTANTDYNAMIC -> + case TAG_DYNAMIC -> currentFrame.pushStack(cp.entryByIndex(index, ConstantDynamicEntry.class).asSymbol().constantType()); default -> throw generatorError("CP entry #%d %s is not loadable constant".formatted(index, cp.entryByIndex(index).tag())); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java index 3377e3ebd1305..b2d5cd9f62c84 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java @@ -28,7 +28,7 @@ import java.util.Objects; import java.lang.classfile.Label; import java.lang.classfile.TypeAnnotation.*; -import static java.lang.classfile.ClassFile.*; + import static java.util.Objects.requireNonNull; public final class TargetInfoImpl { @@ -47,7 +47,7 @@ public record TypeParameterTargetImpl(TargetType targetType, int typeParameterIn implements TypeParameterTarget { public TypeParameterTargetImpl(TargetType targetType, int typeParameterIndex) { - this.targetType = checkValid(targetType, TAT_CLASS_TYPE_PARAMETER, TAT_METHOD_TYPE_PARAMETER); + this.targetType = checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER, TARGET_METHOD_TYPE_PARAMETER); this.typeParameterIndex = typeParameterIndex; } } @@ -63,7 +63,7 @@ public record TypeParameterBoundTargetImpl(TargetType targetType, int typeParame implements TypeParameterBoundTarget { public TypeParameterBoundTargetImpl(TargetType targetType, int typeParameterIndex, int boundIndex) { - this.targetType = checkValid(targetType, TAT_CLASS_TYPE_PARAMETER_BOUND, TAT_METHOD_TYPE_PARAMETER_BOUND); + this.targetType = checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER_BOUND, TARGET_METHOD_TYPE_PARAMETER_BOUND); this.typeParameterIndex = typeParameterIndex; this.boundIndex = boundIndex; } @@ -72,7 +72,7 @@ public TypeParameterBoundTargetImpl(TargetType targetType, int typeParameterInde public record EmptyTargetImpl(TargetType targetType) implements EmptyTarget { public EmptyTargetImpl(TargetType targetType) { - this.targetType = checkValid(targetType, TAT_FIELD, TAT_METHOD_RECEIVER); + this.targetType = checkValid(targetType, TARGET_FIELD, TARGET_METHOD_RECEIVER); } } @@ -94,7 +94,7 @@ public record LocalVarTargetImpl(TargetType targetType, List implements LocalVarTarget { public LocalVarTargetImpl(TargetType targetType, List table) { - this.targetType = checkValid(targetType, TAT_LOCAL_VARIABLE, TAT_RESOURCE_VARIABLE); + this.targetType = checkValid(targetType, TARGET_LOCAL_VARIABLE, TARGET_RESOURCE_VARIABLE); this.table = List.copyOf(table); } @Override @@ -122,7 +122,7 @@ public TargetType targetType() { public record OffsetTargetImpl(TargetType targetType, Label target) implements OffsetTarget { public OffsetTargetImpl(TargetType targetType, Label target) { - this.targetType = checkValid(targetType, TAT_INSTANCEOF, TAT_METHOD_REFERENCE); + this.targetType = checkValid(targetType, TARGET_INSTANCEOF, TARGET_METHOD_REFERENCE); this.target = requireNonNull(target); } } @@ -131,7 +131,7 @@ public record TypeArgumentTargetImpl(TargetType targetType, Label target, int ty implements TypeArgumentTarget { public TypeArgumentTargetImpl(TargetType targetType, Label target, int typeArgumentIndex) { - this.targetType = checkValid(targetType, TAT_CAST, TAT_METHOD_REFERENCE_TYPE_ARGUMENT); + this.targetType = checkValid(targetType, TARGET_CAST, TARGET_METHOD_REFERENCE_TYPE_ARGUMENT); this.target = requireNonNull(target); this.typeArgumentIndex = typeArgumentIndex; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java index de97730aff579..5aed968c6aefc 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java @@ -24,7 +24,7 @@ */ package jdk.internal.classfile.impl.verifier; -import java.lang.classfile.ClassFile; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; import jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType; import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*; @@ -83,7 +83,7 @@ static boolean is_valid(int code) { } static boolean is_store_into_local(int code) { - return (ClassFile.ISTORE <= code && code <= ClassFile.ASTORE_3); + return (ISTORE <= code && code <= ASTORE_3); } static final int _lengths[] = new int[number_of_codes]; @@ -104,244 +104,244 @@ static void def(int code, String name, String format, String wide_format, BasicT } static { - def(ClassFile.NOP, "nop", "b", null, T_VOID, 0); - def(ClassFile.ACONST_NULL, "aconst_null", "b", null, T_OBJECT, 1); - def(ClassFile.ICONST_M1, "iconst_m1", "b", null, T_INT, 1); - def(ClassFile.ICONST_0, "iconst_0", "b", null, T_INT, 1); - def(ClassFile.ICONST_1, "iconst_1", "b", null, T_INT, 1); - def(ClassFile.ICONST_2, "iconst_2", "b", null, T_INT, 1); - def(ClassFile.ICONST_3, "iconst_3", "b", null, T_INT, 1); - def(ClassFile.ICONST_4, "iconst_4", "b", null, T_INT, 1); - def(ClassFile.ICONST_5, "iconst_5", "b", null, T_INT, 1); - def(ClassFile.LCONST_0, "lconst_0", "b", null, T_LONG, 2); - def(ClassFile.LCONST_1, "lconst_1", "b", null, T_LONG, 2); - def(ClassFile.FCONST_0, "fconst_0", "b", null, T_FLOAT, 1); - def(ClassFile.FCONST_1, "fconst_1", "b", null, T_FLOAT, 1); - def(ClassFile.FCONST_2, "fconst_2", "b", null, T_FLOAT, 1); - def(ClassFile.DCONST_0, "dconst_0", "b", null, T_DOUBLE, 2); - def(ClassFile.DCONST_1, "dconst_1", "b", null, T_DOUBLE, 2); - def(ClassFile.BIPUSH, "bipush", "bc", null, T_INT, 1); - def(ClassFile.SIPUSH, "sipush", "bcc", null, T_INT, 1); - def(ClassFile.LDC, "ldc", "bk", null, T_ILLEGAL, 1); - def(ClassFile.LDC_W, "ldc_w", "bkk", null, T_ILLEGAL, 1); - def(ClassFile.LDC2_W, "ldc2_w", "bkk", null, T_ILLEGAL, 2); - def(ClassFile.ILOAD, "iload", "bi", "wbii", T_INT, 1); - def(ClassFile.LLOAD, "lload", "bi", "wbii", T_LONG, 2); - def(ClassFile.FLOAD, "fload", "bi", "wbii", T_FLOAT, 1); - def(ClassFile.DLOAD, "dload", "bi", "wbii", T_DOUBLE, 2); - def(ClassFile.ALOAD, "aload", "bi", "wbii", T_OBJECT, 1); - def(ClassFile.ILOAD_0, "iload_0", "b", null, T_INT, 1); - def(ClassFile.ILOAD_1, "iload_1", "b", null, T_INT, 1); - def(ClassFile.ILOAD_2, "iload_2", "b", null, T_INT, 1); - def(ClassFile.ILOAD_3, "iload_3", "b", null, T_INT, 1); - def(ClassFile.LLOAD_0, "lload_0", "b", null, T_LONG, 2); - def(ClassFile.LLOAD_1, "lload_1", "b", null, T_LONG, 2); - def(ClassFile.LLOAD_2, "lload_2", "b", null, T_LONG, 2); - def(ClassFile.LLOAD_3, "lload_3", "b", null, T_LONG, 2); - def(ClassFile.FLOAD_0, "fload_0", "b", null, T_FLOAT, 1); - def(ClassFile.FLOAD_1, "fload_1", "b", null, T_FLOAT, 1); - def(ClassFile.FLOAD_2, "fload_2", "b", null, T_FLOAT, 1); - def(ClassFile.FLOAD_3, "fload_3", "b", null, T_FLOAT, 1); - def(ClassFile.DLOAD_0, "dload_0", "b", null, T_DOUBLE, 2); - def(ClassFile.DLOAD_1, "dload_1", "b", null, T_DOUBLE, 2); - def(ClassFile.DLOAD_2, "dload_2", "b", null, T_DOUBLE, 2); - def(ClassFile.DLOAD_3, "dload_3", "b", null, T_DOUBLE, 2); - def(ClassFile.ALOAD_0, "aload_0", "b", null, T_OBJECT, 1); - def(ClassFile.ALOAD_1, "aload_1", "b", null, T_OBJECT, 1); - def(ClassFile.ALOAD_2, "aload_2", "b", null, T_OBJECT, 1); - def(ClassFile.ALOAD_3, "aload_3", "b", null, T_OBJECT, 1); - def(ClassFile.IALOAD, "iaload", "b", null, T_INT, -1); - def(ClassFile.LALOAD, "laload", "b", null, T_LONG, 0); - def(ClassFile.FALOAD, "faload", "b", null, T_FLOAT, -1); - def(ClassFile.DALOAD, "daload", "b", null, T_DOUBLE, 0); - def(ClassFile.AALOAD, "aaload", "b", null, T_OBJECT, -1); - def(ClassFile.BALOAD, "baload", "b", null, T_INT, -1); - def(ClassFile.CALOAD, "caload", "b", null, T_INT, -1); - def(ClassFile.SALOAD, "saload", "b", null, T_INT, -1); - def(ClassFile.ISTORE, "istore", "bi", "wbii", T_VOID, -1); - def(ClassFile.LSTORE, "lstore", "bi", "wbii", T_VOID, -2); - def(ClassFile.FSTORE, "fstore", "bi", "wbii", T_VOID, -1); - def(ClassFile.DSTORE, "dstore", "bi", "wbii", T_VOID, -2); - def(ClassFile.ASTORE, "astore", "bi", "wbii", T_VOID, -1); - def(ClassFile.ISTORE_0, "istore_0", "b", null, T_VOID, -1); - def(ClassFile.ISTORE_1, "istore_1", "b", null, T_VOID, -1); - def(ClassFile.ISTORE_2, "istore_2", "b", null, T_VOID, -1); - def(ClassFile.ISTORE_3, "istore_3", "b", null, T_VOID, -1); - def(ClassFile.LSTORE_0, "lstore_0", "b", null, T_VOID, -2); - def(ClassFile.LSTORE_1, "lstore_1", "b", null, T_VOID, -2); - def(ClassFile.LSTORE_2, "lstore_2", "b", null, T_VOID, -2); - def(ClassFile.LSTORE_3, "lstore_3", "b", null, T_VOID, -2); - def(ClassFile.FSTORE_0, "fstore_0", "b", null, T_VOID, -1); - def(ClassFile.FSTORE_1, "fstore_1", "b", null, T_VOID, -1); - def(ClassFile.FSTORE_2, "fstore_2", "b", null, T_VOID, -1); - def(ClassFile.FSTORE_3, "fstore_3", "b", null, T_VOID, -1); - def(ClassFile.DSTORE_0, "dstore_0", "b", null, T_VOID, -2); - def(ClassFile.DSTORE_1, "dstore_1", "b", null, T_VOID, -2); - def(ClassFile.DSTORE_2, "dstore_2", "b", null, T_VOID, -2); - def(ClassFile.DSTORE_3, "dstore_3", "b", null, T_VOID, -2); - def(ClassFile.ASTORE_0, "astore_0", "b", null, T_VOID, -1); - def(ClassFile.ASTORE_1, "astore_1", "b", null, T_VOID, -1); - def(ClassFile.ASTORE_2, "astore_2", "b", null, T_VOID, -1); - def(ClassFile.ASTORE_3, "astore_3", "b", null, T_VOID, -1); - def(ClassFile.IASTORE, "iastore", "b", null, T_VOID, -3); - def(ClassFile.LASTORE, "lastore", "b", null, T_VOID, -4); - def(ClassFile.FASTORE, "fastore", "b", null, T_VOID, -3); - def(ClassFile.DASTORE, "dastore", "b", null, T_VOID, -4); - def(ClassFile.AASTORE, "aastore", "b", null, T_VOID, -3); - def(ClassFile.BASTORE, "bastore", "b", null, T_VOID, -3); - def(ClassFile.CASTORE, "castore", "b", null, T_VOID, -3); - def(ClassFile.SASTORE, "sastore", "b", null, T_VOID, -3); - def(ClassFile.POP, "pop", "b", null, T_VOID, -1); - def(ClassFile.POP2, "pop2", "b", null, T_VOID, -2); - def(ClassFile.DUP, "dup", "b", null, T_VOID, 1); - def(ClassFile.DUP_X1, "dup_x1", "b", null, T_VOID, 1); - def(ClassFile.DUP_X2, "dup_x2", "b", null, T_VOID, 1); - def(ClassFile.DUP2, "dup2", "b", null, T_VOID, 2); - def(ClassFile.DUP2_X1, "dup2_x1", "b", null, T_VOID, 2); - def(ClassFile.DUP2_X2, "dup2_x2", "b", null, T_VOID, 2); - def(ClassFile.SWAP, "swap", "b", null, T_VOID, 0); - def(ClassFile.IADD, "iadd", "b", null, T_INT, -1); - def(ClassFile.LADD, "ladd", "b", null, T_LONG, -2); - def(ClassFile.FADD, "fadd", "b", null, T_FLOAT, -1); - def(ClassFile.DADD, "dadd", "b", null, T_DOUBLE, -2); - def(ClassFile.ISUB, "isub", "b", null, T_INT, -1); - def(ClassFile.LSUB, "lsub", "b", null, T_LONG, -2); - def(ClassFile.FSUB, "fsub", "b", null, T_FLOAT, -1); - def(ClassFile.DSUB, "dsub", "b", null, T_DOUBLE, -2); - def(ClassFile.IMUL, "imul", "b", null, T_INT, -1); - def(ClassFile.LMUL, "lmul", "b", null, T_LONG, -2); - def(ClassFile.FMUL, "fmul", "b", null, T_FLOAT, -1); - def(ClassFile.DMUL, "dmul", "b", null, T_DOUBLE, -2); - def(ClassFile.IDIV, "idiv", "b", null, T_INT, -1); - def(ClassFile.LDIV, "ldiv", "b", null, T_LONG, -2); - def(ClassFile.FDIV, "fdiv", "b", null, T_FLOAT, -1); - def(ClassFile.DDIV, "ddiv", "b", null, T_DOUBLE, -2); - def(ClassFile.IREM, "irem", "b", null, T_INT, -1); - def(ClassFile.LREM, "lrem", "b", null, T_LONG, -2); - def(ClassFile.FREM, "frem", "b", null, T_FLOAT, -1); - def(ClassFile.DREM, "drem", "b", null, T_DOUBLE, -2); - def(ClassFile.INEG, "ineg", "b", null, T_INT, 0); - def(ClassFile.LNEG, "lneg", "b", null, T_LONG, 0); - def(ClassFile.FNEG, "fneg", "b", null, T_FLOAT, 0); - def(ClassFile.DNEG, "dneg", "b", null, T_DOUBLE, 0); - def(ClassFile.ISHL, "ishl", "b", null, T_INT, -1); - def(ClassFile.LSHL, "lshl", "b", null, T_LONG, -1); - def(ClassFile.ISHR, "ishr", "b", null, T_INT, -1); - def(ClassFile.LSHR, "lshr", "b", null, T_LONG, -1); - def(ClassFile.IUSHR, "iushr", "b", null, T_INT, -1); - def(ClassFile.LUSHR, "lushr", "b", null, T_LONG, -1); - def(ClassFile.IAND, "iand", "b", null, T_INT, -1); - def(ClassFile.LAND, "land", "b", null, T_LONG, -2); - def(ClassFile.IOR, "ior", "b", null, T_INT, -1); - def(ClassFile.LOR, "lor", "b", null, T_LONG, -2); - def(ClassFile.IXOR, "ixor", "b", null, T_INT, -1); - def(ClassFile.LXOR, "lxor", "b", null, T_LONG, -2); - def(ClassFile.IINC, "iinc", "bic", "wbiicc", T_VOID, 0); - def(ClassFile.I2L, "i2l", "b", null, T_LONG, 1); - def(ClassFile.I2F, "i2f", "b", null, T_FLOAT, 0); - def(ClassFile.I2D, "i2d", "b", null, T_DOUBLE, 1); - def(ClassFile.L2I, "l2i", "b", null, T_INT, -1); - def(ClassFile.L2F, "l2f", "b", null, T_FLOAT, -1); - def(ClassFile.L2D, "l2d", "b", null, T_DOUBLE, 0); - def(ClassFile.F2I, "f2i", "b", null, T_INT, 0); - def(ClassFile.F2L, "f2l", "b", null, T_LONG, 1); - def(ClassFile.F2D, "f2d", "b", null, T_DOUBLE, 1); - def(ClassFile.D2I, "d2i", "b", null, T_INT, -1); - def(ClassFile.D2L, "d2l", "b", null, T_LONG, 0); - def(ClassFile.D2F, "d2f", "b", null, T_FLOAT, -1); - def(ClassFile.I2B, "i2b", "b", null, T_BYTE, 0); - def(ClassFile.I2C, "i2c", "b", null, T_CHAR, 0); - def(ClassFile.I2S, "i2s", "b", null, T_SHORT, 0); - def(ClassFile.LCMP, "lcmp", "b", null, T_VOID, -3); - def(ClassFile.FCMPL, "fcmpl", "b", null, T_VOID, -1); - def(ClassFile.FCMPG, "fcmpg", "b", null, T_VOID, -1); - def(ClassFile.DCMPL, "dcmpl", "b", null, T_VOID, -3); - def(ClassFile.DCMPG, "dcmpg", "b", null, T_VOID, -3); - def(ClassFile.IFEQ, "ifeq", "boo", null, T_VOID, -1); - def(ClassFile.IFNE, "ifne", "boo", null, T_VOID, -1); - def(ClassFile.IFLT, "iflt", "boo", null, T_VOID, -1); - def(ClassFile.IFGE, "ifge", "boo", null, T_VOID, -1); - def(ClassFile.IFGT, "ifgt", "boo", null, T_VOID, -1); - def(ClassFile.IFLE, "ifle", "boo", null, T_VOID, -1); - def(ClassFile.IF_ICMPEQ, "if_icmpeq", "boo", null, T_VOID, -2); - def(ClassFile.IF_ICMPNE, "if_icmpne", "boo", null, T_VOID, -2); - def(ClassFile.IF_ICMPLT, "if_icmplt", "boo", null, T_VOID, -2); - def(ClassFile.IF_ICMPGE, "if_icmpge", "boo", null, T_VOID, -2); - def(ClassFile.IF_ICMPGT, "if_icmpgt", "boo", null, T_VOID, -2); - def(ClassFile.IF_ICMPLE, "if_icmple", "boo", null, T_VOID, -2); - def(ClassFile.IF_ACMPEQ, "if_acmpeq", "boo", null, T_VOID, -2); - def(ClassFile.IF_ACMPNE, "if_acmpne", "boo", null, T_VOID, -2); - def(ClassFile.GOTO, "goto", "boo", null, T_VOID, 0); - def(ClassFile.JSR, "jsr", "boo", null, T_INT, 0); - def(ClassFile.RET, "ret", "bi", "wbii", T_VOID, 0); - def(ClassFile.TABLESWITCH, "tableswitch", "", null, T_VOID, -1); // may have backward branches - def(ClassFile.LOOKUPSWITCH, "lookupswitch", "", null, T_VOID, -1); // rewriting in interpreter - def(ClassFile.IRETURN, "ireturn", "b", null, T_INT, -1); - def(ClassFile.LRETURN, "lreturn", "b", null, T_LONG, -2); - def(ClassFile.FRETURN, "freturn", "b", null, T_FLOAT, -1); - def(ClassFile.DRETURN, "dreturn", "b", null, T_DOUBLE, -2); - def(ClassFile.ARETURN, "areturn", "b", null, T_OBJECT, -1); - def(ClassFile.RETURN, "return", "b", null, T_VOID, 0); - def(ClassFile.GETSTATIC, "getstatic", "bJJ", null, T_ILLEGAL, 1); - def(ClassFile.PUTSTATIC, "putstatic", "bJJ", null, T_ILLEGAL, -1); - def(ClassFile.GETFIELD, "getfield", "bJJ", null, T_ILLEGAL, 0); - def(ClassFile.PUTFIELD, "putfield", "bJJ", null, T_ILLEGAL, -2); - def(ClassFile.INVOKEVIRTUAL, "invokevirtual", "bJJ", null, T_ILLEGAL, -1); - def(ClassFile.INVOKESPECIAL, "invokespecial", "bJJ", null, T_ILLEGAL, -1); - def(ClassFile.INVOKESTATIC, "invokestatic", "bJJ", null, T_ILLEGAL, 0); - def(ClassFile.INVOKEINTERFACE, "invokeinterface", "bJJ__", null, T_ILLEGAL, -1); - def(ClassFile.INVOKEDYNAMIC, "invokedynamic", "bJJJJ", null, T_ILLEGAL, 0); - def(ClassFile.NEW, "new", "bkk", null, T_OBJECT, 1); - def(ClassFile.NEWARRAY, "newarray", "bc", null, T_OBJECT, 0); - def(ClassFile.ANEWARRAY, "anewarray", "bkk", null, T_OBJECT, 0); - def(ClassFile.ARRAYLENGTH, "arraylength", "b", null, T_VOID, 0); - def(ClassFile.ATHROW, "athrow", "b", null, T_VOID, -1); - def(ClassFile.CHECKCAST, "checkcast", "bkk", null, T_OBJECT, 0); - def(ClassFile.INSTANCEOF, "instanceof", "bkk", null, T_INT, 0); - def(ClassFile.MONITORENTER, "monitorenter", "b", null, T_VOID, -1); - def(ClassFile.MONITOREXIT, "monitorexit", "b", null, T_VOID, -1); - def(ClassFile.WIDE, "wide", "", null, T_VOID, 0); - def(ClassFile.MULTIANEWARRAY, "multianewarray", "bkkc", null, T_OBJECT, 1); - def(ClassFile.IFNULL, "ifnull", "boo", null, T_VOID, -1); - def(ClassFile.IFNONNULL, "ifnonnull", "boo", null, T_VOID, -1); - def(ClassFile.GOTO_W, "goto_w", "boooo", null, T_VOID, 0); - def(ClassFile.JSR_W, "jsr_w", "boooo", null, T_INT, 0); + def(NOP, "nop", "b", null, T_VOID, 0); + def(ACONST_NULL, "aconst_null", "b", null, T_OBJECT, 1); + def(ICONST_M1, "iconst_m1", "b", null, T_INT, 1); + def(ICONST_0, "iconst_0", "b", null, T_INT, 1); + def(ICONST_1, "iconst_1", "b", null, T_INT, 1); + def(ICONST_2, "iconst_2", "b", null, T_INT, 1); + def(ICONST_3, "iconst_3", "b", null, T_INT, 1); + def(ICONST_4, "iconst_4", "b", null, T_INT, 1); + def(ICONST_5, "iconst_5", "b", null, T_INT, 1); + def(LCONST_0, "lconst_0", "b", null, T_LONG, 2); + def(LCONST_1, "lconst_1", "b", null, T_LONG, 2); + def(FCONST_0, "fconst_0", "b", null, T_FLOAT, 1); + def(FCONST_1, "fconst_1", "b", null, T_FLOAT, 1); + def(FCONST_2, "fconst_2", "b", null, T_FLOAT, 1); + def(DCONST_0, "dconst_0", "b", null, T_DOUBLE, 2); + def(DCONST_1, "dconst_1", "b", null, T_DOUBLE, 2); + def(BIPUSH, "bipush", "bc", null, T_INT, 1); + def(SIPUSH, "sipush", "bcc", null, T_INT, 1); + def(LDC, "ldc", "bk", null, T_ILLEGAL, 1); + def(LDC_W, "ldc_w", "bkk", null, T_ILLEGAL, 1); + def(LDC2_W, "ldc2_w", "bkk", null, T_ILLEGAL, 2); + def(ILOAD, "iload", "bi", "wbii", T_INT, 1); + def(LLOAD, "lload", "bi", "wbii", T_LONG, 2); + def(FLOAD, "fload", "bi", "wbii", T_FLOAT, 1); + def(DLOAD, "dload", "bi", "wbii", T_DOUBLE, 2); + def(ALOAD, "aload", "bi", "wbii", T_OBJECT, 1); + def(ILOAD_0, "iload_0", "b", null, T_INT, 1); + def(ILOAD_1, "iload_1", "b", null, T_INT, 1); + def(ILOAD_2, "iload_2", "b", null, T_INT, 1); + def(ILOAD_3, "iload_3", "b", null, T_INT, 1); + def(LLOAD_0, "lload_0", "b", null, T_LONG, 2); + def(LLOAD_1, "lload_1", "b", null, T_LONG, 2); + def(LLOAD_2, "lload_2", "b", null, T_LONG, 2); + def(LLOAD_3, "lload_3", "b", null, T_LONG, 2); + def(FLOAD_0, "fload_0", "b", null, T_FLOAT, 1); + def(FLOAD_1, "fload_1", "b", null, T_FLOAT, 1); + def(FLOAD_2, "fload_2", "b", null, T_FLOAT, 1); + def(FLOAD_3, "fload_3", "b", null, T_FLOAT, 1); + def(DLOAD_0, "dload_0", "b", null, T_DOUBLE, 2); + def(DLOAD_1, "dload_1", "b", null, T_DOUBLE, 2); + def(DLOAD_2, "dload_2", "b", null, T_DOUBLE, 2); + def(DLOAD_3, "dload_3", "b", null, T_DOUBLE, 2); + def(ALOAD_0, "aload_0", "b", null, T_OBJECT, 1); + def(ALOAD_1, "aload_1", "b", null, T_OBJECT, 1); + def(ALOAD_2, "aload_2", "b", null, T_OBJECT, 1); + def(ALOAD_3, "aload_3", "b", null, T_OBJECT, 1); + def(IALOAD, "iaload", "b", null, T_INT, -1); + def(LALOAD, "laload", "b", null, T_LONG, 0); + def(FALOAD, "faload", "b", null, T_FLOAT, -1); + def(DALOAD, "daload", "b", null, T_DOUBLE, 0); + def(AALOAD, "aaload", "b", null, T_OBJECT, -1); + def(BALOAD, "baload", "b", null, T_INT, -1); + def(CALOAD, "caload", "b", null, T_INT, -1); + def(SALOAD, "saload", "b", null, T_INT, -1); + def(ISTORE, "istore", "bi", "wbii", T_VOID, -1); + def(LSTORE, "lstore", "bi", "wbii", T_VOID, -2); + def(FSTORE, "fstore", "bi", "wbii", T_VOID, -1); + def(DSTORE, "dstore", "bi", "wbii", T_VOID, -2); + def(ASTORE, "astore", "bi", "wbii", T_VOID, -1); + def(ISTORE_0, "istore_0", "b", null, T_VOID, -1); + def(ISTORE_1, "istore_1", "b", null, T_VOID, -1); + def(ISTORE_2, "istore_2", "b", null, T_VOID, -1); + def(ISTORE_3, "istore_3", "b", null, T_VOID, -1); + def(LSTORE_0, "lstore_0", "b", null, T_VOID, -2); + def(LSTORE_1, "lstore_1", "b", null, T_VOID, -2); + def(LSTORE_2, "lstore_2", "b", null, T_VOID, -2); + def(LSTORE_3, "lstore_3", "b", null, T_VOID, -2); + def(FSTORE_0, "fstore_0", "b", null, T_VOID, -1); + def(FSTORE_1, "fstore_1", "b", null, T_VOID, -1); + def(FSTORE_2, "fstore_2", "b", null, T_VOID, -1); + def(FSTORE_3, "fstore_3", "b", null, T_VOID, -1); + def(DSTORE_0, "dstore_0", "b", null, T_VOID, -2); + def(DSTORE_1, "dstore_1", "b", null, T_VOID, -2); + def(DSTORE_2, "dstore_2", "b", null, T_VOID, -2); + def(DSTORE_3, "dstore_3", "b", null, T_VOID, -2); + def(ASTORE_0, "astore_0", "b", null, T_VOID, -1); + def(ASTORE_1, "astore_1", "b", null, T_VOID, -1); + def(ASTORE_2, "astore_2", "b", null, T_VOID, -1); + def(ASTORE_3, "astore_3", "b", null, T_VOID, -1); + def(IASTORE, "iastore", "b", null, T_VOID, -3); + def(LASTORE, "lastore", "b", null, T_VOID, -4); + def(FASTORE, "fastore", "b", null, T_VOID, -3); + def(DASTORE, "dastore", "b", null, T_VOID, -4); + def(AASTORE, "aastore", "b", null, T_VOID, -3); + def(BASTORE, "bastore", "b", null, T_VOID, -3); + def(CASTORE, "castore", "b", null, T_VOID, -3); + def(SASTORE, "sastore", "b", null, T_VOID, -3); + def(POP, "pop", "b", null, T_VOID, -1); + def(POP2, "pop2", "b", null, T_VOID, -2); + def(DUP, "dup", "b", null, T_VOID, 1); + def(DUP_X1, "dup_x1", "b", null, T_VOID, 1); + def(DUP_X2, "dup_x2", "b", null, T_VOID, 1); + def(DUP2, "dup2", "b", null, T_VOID, 2); + def(DUP2_X1, "dup2_x1", "b", null, T_VOID, 2); + def(DUP2_X2, "dup2_x2", "b", null, T_VOID, 2); + def(SWAP, "swap", "b", null, T_VOID, 0); + def(IADD, "iadd", "b", null, T_INT, -1); + def(LADD, "ladd", "b", null, T_LONG, -2); + def(FADD, "fadd", "b", null, T_FLOAT, -1); + def(DADD, "dadd", "b", null, T_DOUBLE, -2); + def(ISUB, "isub", "b", null, T_INT, -1); + def(LSUB, "lsub", "b", null, T_LONG, -2); + def(FSUB, "fsub", "b", null, T_FLOAT, -1); + def(DSUB, "dsub", "b", null, T_DOUBLE, -2); + def(IMUL, "imul", "b", null, T_INT, -1); + def(LMUL, "lmul", "b", null, T_LONG, -2); + def(FMUL, "fmul", "b", null, T_FLOAT, -1); + def(DMUL, "dmul", "b", null, T_DOUBLE, -2); + def(IDIV, "idiv", "b", null, T_INT, -1); + def(LDIV, "ldiv", "b", null, T_LONG, -2); + def(FDIV, "fdiv", "b", null, T_FLOAT, -1); + def(DDIV, "ddiv", "b", null, T_DOUBLE, -2); + def(IREM, "irem", "b", null, T_INT, -1); + def(LREM, "lrem", "b", null, T_LONG, -2); + def(FREM, "frem", "b", null, T_FLOAT, -1); + def(DREM, "drem", "b", null, T_DOUBLE, -2); + def(INEG, "ineg", "b", null, T_INT, 0); + def(LNEG, "lneg", "b", null, T_LONG, 0); + def(FNEG, "fneg", "b", null, T_FLOAT, 0); + def(DNEG, "dneg", "b", null, T_DOUBLE, 0); + def(ISHL, "ishl", "b", null, T_INT, -1); + def(LSHL, "lshl", "b", null, T_LONG, -1); + def(ISHR, "ishr", "b", null, T_INT, -1); + def(LSHR, "lshr", "b", null, T_LONG, -1); + def(IUSHR, "iushr", "b", null, T_INT, -1); + def(LUSHR, "lushr", "b", null, T_LONG, -1); + def(IAND, "iand", "b", null, T_INT, -1); + def(LAND, "land", "b", null, T_LONG, -2); + def(IOR, "ior", "b", null, T_INT, -1); + def(LOR, "lor", "b", null, T_LONG, -2); + def(IXOR, "ixor", "b", null, T_INT, -1); + def(LXOR, "lxor", "b", null, T_LONG, -2); + def(IINC, "iinc", "bic", "wbiicc", T_VOID, 0); + def(I2L, "i2l", "b", null, T_LONG, 1); + def(I2F, "i2f", "b", null, T_FLOAT, 0); + def(I2D, "i2d", "b", null, T_DOUBLE, 1); + def(L2I, "l2i", "b", null, T_INT, -1); + def(L2F, "l2f", "b", null, T_FLOAT, -1); + def(L2D, "l2d", "b", null, T_DOUBLE, 0); + def(F2I, "f2i", "b", null, T_INT, 0); + def(F2L, "f2l", "b", null, T_LONG, 1); + def(F2D, "f2d", "b", null, T_DOUBLE, 1); + def(D2I, "d2i", "b", null, T_INT, -1); + def(D2L, "d2l", "b", null, T_LONG, 0); + def(D2F, "d2f", "b", null, T_FLOAT, -1); + def(I2B, "i2b", "b", null, T_BYTE, 0); + def(I2C, "i2c", "b", null, T_CHAR, 0); + def(I2S, "i2s", "b", null, T_SHORT, 0); + def(LCMP, "lcmp", "b", null, T_VOID, -3); + def(FCMPL, "fcmpl", "b", null, T_VOID, -1); + def(FCMPG, "fcmpg", "b", null, T_VOID, -1); + def(DCMPL, "dcmpl", "b", null, T_VOID, -3); + def(DCMPG, "dcmpg", "b", null, T_VOID, -3); + def(IFEQ, "ifeq", "boo", null, T_VOID, -1); + def(IFNE, "ifne", "boo", null, T_VOID, -1); + def(IFLT, "iflt", "boo", null, T_VOID, -1); + def(IFGE, "ifge", "boo", null, T_VOID, -1); + def(IFGT, "ifgt", "boo", null, T_VOID, -1); + def(IFLE, "ifle", "boo", null, T_VOID, -1); + def(IF_ICMPEQ, "if_icmpeq", "boo", null, T_VOID, -2); + def(IF_ICMPNE, "if_icmpne", "boo", null, T_VOID, -2); + def(IF_ICMPLT, "if_icmplt", "boo", null, T_VOID, -2); + def(IF_ICMPGE, "if_icmpge", "boo", null, T_VOID, -2); + def(IF_ICMPGT, "if_icmpgt", "boo", null, T_VOID, -2); + def(IF_ICMPLE, "if_icmple", "boo", null, T_VOID, -2); + def(IF_ACMPEQ, "if_acmpeq", "boo", null, T_VOID, -2); + def(IF_ACMPNE, "if_acmpne", "boo", null, T_VOID, -2); + def(GOTO, "goto", "boo", null, T_VOID, 0); + def(JSR, "jsr", "boo", null, T_INT, 0); + def(RET, "ret", "bi", "wbii", T_VOID, 0); + def(TABLESWITCH, "tableswitch", "", null, T_VOID, -1); // may have backward branches + def(LOOKUPSWITCH, "lookupswitch", "", null, T_VOID, -1); // rewriting in interpreter + def(IRETURN, "ireturn", "b", null, T_INT, -1); + def(LRETURN, "lreturn", "b", null, T_LONG, -2); + def(FRETURN, "freturn", "b", null, T_FLOAT, -1); + def(DRETURN, "dreturn", "b", null, T_DOUBLE, -2); + def(ARETURN, "areturn", "b", null, T_OBJECT, -1); + def(RETURN, "return", "b", null, T_VOID, 0); + def(GETSTATIC, "getstatic", "bJJ", null, T_ILLEGAL, 1); + def(PUTSTATIC, "putstatic", "bJJ", null, T_ILLEGAL, -1); + def(GETFIELD, "getfield", "bJJ", null, T_ILLEGAL, 0); + def(PUTFIELD, "putfield", "bJJ", null, T_ILLEGAL, -2); + def(INVOKEVIRTUAL, "invokevirtual", "bJJ", null, T_ILLEGAL, -1); + def(INVOKESPECIAL, "invokespecial", "bJJ", null, T_ILLEGAL, -1); + def(INVOKESTATIC, "invokestatic", "bJJ", null, T_ILLEGAL, 0); + def(INVOKEINTERFACE, "invokeinterface", "bJJ__", null, T_ILLEGAL, -1); + def(INVOKEDYNAMIC, "invokedynamic", "bJJJJ", null, T_ILLEGAL, 0); + def(NEW, "new", "bkk", null, T_OBJECT, 1); + def(NEWARRAY, "newarray", "bc", null, T_OBJECT, 0); + def(ANEWARRAY, "anewarray", "bkk", null, T_OBJECT, 0); + def(ARRAYLENGTH, "arraylength", "b", null, T_VOID, 0); + def(ATHROW, "athrow", "b", null, T_VOID, -1); + def(CHECKCAST, "checkcast", "bkk", null, T_OBJECT, 0); + def(INSTANCEOF, "instanceof", "bkk", null, T_INT, 0); + def(MONITORENTER, "monitorenter", "b", null, T_VOID, -1); + def(MONITOREXIT, "monitorexit", "b", null, T_VOID, -1); + def(WIDE, "wide", "", null, T_VOID, 0); + def(MULTIANEWARRAY, "multianewarray", "bkkc", null, T_OBJECT, 1); + def(IFNULL, "ifnull", "boo", null, T_VOID, -1); + def(IFNONNULL, "ifnonnull", "boo", null, T_VOID, -1); + def(GOTO_W, "goto_w", "boooo", null, T_VOID, 0); + def(JSR_W, "jsr_w", "boooo", null, T_INT, 0); def(_breakpoint, "breakpoint", "", null, T_VOID, 0); - def(_fast_agetfield, "fast_agetfield", "bJJ", null, T_OBJECT, 0, ClassFile.GETFIELD); - def(_fast_bgetfield, "fast_bgetfield", "bJJ", null, T_INT, 0, ClassFile.GETFIELD); - def(_fast_cgetfield, "fast_cgetfield", "bJJ", null, T_CHAR, 0, ClassFile.GETFIELD); - def(_fast_dgetfield, "fast_dgetfield", "bJJ", null, T_DOUBLE, 0, ClassFile.GETFIELD); - def(_fast_fgetfield, "fast_fgetfield", "bJJ", null, T_FLOAT, 0, ClassFile.GETFIELD); - def(_fast_igetfield, "fast_igetfield", "bJJ", null, T_INT, 0, ClassFile.GETFIELD); - def(_fast_lgetfield, "fast_lgetfield", "bJJ", null, T_LONG, 0, ClassFile.GETFIELD); - def(_fast_sgetfield, "fast_sgetfield", "bJJ", null, T_SHORT, 0, ClassFile.GETFIELD); - def(_fast_aputfield, "fast_aputfield", "bJJ", null, T_OBJECT, 0, ClassFile.PUTFIELD); - def(_fast_bputfield, "fast_bputfield", "bJJ", null, T_INT, 0, ClassFile.PUTFIELD); - def(_fast_zputfield, "fast_zputfield", "bJJ", null, T_INT, 0, ClassFile.PUTFIELD); - def(_fast_cputfield, "fast_cputfield", "bJJ", null, T_CHAR, 0, ClassFile.PUTFIELD); - def(_fast_dputfield, "fast_dputfield", "bJJ", null, T_DOUBLE, 0, ClassFile.PUTFIELD); - def(_fast_fputfield, "fast_fputfield", "bJJ", null, T_FLOAT, 0, ClassFile.PUTFIELD); - def(_fast_iputfield, "fast_iputfield", "bJJ", null, T_INT, 0, ClassFile.PUTFIELD); - def(_fast_lputfield, "fast_lputfield", "bJJ", null, T_LONG, 0, ClassFile.PUTFIELD); - def(_fast_sputfield, "fast_sputfield", "bJJ", null, T_SHORT, 0, ClassFile.PUTFIELD); - def(_fast_aload_0, "fast_aload_0", "b", null, T_OBJECT, 1, ClassFile.ALOAD_0); - def(_fast_iaccess_0, "fast_iaccess_0", "b_JJ", null, T_INT, 1, ClassFile.ALOAD_0); - def(_fast_aaccess_0, "fast_aaccess_0", "b_JJ", null, T_OBJECT, 1, ClassFile.ALOAD_0); - def(_fast_faccess_0, "fast_faccess_0", "b_JJ", null, T_OBJECT, 1, ClassFile.ALOAD_0); - def(_fast_iload, "fast_iload", "bi", null, T_INT, 1, ClassFile.ILOAD); - def(_fast_iload2, "fast_iload2", "bi_i", null, T_INT, 2, ClassFile.ILOAD); - def(_fast_icaload, "fast_icaload", "bi_", null, T_INT, 0, ClassFile.ILOAD); - def(_fast_invokevfinal, "fast_invokevfinal", "bJJ", null, T_ILLEGAL, -1, ClassFile.INVOKEVIRTUAL); - def(_fast_linearswitch, "fast_linearswitch", "", null, T_VOID, -1, ClassFile.LOOKUPSWITCH); - def(_fast_binaryswitch, "fast_binaryswitch", "", null, T_VOID, -1, ClassFile.LOOKUPSWITCH); - def(_return_register_finalizer, "return_register_finalizer", "b", null, T_VOID, 0, ClassFile.RETURN); - def(_invokehandle, "invokehandle", "bJJ", null, T_ILLEGAL, -1, ClassFile.INVOKEVIRTUAL); - def(_fast_aldc, "fast_aldc", "bj", null, T_OBJECT, 1, ClassFile.LDC); - def(_fast_aldc_w, "fast_aldc_w", "bJJ", null, T_OBJECT, 1, ClassFile.LDC_W); - def(_nofast_getfield, "nofast_getfield", "bJJ", null, T_ILLEGAL, 0, ClassFile.GETFIELD); - def(_nofast_putfield, "nofast PUTFIELD", "bJJ", null, T_ILLEGAL, -2, ClassFile.PUTFIELD); - def(_nofast_aload_0, "nofast_aload_0", "b", null, T_ILLEGAL, 1, ClassFile.ALOAD_0); - def(_nofast_iload, "nofast_iload", "bi", null, T_ILLEGAL, 1, ClassFile.ILOAD); + def(_fast_agetfield, "fast_agetfield", "bJJ", null, T_OBJECT, 0, GETFIELD); + def(_fast_bgetfield, "fast_bgetfield", "bJJ", null, T_INT, 0, GETFIELD); + def(_fast_cgetfield, "fast_cgetfield", "bJJ", null, T_CHAR, 0, GETFIELD); + def(_fast_dgetfield, "fast_dgetfield", "bJJ", null, T_DOUBLE, 0, GETFIELD); + def(_fast_fgetfield, "fast_fgetfield", "bJJ", null, T_FLOAT, 0, GETFIELD); + def(_fast_igetfield, "fast_igetfield", "bJJ", null, T_INT, 0, GETFIELD); + def(_fast_lgetfield, "fast_lgetfield", "bJJ", null, T_LONG, 0, GETFIELD); + def(_fast_sgetfield, "fast_sgetfield", "bJJ", null, T_SHORT, 0, GETFIELD); + def(_fast_aputfield, "fast_aputfield", "bJJ", null, T_OBJECT, 0, PUTFIELD); + def(_fast_bputfield, "fast_bputfield", "bJJ", null, T_INT, 0, PUTFIELD); + def(_fast_zputfield, "fast_zputfield", "bJJ", null, T_INT, 0, PUTFIELD); + def(_fast_cputfield, "fast_cputfield", "bJJ", null, T_CHAR, 0, PUTFIELD); + def(_fast_dputfield, "fast_dputfield", "bJJ", null, T_DOUBLE, 0, PUTFIELD); + def(_fast_fputfield, "fast_fputfield", "bJJ", null, T_FLOAT, 0, PUTFIELD); + def(_fast_iputfield, "fast_iputfield", "bJJ", null, T_INT, 0, PUTFIELD); + def(_fast_lputfield, "fast_lputfield", "bJJ", null, T_LONG, 0, PUTFIELD); + def(_fast_sputfield, "fast_sputfield", "bJJ", null, T_SHORT, 0, PUTFIELD); + def(_fast_aload_0, "fast_aload_0", "b", null, T_OBJECT, 1, ALOAD_0); + def(_fast_iaccess_0, "fast_iaccess_0", "b_JJ", null, T_INT, 1, ALOAD_0); + def(_fast_aaccess_0, "fast_aaccess_0", "b_JJ", null, T_OBJECT, 1, ALOAD_0); + def(_fast_faccess_0, "fast_faccess_0", "b_JJ", null, T_OBJECT, 1, ALOAD_0); + def(_fast_iload, "fast_iload", "bi", null, T_INT, 1, ILOAD); + def(_fast_iload2, "fast_iload2", "bi_i", null, T_INT, 2, ILOAD); + def(_fast_icaload, "fast_icaload", "bi_", null, T_INT, 0, ILOAD); + def(_fast_invokevfinal, "fast_invokevfinal", "bJJ", null, T_ILLEGAL, -1, INVOKEVIRTUAL); + def(_fast_linearswitch, "fast_linearswitch", "", null, T_VOID, -1, LOOKUPSWITCH); + def(_fast_binaryswitch, "fast_binaryswitch", "", null, T_VOID, -1, LOOKUPSWITCH); + def(_return_register_finalizer, "return_register_finalizer", "b", null, T_VOID, 0, RETURN); + def(_invokehandle, "invokehandle", "bJJ", null, T_ILLEGAL, -1, INVOKEVIRTUAL); + def(_fast_aldc, "fast_aldc", "bj", null, T_OBJECT, 1, LDC); + def(_fast_aldc_w, "fast_aldc_w", "bJJ", null, T_OBJECT, 1, LDC_W); + def(_nofast_getfield, "nofast_getfield", "bJJ", null, T_ILLEGAL, 0, GETFIELD); + def(_nofast_putfield, "nofast PUTFIELD", "bJJ", null, T_ILLEGAL, -2, PUTFIELD); + def(_nofast_aload_0, "nofast_aload_0", "b", null, T_ILLEGAL, 1, ALOAD_0); + def(_nofast_iload, "nofast_iload", "bi", null, T_ILLEGAL, 1, ILOAD); def(_shouldnotreachhere, "_shouldnotreachhere", "b", null, T_VOID, 0); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java index 9a0e781d1458a..f41647788a175 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java @@ -31,10 +31,9 @@ import java.lang.classfile.ClassHierarchyResolver; import java.lang.classfile.ClassModel; import java.lang.classfile.components.ClassPrinter; -import java.lang.classfile.ClassFile; import jdk.internal.classfile.impl.ClassHierarchyImpl; import jdk.internal.classfile.impl.RawBytecodeHelper; -import static jdk.internal.classfile.impl.RawBytecodeHelper.ILLEGAL; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; import jdk.internal.classfile.impl.verifier.VerificationWrapper.ConstantPoolWrapper; import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*; import jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType; @@ -340,12 +339,12 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType type, type2 = null; VerificationType atype; if (bcs.isWide()) { - if (opcode != ClassFile.IINC && opcode != ClassFile.ILOAD - && opcode != ClassFile.ALOAD && opcode != ClassFile.LLOAD - && opcode != ClassFile.ISTORE && opcode != ClassFile.ASTORE - && opcode != ClassFile.LSTORE && opcode != ClassFile.FLOAD - && opcode != ClassFile.DLOAD && opcode != ClassFile.FSTORE - && opcode != ClassFile.DSTORE) { + if (opcode != IINC && opcode != ILOAD + && opcode != ALOAD && opcode != LLOAD + && opcode != ISTORE && opcode != ASTORE + && opcode != LSTORE && opcode != FLOAD + && opcode != DLOAD && opcode != FSTORE + && opcode != DSTORE) { verifyError("Bad wide instruction"); } } @@ -354,107 +353,107 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verified_exc_handlers = true; } switch (opcode) { - case ClassFile.NOP : + case NOP : no_control_flow = false; break; - case ClassFile.ACONST_NULL : + case ACONST_NULL : current_frame.push_stack( VerificationType.null_type); no_control_flow = false; break; - case ClassFile.ICONST_M1 : - case ClassFile.ICONST_0 : - case ClassFile.ICONST_1 : - case ClassFile.ICONST_2 : - case ClassFile.ICONST_3 : - case ClassFile.ICONST_4 : - case ClassFile.ICONST_5 : + case ICONST_M1 : + case ICONST_0 : + case ICONST_1 : + case ICONST_2 : + case ICONST_3 : + case ICONST_4 : + case ICONST_5 : current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.LCONST_0 : - case ClassFile.LCONST_1 : + case LCONST_0 : + case LCONST_1 : current_frame.push_stack_2( VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.FCONST_0 : - case ClassFile.FCONST_1 : - case ClassFile.FCONST_2 : + case FCONST_0 : + case FCONST_1 : + case FCONST_2 : current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.DCONST_0 : - case ClassFile.DCONST_1 : + case DCONST_0 : + case DCONST_1 : current_frame.push_stack_2( VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.SIPUSH : - case ClassFile.BIPUSH : + case SIPUSH : + case BIPUSH : current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.LDC : + case LDC : verify_ldc( opcode, bcs.getIndexU1(), current_frame, cp, bci); no_control_flow = false; break; - case ClassFile.LDC_W : - case ClassFile.LDC2_W : + case LDC_W : + case LDC2_W : verify_ldc( opcode, bcs.getIndexU2(), current_frame, cp, bci); no_control_flow = false; break; - case ClassFile.ILOAD : + case ILOAD : verify_iload(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.ILOAD_0 : - case ClassFile.ILOAD_1 : - case ClassFile.ILOAD_2 : - case ClassFile.ILOAD_3 : - index = opcode - ClassFile.ILOAD_0; + case ILOAD_0 : + case ILOAD_1 : + case ILOAD_2 : + case ILOAD_3 : + index = opcode - ILOAD_0; verify_iload(index, current_frame); no_control_flow = false; break; - case ClassFile.LLOAD : + case LLOAD : verify_lload(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.LLOAD_0 : - case ClassFile.LLOAD_1 : - case ClassFile.LLOAD_2 : - case ClassFile.LLOAD_3 : - index = opcode - ClassFile.LLOAD_0; + case LLOAD_0 : + case LLOAD_1 : + case LLOAD_2 : + case LLOAD_3 : + index = opcode - LLOAD_0; verify_lload(index, current_frame); no_control_flow = false; break; - case ClassFile.FLOAD : + case FLOAD : verify_fload(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.FLOAD_0 : - case ClassFile.FLOAD_1 : - case ClassFile.FLOAD_2 : - case ClassFile.FLOAD_3 : - index = opcode - ClassFile.FLOAD_0; + case FLOAD_0 : + case FLOAD_1 : + case FLOAD_2 : + case FLOAD_3 : + index = opcode - FLOAD_0; verify_fload(index, current_frame); no_control_flow = false; break; - case ClassFile.DLOAD : + case DLOAD : verify_dload(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.DLOAD_0 : - case ClassFile.DLOAD_1 : - case ClassFile.DLOAD_2 : - case ClassFile.DLOAD_3 : - index = opcode - ClassFile.DLOAD_0; + case DLOAD_0 : + case DLOAD_1 : + case DLOAD_2 : + case DLOAD_3 : + index = opcode - DLOAD_0; verify_dload(index, current_frame); no_control_flow = false; break; - case ClassFile.ALOAD : + case ALOAD : verify_aload(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.ALOAD_0 : - case ClassFile.ALOAD_1 : - case ClassFile.ALOAD_2 : - case ClassFile.ALOAD_3 : - index = opcode - ClassFile.ALOAD_0; + case ALOAD_0 : + case ALOAD_1 : + case ALOAD_2 : + case ALOAD_3 : + index = opcode - ALOAD_0; verify_aload(index, current_frame); no_control_flow = false; break; - case ClassFile.IALOAD : + case IALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -465,7 +464,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.BALOAD : + case BALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -476,7 +475,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.CALOAD : + case CALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -487,7 +486,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.SALOAD : + case SALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -498,7 +497,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.LALOAD : + case LALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -510,7 +509,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.FALOAD : + case FALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -521,7 +520,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.DALOAD : + case DALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -533,7 +532,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.AALOAD : { + case AALOAD : { type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -551,57 +550,57 @@ void verify_method(VerificationWrapper.MethodWrapper m) { } no_control_flow = false; break; } - case ClassFile.ISTORE : + case ISTORE : verify_istore(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.ISTORE_0 : - case ClassFile.ISTORE_1 : - case ClassFile.ISTORE_2 : - case ClassFile.ISTORE_3 : - index = opcode - ClassFile.ISTORE_0; + case ISTORE_0 : + case ISTORE_1 : + case ISTORE_2 : + case ISTORE_3 : + index = opcode - ISTORE_0; verify_istore(index, current_frame); no_control_flow = false; break; - case ClassFile.LSTORE : + case LSTORE : verify_lstore(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.LSTORE_0 : - case ClassFile.LSTORE_1 : - case ClassFile.LSTORE_2 : - case ClassFile.LSTORE_3 : - index = opcode - ClassFile.LSTORE_0; + case LSTORE_0 : + case LSTORE_1 : + case LSTORE_2 : + case LSTORE_3 : + index = opcode - LSTORE_0; verify_lstore(index, current_frame); no_control_flow = false; break; - case ClassFile.FSTORE : + case FSTORE : verify_fstore(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.FSTORE_0 : - case ClassFile.FSTORE_1 : - case ClassFile.FSTORE_2 : - case ClassFile.FSTORE_3 : - index = opcode - ClassFile.FSTORE_0; + case FSTORE_0 : + case FSTORE_1 : + case FSTORE_2 : + case FSTORE_3 : + index = opcode - FSTORE_0; verify_fstore(index, current_frame); no_control_flow = false; break; - case ClassFile.DSTORE : + case DSTORE : verify_dstore(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.DSTORE_0 : - case ClassFile.DSTORE_1 : - case ClassFile.DSTORE_2 : - case ClassFile.DSTORE_3 : - index = opcode - ClassFile.DSTORE_0; + case DSTORE_0 : + case DSTORE_1 : + case DSTORE_2 : + case DSTORE_3 : + index = opcode - DSTORE_0; verify_dstore(index, current_frame); no_control_flow = false; break; - case ClassFile.ASTORE : + case ASTORE : verify_astore(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.ASTORE_0 : - case ClassFile.ASTORE_1 : - case ClassFile.ASTORE_2 : - case ClassFile.ASTORE_3 : - index = opcode - ClassFile.ASTORE_0; + case ASTORE_0 : + case ASTORE_1 : + case ASTORE_2 : + case ASTORE_3 : + index = opcode - ASTORE_0; verify_astore(index, current_frame); no_control_flow = false; break; - case ClassFile.IASTORE : + case IASTORE : type = current_frame.pop_stack( VerificationType.integer_type); type2 = current_frame.pop_stack( @@ -612,7 +611,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.BASTORE : + case BASTORE : type = current_frame.pop_stack( VerificationType.integer_type); type2 = current_frame.pop_stack( @@ -623,7 +622,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.CASTORE : + case CASTORE : current_frame.pop_stack( VerificationType.integer_type); current_frame.pop_stack( @@ -634,7 +633,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.SASTORE : + case SASTORE : current_frame.pop_stack( VerificationType.integer_type); current_frame.pop_stack( @@ -645,7 +644,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.LASTORE : + case LASTORE : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); @@ -657,7 +656,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.FASTORE : + case FASTORE : current_frame.pop_stack( VerificationType.float_type); current_frame.pop_stack @@ -668,7 +667,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.DASTORE : + case DASTORE : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); @@ -680,7 +679,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.AASTORE : + case AASTORE : type = current_frame.pop_stack(object_type()); type2 = current_frame.pop_stack( VerificationType.integer_type); @@ -692,11 +691,11 @@ void verify_method(VerificationWrapper.MethodWrapper m) { } // 4938384: relaxed constraint in JVMS 3nd edition. no_control_flow = false; break; - case ClassFile.POP : + case POP : current_frame.pop_stack( VerificationType.category1_check); no_control_flow = false; break; - case ClassFile.POP2 : + case POP2 : type = current_frame.pop_stack(); if (type.is_category1(this)) { current_frame.pop_stack( @@ -708,13 +707,13 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.DUP : + case DUP : type = current_frame.pop_stack( VerificationType.category1_check); current_frame.push_stack(type); current_frame.push_stack(type); no_control_flow = false; break; - case ClassFile.DUP_X1 : + case DUP_X1 : type = current_frame.pop_stack( VerificationType.category1_check); type2 = current_frame.pop_stack( @@ -723,7 +722,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type2); current_frame.push_stack(type); no_control_flow = false; break; - case ClassFile.DUP_X2 : + case DUP_X2 : { VerificationType type3 = null; type = current_frame.pop_stack( @@ -744,7 +743,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type); no_control_flow = false; break; } - case ClassFile.DUP2 : + case DUP2 : type = current_frame.pop_stack(); if (type.is_category1(this)) { type2 = current_frame.pop_stack( @@ -760,7 +759,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type2); current_frame.push_stack(type); no_control_flow = false; break; - case ClassFile.DUP2_X1 : + case DUP2_X1 : { VerificationType type3; type = current_frame.pop_stack(); @@ -782,7 +781,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type); no_control_flow = false; break; } - case ClassFile.DUP2_X2 : + case DUP2_X2 : VerificationType type3, type4 = null; type = current_frame.pop_stack(); if (type.is_category1(this)) { @@ -811,7 +810,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type2); current_frame.push_stack(type); no_control_flow = false; break; - case ClassFile.SWAP : + case SWAP : type = current_frame.pop_stack( VerificationType.category1_check); type2 = current_frame.pop_stack( @@ -819,39 +818,39 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type); current_frame.push_stack(type2); no_control_flow = false; break; - case ClassFile.IADD : - case ClassFile.ISUB : - case ClassFile.IMUL : - case ClassFile.IDIV : - case ClassFile.IREM : - case ClassFile.ISHL : - case ClassFile.ISHR : - case ClassFile.IUSHR : - case ClassFile.IOR : - case ClassFile.IXOR : - case ClassFile.IAND : + case IADD : + case ISUB : + case IMUL : + case IDIV : + case IREM : + case ISHL : + case ISHR : + case IUSHR : + case IOR : + case IXOR : + case IAND : current_frame.pop_stack( VerificationType.integer_type); // fall through - case ClassFile.INEG : + case INEG : current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.LADD : - case ClassFile.LSUB : - case ClassFile.LMUL : - case ClassFile.LDIV : - case ClassFile.LREM : - case ClassFile.LAND : - case ClassFile.LOR : - case ClassFile.LXOR : + case LADD : + case LSUB : + case LMUL : + case LDIV : + case LREM : + case LAND : + case LOR : + case LXOR : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); // fall through - case ClassFile.LNEG : + case LNEG : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); @@ -859,9 +858,9 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.LSHL : - case ClassFile.LSHR : - case ClassFile.LUSHR : + case LSHL : + case LSHR : + case LUSHR : current_frame.pop_stack( VerificationType.integer_type); current_frame.pop_stack_2( @@ -871,30 +870,30 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.FADD : - case ClassFile.FSUB : - case ClassFile.FMUL : - case ClassFile.FDIV : - case ClassFile.FREM : + case FADD : + case FSUB : + case FMUL : + case FDIV : + case FREM : current_frame.pop_stack( VerificationType.float_type); // fall through - case ClassFile.FNEG : + case FNEG : current_frame.pop_stack( VerificationType.float_type); current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.DADD : - case ClassFile.DSUB : - case ClassFile.DMUL : - case ClassFile.DDIV : - case ClassFile.DREM : + case DADD : + case DSUB : + case DMUL : + case DDIV : + case DREM : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); // fall through - case ClassFile.DNEG : + case DNEG : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); @@ -902,44 +901,44 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.IINC : + case IINC : verify_iinc(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.I2L : + case I2L : type = current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack_2( VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.L2I : + case L2I : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.I2F : + case I2F : current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.I2D : + case I2D : current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack_2( VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.L2F : + case L2F : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.L2D : + case L2D : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); @@ -947,34 +946,34 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.F2I : + case F2I : current_frame.pop_stack( VerificationType.float_type); current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.F2L : + case F2L : current_frame.pop_stack( VerificationType.float_type); current_frame.push_stack_2( VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.F2D : + case F2D : current_frame.pop_stack( VerificationType.float_type); current_frame.push_stack_2( VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.D2I : + case D2I : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.D2L : + case D2L : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); @@ -982,22 +981,22 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.D2F : + case D2F : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.I2B : - case ClassFile.I2C : - case ClassFile.I2S : + case I2B : + case I2C : + case I2S : current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.LCMP : + case LCMP : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); @@ -1007,8 +1006,8 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.FCMPL : - case ClassFile.FCMPG : + case FCMPL : + case FCMPG : current_frame.pop_stack( VerificationType.float_type); current_frame.pop_stack( @@ -1016,8 +1015,8 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.DCMPL : - case ClassFile.DCMPG : + case DCMPL : + case DCMPG : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); @@ -1027,63 +1026,63 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.IF_ICMPEQ: - case ClassFile.IF_ICMPNE: - case ClassFile.IF_ICMPLT: - case ClassFile.IF_ICMPGE: - case ClassFile.IF_ICMPGT: - case ClassFile.IF_ICMPLE: + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: current_frame.pop_stack( VerificationType.integer_type); // fall through - case ClassFile.IFEQ: - case ClassFile.IFNE: - case ClassFile.IFLT: - case ClassFile.IFGE: - case ClassFile.IFGT: - case ClassFile.IFLE: + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: current_frame.pop_stack( VerificationType.integer_type); target = bcs.dest(); stackmap_table.check_jump_target( current_frame, target); no_control_flow = false; break; - case ClassFile.IF_ACMPEQ : - case ClassFile.IF_ACMPNE : + case IF_ACMPEQ : + case IF_ACMPNE : current_frame.pop_stack( VerificationType.reference_check); // fall through - case ClassFile.IFNULL : - case ClassFile.IFNONNULL : + case IFNULL : + case IFNONNULL : current_frame.pop_stack( VerificationType.reference_check); target = bcs.dest(); stackmap_table.check_jump_target (current_frame, target); no_control_flow = false; break; - case ClassFile.GOTO : + case GOTO : target = bcs.dest(); stackmap_table.check_jump_target( current_frame, target); no_control_flow = true; break; - case ClassFile.GOTO_W : + case GOTO_W : target = bcs.destW(); stackmap_table.check_jump_target( current_frame, target); no_control_flow = true; break; - case ClassFile.TABLESWITCH : - case ClassFile.LOOKUPSWITCH : + case TABLESWITCH : + case LOOKUPSWITCH : verify_switch( bcs, code_length, code_data, current_frame, stackmap_table); no_control_flow = true; break; - case ClassFile.IRETURN : + case IRETURN : type = current_frame.pop_stack( VerificationType.integer_type); verify_return_value(return_type, type, bci, current_frame); no_control_flow = true; break; - case ClassFile.LRETURN : + case LRETURN : type2 = current_frame.pop_stack( VerificationType.long2_type); type = current_frame.pop_stack( @@ -1091,13 +1090,13 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verify_return_value(return_type, type, bci, current_frame); no_control_flow = true; break; - case ClassFile.FRETURN : + case FRETURN : type = current_frame.pop_stack( VerificationType.float_type); verify_return_value(return_type, type, bci, current_frame); no_control_flow = true; break; - case ClassFile.DRETURN : + case DRETURN : type2 = current_frame.pop_stack( VerificationType.double2_type); type = current_frame.pop_stack( @@ -1105,13 +1104,13 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verify_return_value(return_type, type, bci, current_frame); no_control_flow = true; break; - case ClassFile.ARETURN : + case ARETURN : type = current_frame.pop_stack( VerificationType.reference_check); verify_return_value(return_type, type, bci, current_frame); no_control_flow = true; break; - case ClassFile.RETURN: + case RETURN: if (!return_type.is_bogus()) { verifyError("Method expects a return value"); } @@ -1120,24 +1119,24 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Constructor must call super() or this() before return"); } no_control_flow = true; break; - case ClassFile.GETSTATIC : - case ClassFile.PUTSTATIC : + case GETSTATIC : + case PUTSTATIC : verify_field_instructions(bcs, current_frame, cp, true); no_control_flow = false; break; - case ClassFile.GETFIELD : - case ClassFile.PUTFIELD : + case GETFIELD : + case PUTFIELD : verify_field_instructions(bcs, current_frame, cp, false); no_control_flow = false; break; - case ClassFile.INVOKEVIRTUAL : - case ClassFile.INVOKESPECIAL : - case ClassFile.INVOKESTATIC : + case INVOKEVIRTUAL : + case INVOKESPECIAL : + case INVOKESTATIC : this_uninit = verify_invoke_instructions(bcs, code_length, current_frame, (bci >= ex_minmax[0] && bci < ex_minmax[1]), this_uninit, return_type, cp, stackmap_table); no_control_flow = false; break; - case ClassFile.INVOKEINTERFACE : - case ClassFile.INVOKEDYNAMIC : + case INVOKEINTERFACE : + case INVOKEDYNAMIC : this_uninit = verify_invoke_instructions(bcs, code_length, current_frame, (bci >= ex_minmax[0] && bci < ex_minmax[1]), this_uninit, return_type, cp, stackmap_table); no_control_flow = false; break; - case ClassFile.NEW : + case NEW : { index = bcs.getIndexU2(); verify_cp_class_type(bci, index, cp); @@ -1150,16 +1149,16 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type); no_control_flow = false; break; } - case ClassFile.NEWARRAY : + case NEWARRAY : type = get_newarray_type(bcs.getIndex(), bci); current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack(type); no_control_flow = false; break; - case ClassFile.ANEWARRAY : + case ANEWARRAY : verify_anewarray(bci, bcs.getIndexU2(), cp, current_frame); no_control_flow = false; break; - case ClassFile.ARRAYLENGTH : + case ARRAYLENGTH : type = current_frame.pop_stack( VerificationType.reference_check); if (!(type.is_null() || type.is_array())) { @@ -1168,7 +1167,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.CHECKCAST : + case CHECKCAST : { index = bcs.getIndexU2(); verify_cp_class_type(bci, index, cp); @@ -1178,7 +1177,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(klass_type); no_control_flow = false; break; } - case ClassFile.INSTANCEOF : { + case INSTANCEOF : { index = bcs.getIndexU2(); verify_cp_class_type(bci, index, cp); current_frame.pop_stack(object_type()); @@ -1186,12 +1185,12 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.integer_type); no_control_flow = false; break; } - case ClassFile.MONITORENTER : - case ClassFile.MONITOREXIT : + case MONITORENTER : + case MONITOREXIT : current_frame.pop_stack( VerificationType.reference_check); no_control_flow = false; break; - case ClassFile.MULTIANEWARRAY : + case MULTIANEWARRAY : { index = bcs.getIndexU2(); int dim = _method.codeArray()[bcs.bci() +3] & 0xff; @@ -1211,7 +1210,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(new_array_type); no_control_flow = false; break; } - case ClassFile.ATHROW : + case ATHROW : type = VerificationType.reference_type(java_lang_Throwable); current_frame.pop_stack(type); no_control_flow = true; break; @@ -1235,7 +1234,7 @@ private byte[] generate_code_data(RawBytecodeHelper.CodeRange code) { while (bcs.next()) { if (bcs.opcode() != ILLEGAL) { int bci = bcs.bci(); - if (bcs.opcode() == ClassFile.NEW) { + if (bcs.opcode() == NEW) { code_data[bci] = NEW_OFFSET; } else { code_data[bci] = BYTECODE_OFFSET; @@ -1368,14 +1367,14 @@ void verify_ldc(int opcode, int index, VerificationFrame current_frame, Constant verify_cp_index(bci, cp, index); int tag = cp.tagAt(index); int types = 0; - if (opcode == ClassFile.LDC || opcode == ClassFile.LDC_W) { + if (opcode == LDC || opcode == LDC_W) { types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float) | (1 << JVM_CONSTANT_String) | (1 << JVM_CONSTANT_Class) | (1 << JVM_CONSTANT_MethodHandle) | (1 << JVM_CONSTANT_MethodType) | (1 << JVM_CONSTANT_Dynamic); verify_cp_type(bci, index, cp, types); } else { - if (opcode != ClassFile.LDC2_W) verifyError("must be ldc2_w"); + if (opcode != LDC2_W) verifyError("must be ldc2_w"); types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long) | (1 << JVM_CONSTANT_Dynamic); verify_cp_type(bci, index, cp, types); } @@ -1395,7 +1394,7 @@ void verify_ldc(int opcode, int index, VerificationFrame current_frame, Constant VerificationType[] v_constant_type = new VerificationType[2]; var sig_stream = new VerificationSignature(constant_type, false, this); int n = change_sig_to_verificationType(sig_stream, v_constant_type, 0); - int opcode_n = (opcode == ClassFile.LDC2_W ? 2 : 1); + int opcode_n = (opcode == LDC2_W ? 2 : 1); if (n != opcode_n) { types &= ~(1 << JVM_CONSTANT_Dynamic); verify_cp_type(bci, index, cp, types); @@ -1424,7 +1423,7 @@ void verify_switch(RawBytecodeHelper bcs, int code_length, byte[] code_data, Ver int default_offset = bcs.getIntUnchecked(aligned_bci); int keys, delta; current_frame.pop_stack(VerificationType.integer_type); - if (bcs.opcode() == ClassFile.TABLESWITCH) { + if (bcs.opcode() == TABLESWITCH) { int low = bcs.getIntUnchecked(aligned_bci + 4); int high = bcs.getIntUnchecked(aligned_bci + 2*4); if (low > high) { @@ -1477,24 +1476,24 @@ void verify_field_instructions(RawBytecodeHelper bcs, VerificationFrame current_ int n = change_sig_to_verificationType(sig_stream, field_type, 0); boolean is_assignable; switch (bcs.opcode()) { - case ClassFile.GETSTATIC -> { + case GETSTATIC -> { for (int i = 0; i < n; i++) { current_frame.push_stack(field_type[i]); } } - case ClassFile.PUTSTATIC -> { + case PUTSTATIC -> { for (int i = n - 1; i >= 0; i--) { current_frame.pop_stack(field_type[i]); } } - case ClassFile.GETFIELD -> { + case GETFIELD -> { stack_object_type = current_frame.pop_stack( target_class_type); for (int i = 0; i < n; i++) { current_frame.push_stack(field_type[i]); } } - case ClassFile.PUTFIELD -> { + case PUTFIELD -> { for (int i = n - 1; i >= 0; i--) { current_frame.pop_stack(field_type[i]); } @@ -1548,7 +1547,7 @@ boolean verify_invoke_init(RawBytecodeHelper bcs, int ref_class_index, Verificat this_uninit = true; } else if (type.is_uninitialized()) { int new_offset = type.bci(this); - if (new_offset > (code_length - 3) || (_method.codeArray()[new_offset] & 0xff) != ClassFile.NEW) { + if (new_offset > (code_length - 3) || (_method.codeArray()[new_offset] & 0xff) != NEW) { verifyError("Expecting new instruction"); } int new_class_index = bcs.getU2(new_offset + 1); @@ -1585,14 +1584,14 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif int opcode = bcs.opcode(); int types = 0; switch (opcode) { - case ClassFile.INVOKEINTERFACE: + case INVOKEINTERFACE: types = 1 << JVM_CONSTANT_InterfaceMethodref; break; - case ClassFile.INVOKEDYNAMIC: + case INVOKEDYNAMIC: types = 1 << JVM_CONSTANT_InvokeDynamic; break; - case ClassFile.INVOKESPECIAL: - case ClassFile.INVOKESTATIC: + case INVOKESPECIAL: + case INVOKESTATIC: types = (_klass.majorVersion() < STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION) ? (1 << JVM_CONSTANT_Methodref) : ((1 << JVM_CONSTANT_InterfaceMethodref) | (1 << JVM_CONSTANT_Methodref)); @@ -1605,7 +1604,7 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif String method_sig = cp.refSignatureAt(index); if (!VerificationSignature.isValidMethodSignature(method_sig)) verifyError("Invalid method signature"); VerificationType ref_class_type = null; - if (opcode == ClassFile.INVOKEDYNAMIC) { + if (opcode == INVOKEDYNAMIC) { if (_klass.majorVersion() < INVOKEDYNAMIC_MAJOR_VERSION) { classError(String.format("invokedynamic instructions not supported by this class file version (%d), class %s", _klass.majorVersion(), _klass.thisClassName())); } @@ -1619,7 +1618,7 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif create_method_sig_entry(mth_sig_verif_types, sig); int nargs = mth_sig_verif_types.num_args(); int bci = bcs.bci(); - if (opcode == ClassFile.INVOKEINTERFACE) { + if (opcode == INVOKEINTERFACE) { if ((_method.codeArray()[bci+3] & 0xff) != (nargs+1)) { verifyError("Inconsistent args count operand in invokeinterface"); } @@ -1627,17 +1626,17 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif verifyError("Fourth operand byte of invokeinterface must be zero"); } } - if (opcode == ClassFile.INVOKEDYNAMIC) { + if (opcode == INVOKEDYNAMIC) { if ((_method.codeArray()[bci+3] & 0xff) != 0 || (_method.codeArray()[bci+4] & 0xff) != 0) { verifyError("Third and fourth operand bytes of invokedynamic must be zero"); } } if (method_name.charAt(0) == JVM_SIGNATURE_SPECIAL) { - if (opcode != ClassFile.INVOKESPECIAL || + if (opcode != INVOKESPECIAL || !object_initializer_name.equals(method_name)) { verifyError("Illegal call to internal method"); } - } else if (opcode == ClassFile.INVOKESPECIAL + } else if (opcode == INVOKESPECIAL && !is_same_or_direct_interface(current_class(), current_type(), ref_class_type) && !ref_class_type.equals(VerificationType.reference_type( current_class().superclassName()))) { @@ -1655,16 +1654,16 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif for (int i = nargs - 1; i >= 0; i--) { // Run backwards current_frame.pop_stack(sig_verif_types.get(i)); } - if (opcode != ClassFile.INVOKESTATIC && - opcode != ClassFile.INVOKEDYNAMIC) { + if (opcode != INVOKESTATIC && + opcode != INVOKEDYNAMIC) { if (object_initializer_name.equals(method_name)) { // method this_uninit = verify_invoke_init(bcs, index, ref_class_type, current_frame, code_length, in_try_block, this_uninit, cp, stackmap_table); } else { switch (opcode) { - case ClassFile.INVOKESPECIAL -> + case INVOKESPECIAL -> current_frame.pop_stack(current_type()); - case ClassFile.INVOKEVIRTUAL -> { + case INVOKEVIRTUAL -> { VerificationType stack_object_type = current_frame.pop_stack(ref_class_type); if (current_type() != stack_object_type) { @@ -1672,7 +1671,7 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif } } default -> { - if (opcode != ClassFile.INVOKEINTERFACE) + if (opcode != INVOKEINTERFACE) verifyError("Unexpected opcode encountered"); current_frame.pop_stack(ref_class_type); } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java index 3b9336c499d9c..cccbaf14f5399 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java @@ -35,6 +35,7 @@ import java.lang.classfile.attribute.*; import static java.lang.classfile.ClassFile.*; import static java.lang.classfile.attribute.StackMapFrameInfo.*; +import static java.lang.classfile.instruction.CharacterRange.*; /* * A writer for writing Attributes as text. @@ -144,23 +145,23 @@ public void write(Attribute a, CodeAttribute lr) { (e.characterRangeStart() & 0x3ff), (e.characterRangeEnd() >> 10), (e.characterRangeEnd() & 0x3ff))); - if ((e.flags() & CRT_STATEMENT) != 0) + if ((e.flags() & FLAG_STATEMENT) != 0) print(", statement"); - if ((e.flags() & CRT_BLOCK) != 0) + if ((e.flags() & FLAG_BLOCK) != 0) print(", block"); - if ((e.flags() & CRT_ASSIGNMENT) != 0) + if ((e.flags() & FLAG_ASSIGNMENT) != 0) print(", assignment"); - if ((e.flags() & CRT_FLOW_CONTROLLER) != 0) + if ((e.flags() & FLAG_FLOW_CONTROLLER) != 0) print(", flow-controller"); - if ((e.flags() & CRT_FLOW_TARGET) != 0) + if ((e.flags() & FLAG_FLOW_TARGET) != 0) print(", flow-target"); - if ((e.flags() & CRT_INVOKE) != 0) + if ((e.flags() & FLAG_INVOKE) != 0) print(", invoke"); - if ((e.flags() & CRT_CREATE) != 0) + if ((e.flags() & FLAG_CREATE) != 0) print(", create"); - if ((e.flags() & CRT_BRANCH_TRUE) != 0) + if ((e.flags() & FLAG_BRANCH_TRUE) != 0) print(", branch-true"); - if ((e.flags() & CRT_BRANCH_FALSE) != 0) + if ((e.flags() & FLAG_BRANCH_FALSE) != 0) print(", branch-false"); println(); } @@ -705,13 +706,13 @@ void printMap(String name, List map, CodeAttribute lr) { String mapTypeName(SimpleVerificationTypeInfo type) { return switch (type) { - case ITEM_TOP -> "top"; - case ITEM_INTEGER -> "int"; - case ITEM_FLOAT -> "float"; - case ITEM_LONG -> "long"; - case ITEM_DOUBLE -> "double"; - case ITEM_NULL -> "null"; - case ITEM_UNINITIALIZED_THIS -> "this"; + case TOP -> "top"; + case INTEGER -> "int"; + case FLOAT -> "float"; + case LONG -> "long"; + case DOUBLE -> "double"; + case NULL -> "null"; + case UNINITIALIZED_THIS -> "this"; }; } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java index 764f93bd54aeb..77fbce8839e72 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java @@ -741,7 +741,7 @@ static String getJavaName(String name) { */ String getConstantValue(ClassDesc d, ConstantValueEntry cpInfo) { switch (cpInfo.tag()) { - case ClassFile.TAG_INTEGER: { + case PoolEntry.TAG_INTEGER: { var val = (Integer)cpInfo.constantValue(); switch (d.descriptorString()) { case "C": @@ -755,7 +755,7 @@ String getConstantValue(ClassDesc d, ConstantValueEntry cpInfo) { return String.valueOf(val); } } - case ClassFile.TAG_STRING: + case PoolEntry.TAG_STRING: return getConstantStringValue(cpInfo.constantValue().toString()); default: return constantWriter.stringValue(cpInfo); diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ConstantWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ConstantWriter.java index c649ce982969e..b3c6b5b6c640d 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ConstantWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ConstantWriter.java @@ -26,7 +26,8 @@ package com.sun.tools.javap; import java.lang.classfile.constantpool.*; -import static java.lang.classfile.ClassFile.*; + +import static java.lang.classfile.constantpool.PoolEntry.*; /* * Write a constant pool entry. @@ -156,13 +157,13 @@ String cpTagName(int tag) { case TAG_CLASS -> "Class"; case TAG_STRING -> "String"; case TAG_FIELDREF -> "Fieldref"; - case TAG_METHODHANDLE -> "MethodHandle"; - case TAG_METHODTYPE -> "MethodType"; + case TAG_METHOD_HANDLE -> "MethodHandle"; + case TAG_METHOD_TYPE -> "MethodType"; case TAG_METHODREF -> "Methodref"; - case TAG_INTERFACEMETHODREF -> "InterfaceMethodref"; - case TAG_INVOKEDYNAMIC -> "InvokeDynamic"; - case TAG_CONSTANTDYNAMIC -> "Dynamic"; - case TAG_NAMEANDTYPE -> "NameAndType"; + case TAG_INTERFACE_METHODREF -> "InterfaceMethodref"; + case TAG_INVOKE_DYNAMIC -> "InvokeDynamic"; + case TAG_DYNAMIC -> "Dynamic"; + case TAG_NAME_AND_TYPE -> "NameAndType"; default -> "Unknown"; }; } @@ -177,13 +178,13 @@ String tagName(int tag) { case TAG_CLASS -> "class"; case TAG_STRING -> "String"; case TAG_FIELDREF -> "Field"; - case TAG_METHODHANDLE -> "MethodHandle"; - case TAG_METHODTYPE -> "MethodType"; + case TAG_METHOD_HANDLE -> "MethodHandle"; + case TAG_METHOD_TYPE -> "MethodType"; case TAG_METHODREF -> "Method"; - case TAG_INTERFACEMETHODREF -> "InterfaceMethod"; - case TAG_INVOKEDYNAMIC -> "InvokeDynamic"; - case TAG_CONSTANTDYNAMIC -> "Dynamic"; - case TAG_NAMEANDTYPE -> "NameAndType"; + case TAG_INTERFACE_METHODREF -> "InterfaceMethod"; + case TAG_INVOKE_DYNAMIC -> "InvokeDynamic"; + case TAG_DYNAMIC -> "Dynamic"; + case TAG_NAME_AND_TYPE -> "NameAndType"; default -> "(unknown tag " + tag + ")"; }; } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java index a1d939bcc4f23..d899569724e66 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java @@ -122,25 +122,25 @@ void print(StackMapFrameInfo.VerificationTypeInfo entry, boolean firstThis) { switch (entry) { case StackMapFrameInfo.SimpleVerificationTypeInfo s -> { switch (s) { - case ITEM_TOP -> + case TOP -> print("top"); - case ITEM_INTEGER -> + case INTEGER -> print("int"); - case ITEM_FLOAT -> + case FLOAT -> print("float"); - case ITEM_LONG -> + case LONG -> print("long"); - case ITEM_DOUBLE -> + case DOUBLE -> print("double"); - case ITEM_NULL -> + case NULL -> print("null"); - case ITEM_UNINITIALIZED_THIS -> + case UNINITIALIZED_THIS -> print("uninit_this"); } } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java index 4edc90a97b7be..9b9e7ad1ce893 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java @@ -33,6 +33,8 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; + +import static java.lang.classfile.constantpool.PoolEntry.*; import static java.util.ResourceBundle.Control; import java.util.Set; import java.util.function.IntUnaryOperator; @@ -41,7 +43,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import static java.lang.classfile.ClassFile.*; + import jdk.tools.jlink.internal.ResourcePrevisitor; import jdk.tools.jlink.internal.StringTable; import jdk.tools.jlink.plugin.ResourcePoolModule; @@ -300,18 +302,18 @@ private boolean stripUnsupportedLocales(byte[] bytes) { } case TAG_CLASS, TAG_STRING, - TAG_METHODTYPE, + TAG_METHOD_TYPE, TAG_MODULE, TAG_PACKAGE -> offset += 3; - case TAG_METHODHANDLE -> offset += 4; + case TAG_METHOD_HANDLE -> offset += 4; case TAG_INTEGER, TAG_FLOAT, TAG_FIELDREF, TAG_METHODREF, - TAG_INTERFACEMETHODREF, - TAG_NAMEANDTYPE, - TAG_CONSTANTDYNAMIC, - TAG_INVOKEDYNAMIC -> offset += 5; + TAG_INTERFACE_METHODREF, + TAG_NAME_AND_TYPE, + TAG_DYNAMIC, + TAG_INVOKE_DYNAMIC -> offset += 5; case TAG_LONG, TAG_DOUBLE -> {offset += 9; cpSlot++;} //additional slot for double and long entries default -> throw new IllegalArgumentException("Unknown constant pool entry: 0x" diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java index 6f8bc9b7779bf..71c509e7deafd 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java @@ -51,6 +51,8 @@ import jdk.tools.jlink.internal.ResourcePrevisitor; import jdk.tools.jlink.internal.StringTable; +import static java.lang.classfile.constantpool.PoolEntry.*; + /** * * A Plugin that stores the image classes constant pool UTF_8 entries into the @@ -214,7 +216,7 @@ private byte[] optimize(ResourcePoolEntry resource, ResourcePoolBuilder resource int tag = stream.readUnsignedByte(); byte[] arr; switch (tag) { - case ClassFile.TAG_UTF8: { + case TAG_UTF8: { String original = stream.readUTF(); // 2 cases, a Descriptor or a simple String if (descriptorIndexes.contains(i)) { @@ -238,8 +240,8 @@ private byte[] optimize(ResourcePoolEntry resource, ResourcePoolBuilder resource break; } - case ClassFile.TAG_LONG: - case ClassFile.TAG_DOUBLE: + case TAG_LONG: + case TAG_DOUBLE: i++; default: { out.write(tag); diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index 9c7b8d9e72d4a..a1899ac1c842b 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -28,6 +28,7 @@ * @run junit LimitsTest */ import java.lang.classfile.Attributes; +import java.lang.classfile.constantpool.PoolEntry; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; @@ -36,12 +37,10 @@ import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.attribute.LineNumberInfo; import java.lang.classfile.attribute.LineNumberTableAttribute; -import java.lang.classfile.attribute.LocalVariableInfo; import java.lang.classfile.attribute.LocalVariableTableAttribute; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.ConstantPoolException; import java.lang.classfile.constantpool.IntegerEntry; -import java.lang.classfile.instruction.LocalVariable; import java.util.List; import jdk.internal.classfile.impl.BufWriterImpl; @@ -113,13 +112,13 @@ void testReadingOutOfBounds() { @Test void testInvalidClassEntry() { assertThrows(ConstantPoolException.class, () -> ClassFile.of().parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, - 0, 0, 0, 0, 0, 2, ClassFile.TAG_METHODREF, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}).thisClass()); + 0, 0, 0, 0, 0, 2, PoolEntry.TAG_METHODREF, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}).thisClass()); } @Test void testInvalidUtf8Entry() { var cp = ClassFile.of().parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, - 0, 0, 0, 0, 0, 3, ClassFile.TAG_INTEGER, 0, 0, 0, 0, ClassFile.TAG_NAMEANDTYPE, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}).constantPool(); + 0, 0, 0, 0, 0, 3, PoolEntry.TAG_INTEGER, 0, 0, 0, 0, PoolEntry.TAG_NAME_AND_TYPE, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}).constantPool(); assertTrue(cp.entryByIndex(1) instanceof IntegerEntry); //parse valid int entry first assertThrows(ConstantPoolException.class, () -> cp.entryByIndex(2)); } diff --git a/test/jdk/jdk/classfile/StackMapsTest.java b/test/jdk/jdk/classfile/StackMapsTest.java index 09be56f0de2a1..1ccd7255ed4b9 100644 --- a/test/jdk/jdk/classfile/StackMapsTest.java +++ b/test/jdk/jdk/classfile/StackMapsTest.java @@ -385,9 +385,9 @@ void testDeadCodeCountersWithCustomSMTA() { StackMapTableAttribute.of(List.of( StackMapFrameInfo.of(f2, List.of(), - List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.ITEM_LONG)), + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.LONG)), StackMapFrameInfo.of(f3, - List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.ITEM_LONG), + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.LONG), List.of())))); } )); diff --git a/test/jdk/jdk/classfile/VerifierSelfTest.java b/test/jdk/jdk/classfile/VerifierSelfTest.java index d0943d2eee9f5..b6a2f08c9ecd7 100644 --- a/test/jdk/jdk/classfile/VerifierSelfTest.java +++ b/test/jdk/jdk/classfile/VerifierSelfTest.java @@ -29,6 +29,7 @@ * @run junit VerifierSelfTest */ import java.io.IOException; +import java.lang.classfile.constantpool.PoolEntry; import java.lang.constant.ClassDesc; import static java.lang.constant.ConstantDescs.*; import java.lang.invoke.MethodHandleInfo; @@ -116,7 +117,7 @@ public void writeBody(BufWriterImpl b) { void testInvalidClassNameEntry() { var cc = ClassFile.of(); var bytes = cc.parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, - 0, 0, 0, 0, 0, 2, ClassFile.TAG_INTEGER, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + 0, 0, 0, 0, 0, 2, PoolEntry.TAG_INTEGER, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); assertTrue(cc.verify(bytes).stream().anyMatch(e -> e.getMessage().contains("expected ClassEntry"))); } diff --git a/test/jdk/jdk/classfile/helpers/ClassRecord.java b/test/jdk/jdk/classfile/helpers/ClassRecord.java index 329e41fa0f484..e7a239015f605 100644 --- a/test/jdk/jdk/classfile/helpers/ClassRecord.java +++ b/test/jdk/jdk/classfile/helpers/ClassRecord.java @@ -22,21 +22,13 @@ */ package helpers; -import java.io.IOException; -import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.RecordComponent; import java.math.BigInteger; import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; import java.util.function.Function; @@ -53,9 +45,10 @@ import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toSet; -import static java.lang.classfile.ClassFile.*; import static java.lang.classfile.Attributes.*; +import static java.lang.classfile.constantpool.PoolEntry.*; import static helpers.ClassRecord.CompatibilityFilter.By_ClassBuilder; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; /** * ClassRecord @@ -916,17 +909,17 @@ public static ConstantPoolEntryRecord ofCPEntry(PoolEntry cpInfo) { CpFieldRefRecord.ofFieldRefEntry((FieldRefEntry) cpInfo); case TAG_METHODREF -> CpMethodRefRecord.ofMethodRefEntry((MethodRefEntry) cpInfo); - case TAG_INTERFACEMETHODREF -> + case TAG_INTERFACE_METHODREF -> CpInterfaceMethodRefRecord.ofInterfaceMethodRefEntry((InterfaceMethodRefEntry) cpInfo); - case TAG_NAMEANDTYPE -> + case TAG_NAME_AND_TYPE -> CpNameAndTypeRecord.ofNameAndTypeEntry((NameAndTypeEntry) cpInfo); - case TAG_METHODHANDLE -> + case TAG_METHOD_HANDLE -> CpMethodHandleRecord.ofMethodHandleEntry((MethodHandleEntry) cpInfo); - case TAG_METHODTYPE -> + case TAG_METHOD_TYPE -> new CpMethodTypeRecord(((MethodTypeEntry) cpInfo).descriptor().stringValue()); - case TAG_CONSTANTDYNAMIC -> + case TAG_DYNAMIC -> CpConstantDynamicRecord.ofConstantDynamicEntry((ConstantDynamicEntry) cpInfo); - case TAG_INVOKEDYNAMIC -> + case TAG_INVOKE_DYNAMIC -> CpInvokeDynamicRecord.ofInvokeDynamicEntry((InvokeDynamicEntry) cpInfo); case TAG_MODULE -> new CpModuleRecord(((ModuleEntry) cpInfo).name().stringValue()); From 10da2c21a19affe93a3f5d67a70db5d9cd37181c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Thu, 26 Sep 2024 08:47:32 +0000 Subject: [PATCH 016/188] 8340923: The class LogSelection copies uninitialized memory Reviewed-by: mbaesken, jwaters, stefank --- src/hotspot/share/logging/logSelection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/logging/logSelection.cpp b/src/hotspot/share/logging/logSelection.cpp index aea5719b36d4f..1e7ba3a887848 100644 --- a/src/hotspot/share/logging/logSelection.cpp +++ b/src/hotspot/share/logging/logSelection.cpp @@ -33,11 +33,11 @@ const LogSelection LogSelection::Invalid; -LogSelection::LogSelection() : _ntags(0), _wildcard(false), _level(LogLevel::Invalid), _tag_sets_selected(0) { +LogSelection::LogSelection() : _ntags(0), _tags(), _wildcard(false), _level(LogLevel::Invalid), _tag_sets_selected(0) { } LogSelection::LogSelection(const LogTagType tags[LogTag::MaxTags], bool wildcard, LogLevelType level) - : _ntags(0), _wildcard(wildcard), _level(level), _tag_sets_selected(0) { + : _ntags(0), _tags(), _wildcard(wildcard), _level(level), _tag_sets_selected(0) { while (_ntags < LogTag::MaxTags && tags[_ntags] != LogTag::__NO_TAG) { _tags[_ntags] = tags[_ntags]; _ntags++; From e2626db2f00d0cc9f3ff8ea374a1ccc89373e398 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 26 Sep 2024 11:34:30 +0000 Subject: [PATCH 017/188] 8340899: Remove wildcard bound in PositionWindows.positionTestWindows Reviewed-by: azvegint, prr --- test/jdk/java/awt/regtesthelpers/PassFailJFrame.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 3a142c716b199..a6c11ad5f5df1 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -587,7 +587,7 @@ public interface PositionWindows { * @param testWindows the list of test windows * @param instructionUI information about the instruction frame */ - void positionTestWindows(List testWindows, + void positionTestWindows(List testWindows, InstructionUI instructionUI); } From 3762ec3978bfe9910929ab22aaf238e9f4c84630 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 26 Sep 2024 11:36:42 +0000 Subject: [PATCH 018/188] 8340466: Add description for PassFailJFrame constructors Reviewed-by: prr, honkar --- .../awt/regtesthelpers/PassFailJFrame.java | 196 +++++++++++++----- 1 file changed, 139 insertions(+), 57 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index a6c11ad5f5df1..45cd191ae39db 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -213,90 +213,172 @@ public final class PassFailJFrame { public enum Position {HORIZONTAL, VERTICAL, TOP_LEFT_CORNER} - public PassFailJFrame(String instructions) throws InterruptedException, - InvocationTargetException { + /** + * Constructs a frame which displays test instructions and + * the Pass / Fail buttons with the given instructions, and + * the default timeout of {@value #TEST_TIMEOUT} minutes, + * the default title of {@value #TITLE} and + * the default values of {@value #ROWS} and {@value #COLUMNS} + * for rows and columns. + *

    + * See {@link #PassFailJFrame(String,String,long,int,int,boolean)} for + * more details. + * + * @param instructions the instructions for the tester + * + * @throws InterruptedException if the current thread is interrupted + * while waiting for EDT to finish creating UI components + * @throws InvocationTargetException if an exception is thrown while + * creating UI components on EDT + */ + public PassFailJFrame(String instructions) + throws InterruptedException, InvocationTargetException { this(instructions, TEST_TIMEOUT); } - public PassFailJFrame(String instructions, long testTimeOut) throws - InterruptedException, InvocationTargetException { + /** + * Constructs a frame which displays test instructions and + * the Pass / Fail buttons + * with the given instructions and timeout as well as + * the default title of {@value #TITLE} + * and the default values of {@value #ROWS} and {@value #COLUMNS} + * for rows and columns. + *

    + * See {@link #PassFailJFrame(String,String,long,int,int,boolean)} for + * more details. + * + * @param instructions the instructions for the tester + * @param testTimeOut the test timeout in minutes + * + * @throws InterruptedException if the current thread is interrupted + * while waiting for EDT to finish creating UI components + * @throws InvocationTargetException if an exception is thrown while + * creating UI components on EDT + */ + public PassFailJFrame(String instructions, long testTimeOut) + throws InterruptedException, InvocationTargetException { this(TITLE, instructions, testTimeOut); } + /** + * Constructs a frame which displays test instructions and + * the Pass / Fail buttons + * with the given title, instructions and timeout as well as + * the default values of {@value #ROWS} and {@value #COLUMNS} + * for rows and columns. + * The screenshot feature is not enabled, if you use this constructor. + *

    + * See {@link #PassFailJFrame(String,String,long,int,int,boolean)} for + * more details. + * + * @param title the title of the instruction frame + * @param instructions the instructions for the tester + * @param testTimeOut the test timeout in minutes + * + * @throws InterruptedException if the current thread is interrupted + * while waiting for EDT to finish creating UI components + * @throws InvocationTargetException if an exception is thrown while + * creating UI components on EDT + */ public PassFailJFrame(String title, String instructions, - long testTimeOut) throws InterruptedException, - InvocationTargetException { + long testTimeOut) + throws InterruptedException, InvocationTargetException { this(title, instructions, testTimeOut, ROWS, COLUMNS); } /** - * Constructs a JFrame with a given title & serves as test instructional - * frame where the user follows the specified test instruction in order - * to test the test case & mark the test pass or fail. If the expected - * result is seen then the user click on the 'Pass' button else click - * on the 'Fail' button and the reason for the failure should be - * specified in the JDialog JTextArea. + * Constructs a frame which displays test instructions and + * the Pass / Fail buttons + * with the given title, instructions, timeout, number of rows and columns. + * The screenshot feature is not enabled, if you use this constructor. + *

    + * See {@link #PassFailJFrame(String,String,long,int,int,boolean)} for + * more details. * - * @param title title of the Frame. - * @param instructions the instruction for the tester on how to test - * and what is expected (pass) and what is not - * expected (fail). - * @param testTimeOut test timeout where time is specified in minutes. - * @param rows number of visible rows of the JTextArea where the - * instruction is show. - * @param columns Number of columns of the instructional - * JTextArea - * @throws InterruptedException exception thrown when thread is - * interrupted + * @param title the title of the instruction frame + * @param instructions the instructions for the tester + * @param testTimeOut the test timeout in minutes + * @param rows the number of rows for the text component + * which displays test instructions + * @param columns the number of columns for the text component + * which displays test instructions + * + * @throws InterruptedException if the current thread is interrupted + * while waiting for EDT to finish creating UI components * @throws InvocationTargetException if an exception is thrown while - * creating the test instruction frame on - * EDT + * creating UI components on EDT */ - public PassFailJFrame(String title, String instructions, long testTimeOut, - int rows, int columns) throws InterruptedException, - InvocationTargetException { + public PassFailJFrame(String title, String instructions, + long testTimeOut, + int rows, int columns) + throws InterruptedException, InvocationTargetException { this(title, instructions, testTimeOut, rows, columns, false); } /** - * Constructs a JFrame with a given title & serves as test instructional - * frame where the user follows the specified test instruction in order - * to test the test case & mark the test pass or fail. If the expected - * result is seen then the user click on the 'Pass' button else click - * on the 'Fail' button and the reason for the failure should be - * specified in the JDialog JTextArea. + * Constructs a frame which displays test instructions and + * the Pass / Fail buttons + * as well as supporting UI components with the given title, instructions, + * timeout, number of rows and columns, + * and screen capture functionality. + * All the UI components are created on the EDT, so it is safe to call + * the constructor on the main thread. *

    - * The test instruction frame also provides a way for the tester to take - * a screenshot (full screen or individual frame) if this feature - * is enabled by passing {@code true} as {@code enableScreenCapture} - * parameter. + * After you create a test UI window, register the window using + * {@link #addTestWindow(Window) addTestWindow} for disposal, and + * position it close to the instruction frame using + * {@link #positionTestWindow(Window, Position) positionTestWindow}. + * As the last step, make your test UI window visible. + *

    + * Call the {@link #awaitAndCheck() awaitAndCheck} method on the instance + * of {@code PassFailJFrame} when you set up the testing environment. + *

    + * If the tester clicks the Fail button, a dialog prompting for + * a description of the problem is displayed, and then an exception + * is thrown which fails the test. + * If the tester clicks the Pass button, the test completes + * successfully. + * If the timeout occurs or the instruction frame is closed, + * the test fails. + *

    + * The {@code rows} and {@code columns} parameters control + * the size of a text component which displays the instructions. + * The preferred size of the instructions is calculated by + * creating {@code new JTextArea(rows, columns)}. + *

    + * If you enable screenshots by setting the {@code screenCapture} + * parameter to {@code true}, a Screenshot button is added. + * Clicking the Screenshot button takes screenshots of + * all the monitors or all the windows registered with + * {@code PassFailJFrame}. * - * @param title title of the Frame. - * @param instructions the instruction for the tester on how to test - * and what is expected (pass) and what is not - * expected (fail). - * @param testTimeOut test timeout where time is specified in minutes. - * @param rows number of visible rows of the JTextArea where the - * instruction is show. - * @param columns Number of columns of the instructional - * JTextArea - * @param enableScreenCapture if set to true, 'Capture Screen' button & its - * associated UIs are added to test instruction - * frame - * @throws InterruptedException exception thrown when thread is - * interrupted + * @param title the title of the instruction frame + * @param instructions the instructions for the tester + * @param testTimeOut the test timeout in minutes + * @param rows the number of rows for the text component + * which displays test instructions + * @param columns the number of columns for the text component + * which displays test instructions + * @param screenCapture if set to {@code true}, enables screen capture + * functionality + * + * @throws InterruptedException if the current thread is interrupted + * while waiting for EDT to finish creating UI components * @throws InvocationTargetException if an exception is thrown while - * creating the test instruction frame on - * EDT + * creating UI components on EDT + * + * @see JTextArea#JTextArea(int,int) JTextArea(int rows, int columns) + * @see Builder Builder */ - public PassFailJFrame(String title, String instructions, long testTimeOut, + public PassFailJFrame(String title, String instructions, + long testTimeOut, int rows, int columns, - boolean enableScreenCapture) + boolean screenCapture) throws InterruptedException, InvocationTargetException { invokeOnEDT(() -> createUI(title, instructions, testTimeOut, rows, columns, - enableScreenCapture)); + screenCapture)); } /** From 777c20cb14010b6726834246ae4c61bc4ccb3f9b Mon Sep 17 00:00:00 2001 From: Lutz Schmidt Date: Thu, 26 Sep 2024 11:45:09 +0000 Subject: [PATCH 019/188] 8339542: compiler/codecache/CheckSegmentedCodeCache.java fails Reviewed-by: mdoerr, shade --- .../jtreg/compiler/codecache/CheckSegmentedCodeCache.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/codecache/CheckSegmentedCodeCache.java b/test/hotspot/jtreg/compiler/codecache/CheckSegmentedCodeCache.java index d0b45333fb8b3..ecdb415843bf0 100644 --- a/test/hotspot/jtreg/compiler/codecache/CheckSegmentedCodeCache.java +++ b/test/hotspot/jtreg/compiler/codecache/CheckSegmentedCodeCache.java @@ -179,7 +179,9 @@ public static void main(String[] args) throws Exception { // Fails if code heap sizes do not add up pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+SegmentedCodeCache", "-XX:ReservedCodeCacheSize=10M", - "-XX:NonNMethodCodeHeapSize=5M", + // After fixing a round_down issue with large page sizes (JDK-8334564), + // 5M is a bit too small for NonNMethodCodeHeap + "-XX:NonNMethodCodeHeapSize=6M", "-XX:ProfiledCodeHeapSize=5M", "-XX:NonProfiledCodeHeapSize=5M", "-version"); From 47fcf5a3b0796ffeb6407be961ceb552ca2a40f8 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Thu, 26 Sep 2024 12:33:23 +0000 Subject: [PATCH 020/188] 8340687: Open source closed frame tests #1 Reviewed-by: aivanov --- .../java/awt/Frame/DefaultFrameIconTest.java | 77 ++++++++ test/jdk/java/awt/Frame/DisposeTest.java | 112 +++++++++++ test/jdk/java/awt/Frame/FramePaintTest.java | 91 +++++++++ test/jdk/java/awt/Frame/MenuCrash.java | 178 ++++++++++++++++++ 4 files changed, 458 insertions(+) create mode 100644 test/jdk/java/awt/Frame/DefaultFrameIconTest.java create mode 100644 test/jdk/java/awt/Frame/DisposeTest.java create mode 100644 test/jdk/java/awt/Frame/FramePaintTest.java create mode 100644 test/jdk/java/awt/Frame/MenuCrash.java diff --git a/test/jdk/java/awt/Frame/DefaultFrameIconTest.java b/test/jdk/java/awt/Frame/DefaultFrameIconTest.java new file mode 100644 index 0000000000000..3ca3b70dbd1a1 --- /dev/null +++ b/test/jdk/java/awt/Frame/DefaultFrameIconTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Window; +import java.util.List; + +/* + * @test + * @bug 4240766 8259023 + * @summary Frame Icon is wrong - should be Coffee Cup or Duke image icon + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DefaultFrameIconTest +*/ + +public class DefaultFrameIconTest { + + private static final String INSTRUCTIONS = """ + You should see a dialog and a frame. + If both have Coffee Cup or Duke image icon in the upper left corner, + the test passes, otherwise it fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("DefaultFrameIconTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(DefaultFrameIconTest::createAndShowUI) + .positionTestUI(DefaultFrameIconTest::positionTestWindows) + .build() + .awaitAndCheck(); + } + + private static void positionTestWindows(List testWindows, + PassFailJFrame.InstructionUI instructionUI) { + int gap = 5; + int x = instructionUI.getLocation().x + instructionUI.getSize().width + gap; + for (Window w : testWindows) { + w.setLocation(x, instructionUI.getLocation().y); + x += w.getWidth() + gap; + } + } + + private static List createAndShowUI() { + Frame testFrame = new Frame("Frame DefaultFrameIconTest"); + Dialog testDialog = new Dialog(testFrame, "Dialog DefaultFrameIconTest"); + + testDialog.setSize(250, 100); + + testFrame.setSize(250, 100); + return List.of(testFrame, testDialog); + } +} diff --git a/test/jdk/java/awt/Frame/DisposeTest.java b/test/jdk/java/awt/Frame/DisposeTest.java new file mode 100644 index 0000000000000..08c0def638e69 --- /dev/null +++ b/test/jdk/java/awt/Frame/DisposeTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.imageio.ImageIO; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +/* + * @test + * @key headful + * @bug 4127271 + * @summary Tests that disposing of a Frame with MenuBar removes all traces + * of the Frame from the screen. + */ + +public class DisposeTest { + private static Frame backgroundFrame; + private static Frame testedFrame; + + private static final Rectangle backgroundFrameBounds = + new Rectangle(100, 100, 200, 200); + private static final Rectangle testedFrameBounds = + new Rectangle(150, 150, 100, 100); + + private static Robot robot; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + try { + EventQueue.invokeAndWait(DisposeTest::initAndShowGui); + robot.waitForIdle(); + robot.delay(500); + EventQueue.invokeAndWait(testedFrame::dispose); + robot.waitForIdle(); + robot.delay(500); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + backgroundFrame.dispose(); + testedFrame.dispose(); + }); + } + } + + private static void test() { + BufferedImage bi = robot.createScreenCapture(backgroundFrameBounds); + int redPix = Color.RED.getRGB(); + + for (int x = 0; x < bi.getWidth(); x++) { + for (int y = 0; y < bi.getHeight(); y++) { + if (bi.getRGB(x, y) != redPix) { + try { + ImageIO.write(bi, "png", + new File("failure.png")); + } catch (IOException ignored) {} + throw new RuntimeException("Test failed"); + } + } + } + } + + private static void initAndShowGui() { + backgroundFrame = new Frame("DisposeTest background"); + backgroundFrame.setUndecorated(true); + backgroundFrame.setBackground(Color.RED); + backgroundFrame.setBounds(backgroundFrameBounds); + backgroundFrame.setVisible(true); + + testedFrame = new UglyFrame(); + } + + static class UglyFrame extends Frame { + public UglyFrame() { + super("DisposeTest"); + MenuBar mb = new MenuBar(); + Menu m = new Menu("menu"); + mb.add(m); + setMenuBar(mb); + setBounds(testedFrameBounds); + setVisible(true); + } + } +} + diff --git a/test/jdk/java/awt/Frame/FramePaintTest.java b/test/jdk/java/awt/Frame/FramePaintTest.java new file mode 100644 index 0000000000000..aaa14893b34a2 --- /dev/null +++ b/test/jdk/java/awt/Frame/FramePaintTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; + +/* + * @test + * @bug 4023385 + * @summary resizing a frame causes too many repaints + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FramePaintTest +*/ + +public class FramePaintTest { + private static final String INSTRUCTIONS = """ + You should see a Frame titled "Repaint Test", filled with colored blocks. + + Resize the frame several times, both inward as well as outward. + + The blocks should move to fill the window without any flashes or + glitches which ensures that repaint is not done excessively + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FramePaintTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(ResizeLW::new) + .build() + .awaitAndCheck(); + } + + static class ResizeLW extends Frame { + + public ResizeLW() { + super("Repaint Test"); + setBackground(Color.red); + setLayout(new FlowLayout()); + setSize(300, 300); + + for (int i = 0; i < 10; i++) { + add(new ColorComp(Color.blue)); + add(new ColorComp(Color.green)); + } + } + + private static class ColorComp extends Component { + public ColorComp(Color c) { + super(); + setBackground(c); + } + + public void paint(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, getWidth(), getHeight()); + } + + public Dimension getPreferredSize() { + return new Dimension(50, 50); + } + } + } +} diff --git a/test/jdk/java/awt/Frame/MenuCrash.java b/test/jdk/java/awt/Frame/MenuCrash.java new file mode 100644 index 0000000000000..f41408ecdadfb --- /dev/null +++ b/test/jdk/java/awt/Frame/MenuCrash.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.CheckboxMenuItem; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.TextField; +import java.awt.Window; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.List; + +/* + * @test + * @bug 4133279 + * @summary Clicking in menu in inactive frame crashes application + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuCrash + */ +public class MenuCrash { + + private static final String INSTRUCTIONS = """ + Two frames will appear, alternate between frames by clicking on the + menubar of the currently deactivated frame and verify no crash occurs. + + Try mousing around the menus and choosing various items to see the menu + item name reflected in the text field. Note that CheckBoxMenuItems do + not fire action events so the check menu item (Item 03) will not change + the field. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("MenuCrash Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(MenuCrash::createAndShowUI) + .positionTestUI(MenuCrash::positionTestWindows) + .build() + .awaitAndCheck(); + } + + + private static List createAndShowUI() { + Frame frame1 = new MenuFrame("Frame 1 MenuCrash"); + Frame frame2 = new MenuFrame("Frame 2 MenuCrash"); + + frame1.setSize(300, 200); + frame2.setSize(300, 200); + + frame1.validate(); + frame2.validate(); + + return List.of(frame1, frame2); + } + + private static void positionTestWindows(List testWindows, + PassFailJFrame.InstructionUI instructionUI) { + int gap = 5; + int x = instructionUI.getLocation().x + instructionUI.getSize().width + gap; + for (Window w : testWindows) { + w.setLocation(x, instructionUI.getLocation().y); + x += w.getWidth() + gap; + } + } + + static class MenuFrame extends Frame { + private final TextField field; + + MenuFrame(String name) { + super(name); + setLayout(new FlowLayout()); + + Button removeMenus = new Button("Remove Menus"); + removeMenus.addActionListener(ev -> remove(getMenuBar())); + + Button addMenus = new Button("Add Menus"); + addMenus.addActionListener(ev -> setupMenus()); + + add(removeMenus); + add(addMenus); + field = new TextField(20); + add(field); + + addWindowListener( + new WindowAdapter() { + public void windowActivated(WindowEvent e) { + setupMenus(); + } + } + ); + + addComponentListener( + new ComponentAdapter() { + public void componentResized(ComponentEvent e) { + System.out.println(MenuFrame.this); + } + } + ); + + pack(); + } + + private void addMenuListeners() { + MenuBar menuBar = getMenuBar(); + + for (int nMenu = 0; nMenu < menuBar.getMenuCount(); nMenu++) { + Menu menu = menuBar.getMenu(nMenu); + for (int nMenuItem = 0; nMenuItem < menu.getItemCount(); nMenuItem++) { + MenuItem item = menu.getItem(nMenuItem); + item.addActionListener(ev -> field.setText(ev.getActionCommand())); + } + } + } + + private void setupMenus() { + MenuItem miSetLabel = new MenuItem("Item 01"); + MenuItem miSetEnabled = new MenuItem("Item 02"); + CheckboxMenuItem miSetState = new CheckboxMenuItem("Item 03"); + MenuItem miAdded = new MenuItem("Item 04 Added"); + + MenuBar menuBar = new MenuBar(); + Menu menu1 = new Menu("Menu 01"); + menu1.add(miSetLabel); + menu1.add(miSetEnabled); + menu1.add(miSetState); + menuBar.add(menu1); + setMenuBar(menuBar); + + // now that the peers are created, screw + // around with the menu items + miSetLabel.setLabel("Menu 01 - SetLabel"); + miSetEnabled.setEnabled(false); + miSetState.setState(true); + menu1.add(miAdded); + menu1.remove(miAdded); + menu1.addSeparator(); + menu1.add(miAdded); + + Menu menu2 = new Menu("Menu 02"); + menuBar.add(menu2); + menuBar.remove(menu2); + menuBar.add(menu2); + menu2.add(new MenuItem("Foo")); + menu1.setLabel("Menu Number 1"); + menu2.setLabel("Menu Number 2"); + + addMenuListeners(); + } + } +} From 95d3e9d199600bac0284f9151b99aef152e027ac Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Thu, 26 Sep 2024 13:20:14 +0000 Subject: [PATCH 021/188] 8339560: Unaddressed comments during code review of JDK-8337664 Reviewed-by: mullan --- .../Symantec/Distrust.java | 292 ------------------ .../{Entrust => distrust}/Distrust.java | 181 +++++------ .../distrust/Entrust.java | 68 ++++ .../distrust/Symantec.java | 95 ++++++ .../affirmtrustcommercialca-chain.pem | 0 .../affirmtrustnetworkingca-chain.pem | 0 .../entrust}/affirmtrustpremiumca-chain.pem | 0 .../affirmtrustpremiumeccca-chain.pem | 0 .../chains/entrust}/entrust2048ca-chain.pem | 0 .../chains/entrust}/entrustevca-chain.pem | 0 .../entrust}/entrustrootcaec1-chain.pem | 0 .../chains/entrust}/entrustrootcag2-chain.pem | 0 .../chains/entrust}/entrustrootcag4-chain.pem | 0 .../chains/symantec}/appleistca8g1-chain.pem | 0 .../symantec}/geotrustprimarycag2-chain.pem | 0 .../symantec}/geotrustprimarycag3-chain.pem | 0 .../symantec}/geotrustuniversalca-chain.pem | 0 .../symantec}/thawteprimaryrootca-chain.pem | 0 .../symantec}/thawteprimaryrootcag2-chain.pem | 0 .../symantec}/thawteprimaryrootcag3-chain.pem | 0 .../symantec}/verisignclass3g3ca-chain.pem | 0 .../symantec}/verisignclass3g4ca-chain.pem | 0 .../symantec}/verisignclass3g5ca-chain.pem | 0 .../verisignclass3g5ca-codesigning-chain.pem | 0 .../verisignuniversalrootca-chain.pem | 0 25 files changed, 243 insertions(+), 393 deletions(-) delete mode 100644 test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Entrust => distrust}/Distrust.java (54%) create mode 100644 test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java create mode 100644 test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Entrust => distrust/chains/entrust}/affirmtrustcommercialca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Entrust => distrust/chains/entrust}/affirmtrustnetworkingca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Entrust => distrust/chains/entrust}/affirmtrustpremiumca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Entrust => distrust/chains/entrust}/affirmtrustpremiumeccca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Entrust => distrust/chains/entrust}/entrust2048ca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Entrust => distrust/chains/entrust}/entrustevca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Entrust => distrust/chains/entrust}/entrustrootcaec1-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Entrust => distrust/chains/entrust}/entrustrootcag2-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Entrust => distrust/chains/entrust}/entrustrootcag4-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/appleistca8g1-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/geotrustprimarycag2-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/geotrustprimarycag3-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/geotrustuniversalca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/thawteprimaryrootca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/thawteprimaryrootcag2-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/thawteprimaryrootcag3-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/verisignclass3g3ca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/verisignclass3g4ca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/verisignclass3g5ca-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/verisignclass3g5ca-codesigning-chain.pem (100%) rename test/jdk/sun/security/ssl/X509TrustManagerImpl/{Symantec => distrust/chains/symantec}/verisignuniversalrootca-chain.pem (100%) diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java deleted file mode 100644 index ba008c68cdc10..0000000000000 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.io.*; -import java.math.BigInteger; -import java.security.*; -import java.security.cert.*; -import java.time.*; -import java.util.*; -import javax.net.ssl.*; -import sun.security.validator.Validator; -import sun.security.validator.ValidatorException; - -import jdk.test.lib.security.SecurityUtils; - -/** - * @test - * @bug 8207258 8216280 - * @summary Check that TLS Server certificates chaining back to distrusted - * Symantec roots are invalid - * @library /test/lib - * @modules java.base/sun.security.validator - * @run main/othervm Distrust after policyOn invalid - * @run main/othervm Distrust after policyOff valid - * @run main/othervm Distrust before policyOn valid - * @run main/othervm Distrust before policyOff valid - */ - -public class Distrust { - - private static final String TEST_SRC = System.getProperty("test.src", "."); - private static CertificateFactory cf; - - // Each of the roots have a test certificate chain stored in a file - // named "-chain.pem". - private static String[] rootsToTest = new String[] { - "geotrustprimarycag2", "geotrustprimarycag3", - "geotrustuniversalca", "thawteprimaryrootca", "thawteprimaryrootcag2", - "thawteprimaryrootcag3", "verisignclass3g3ca", "verisignclass3g4ca", - "verisignclass3g5ca", "verisignuniversalrootca" }; - - // Each of the subCAs with a delayed distrust date have a test certificate - // chain stored in a file named "-chain.pem". - private static String[] subCAsToTest = new String[]{"appleistca8g1"}; - - // A date that is after the restrictions take affect - private static final Date APRIL_17_2019 = - Date.from(LocalDate.of(2019, 4, 17) - .atStartOfDay(ZoneOffset.UTC) - .toInstant()); - - // A date that is a second before the restrictions take affect - private static final Date BEFORE_APRIL_17_2019 = - Date.from(LocalDate.of(2019, 4, 17) - .atStartOfDay(ZoneOffset.UTC) - .minusSeconds(1) - .toInstant()); - - // A date that is after the subCA restrictions take affect - private static final Date JANUARY_1_2020 = - Date.from(LocalDate.of(2020, 1, 1) - .atStartOfDay(ZoneOffset.UTC) - .toInstant()); - - // A date that is a second before the subCA restrictions take affect - private static final Date BEFORE_JANUARY_1_2020 = - Date.from(LocalDate.of(2020, 1, 1) - .atStartOfDay(ZoneOffset.UTC) - .minusSeconds(1) - .toInstant()); - - public static void main(String[] args) throws Exception { - - cf = CertificateFactory.getInstance("X.509"); - - boolean before = args[0].equals("before"); - boolean policyOn = args[1].equals("policyOn"); - boolean isValid = args[2].equals("valid"); - - if (!policyOn) { - // disable policy (default is on) - Security.setProperty("jdk.security.caDistrustPolicies", ""); - } - - Date notBefore = before ? BEFORE_APRIL_17_2019 : APRIL_17_2019; - - X509TrustManager pkixTM = getTMF("PKIX", null); - X509TrustManager sunX509TM = getTMF("SunX509", null); - for (String test : rootsToTest) { - System.err.println("Testing " + test); - X509Certificate[] chain = loadCertificateChain(test); - - testTM(sunX509TM, chain, notBefore, isValid); - testTM(pkixTM, chain, notBefore, isValid); - } - - // test chain if params are passed to TrustManager - System.err.println("Testing verisignuniversalrootca with params"); - testTM(getTMF("PKIX", getParams()), - loadCertificateChain("verisignuniversalrootca"), - notBefore, isValid); - - // test code-signing chain (should be valid as restrictions don't apply) - System.err.println("Testing verisignclass3g5ca code-signing chain"); - Validator v = Validator.getInstance(Validator.TYPE_PKIX, - Validator.VAR_CODE_SIGNING, - getParams()); - // set validation date so this will still pass when cert expires - v.setValidationDate(new Date(1544197375493l)); - v.validate(loadCertificateChain("verisignclass3g5ca-codesigning")); - - // test chains issued through subCAs - notBefore = before ? BEFORE_JANUARY_1_2020 : JANUARY_1_2020; - for (String test : subCAsToTest) { - System.err.println("Testing " + test); - X509Certificate[] chain = loadCertificateChain(test); - - testTM(sunX509TM, chain, notBefore, isValid); - testTM(pkixTM, chain, notBefore, isValid); - } - } - - private static X509TrustManager getTMF(String type, - PKIXBuilderParameters params) throws Exception { - TrustManagerFactory tmf = TrustManagerFactory.getInstance(type); - if (params == null) { - tmf.init((KeyStore)null); - } else { - tmf.init(new CertPathTrustManagerParameters(params)); - } - TrustManager[] tms = tmf.getTrustManagers(); - for (TrustManager tm : tms) { - X509TrustManager xtm = (X509TrustManager)tm; - return xtm; - } - throw new Exception("No TrustManager for " + type); - } - - private static PKIXBuilderParameters getParams() throws Exception { - PKIXBuilderParameters pbp = - new PKIXBuilderParameters(SecurityUtils.getCacertsKeyStore(), - new X509CertSelector()); - pbp.setRevocationEnabled(false); - return pbp; - } - - private static void testTM(X509TrustManager xtm, X509Certificate[] chain, - Date notBefore, boolean valid) throws Exception { - // Check if TLS Server certificate (the first element of the chain) - // is issued after the specified notBefore date (should be rejected - // unless distrust property is false). To do this, we need to - // fake the notBefore date since none of the test certs are issued - // after then. - chain[0] = new DistrustedTLSServerCert(chain[0], notBefore); - - try { - xtm.checkServerTrusted(chain, "ECDHE_RSA"); - if (!valid) { - throw new Exception("chain should be invalid"); - } - } catch (CertificateException ce) { - // expired TLS certificates should not be treated as failure - if (expired(ce)) { - System.err.println("Test is N/A, chain is expired"); - return; - } - if (valid) { - throw new Exception("Unexpected exception, chain " + - "should be valid", ce); - } - if (ce instanceof ValidatorException) { - ValidatorException ve = (ValidatorException)ce; - if (ve.getErrorType() != ValidatorException.T_UNTRUSTED_CERT) { - ce.printStackTrace(System.err); - throw new Exception("Unexpected exception: " + ce); - } - } else { - throw new Exception("Unexpected exception: " + ce); - } - } - } - - // check if a cause of exception is an expired cert - private static boolean expired(CertificateException ce) { - if (ce instanceof CertificateExpiredException) { - return true; - } - Throwable t = ce.getCause(); - while (t != null) { - if (t instanceof CertificateExpiredException) { - return true; - } - t = t.getCause(); - } - return false; - } - - private static X509Certificate[] loadCertificateChain(String name) - throws Exception { - try (InputStream in = new FileInputStream(TEST_SRC + File.separator + - name + "-chain.pem")) { - Collection certs = - (Collection)cf.generateCertificates(in); - return certs.toArray(new X509Certificate[0]); - } - } - - private static class DistrustedTLSServerCert extends X509Certificate { - private final X509Certificate cert; - private final Date notBefore; - DistrustedTLSServerCert(X509Certificate cert, Date notBefore) { - this.cert = cert; - this.notBefore = notBefore; - } - public Set getCriticalExtensionOIDs() { - return cert.getCriticalExtensionOIDs(); - } - public byte[] getExtensionValue(String oid) { - return cert.getExtensionValue(oid); - } - public Set getNonCriticalExtensionOIDs() { - return cert.getNonCriticalExtensionOIDs(); - } - public boolean hasUnsupportedCriticalExtension() { - return cert.hasUnsupportedCriticalExtension(); - } - public void checkValidity() throws CertificateExpiredException, - CertificateNotYetValidException { - // always pass - } - public void checkValidity(Date date) throws CertificateExpiredException, - CertificateNotYetValidException { - // always pass - } - public int getVersion() { return cert.getVersion(); } - public BigInteger getSerialNumber() { return cert.getSerialNumber(); } - public Principal getIssuerDN() { return cert.getIssuerDN(); } - public Principal getSubjectDN() { return cert.getSubjectDN(); } - public Date getNotBefore() { return notBefore; } - public Date getNotAfter() { return cert.getNotAfter(); } - public byte[] getTBSCertificate() throws CertificateEncodingException { - return cert.getTBSCertificate(); - } - public byte[] getSignature() { return cert.getSignature(); } - public String getSigAlgName() { return cert.getSigAlgName(); } - public String getSigAlgOID() { return cert.getSigAlgOID(); } - public byte[] getSigAlgParams() { return cert.getSigAlgParams(); } - public boolean[] getIssuerUniqueID() { - return cert.getIssuerUniqueID(); - } - public boolean[] getSubjectUniqueID() { - return cert.getSubjectUniqueID(); - } - public boolean[] getKeyUsage() { return cert.getKeyUsage(); } - public int getBasicConstraints() { return cert.getBasicConstraints(); } - public byte[] getEncoded() throws CertificateEncodingException { - return cert.getEncoded(); - } - public void verify(PublicKey key) throws CertificateException, - InvalidKeyException, NoSuchAlgorithmException, - NoSuchProviderException, SignatureException { - cert.verify(key); - } - public void verify(PublicKey key, String sigProvider) throws - CertificateException, InvalidKeyException, NoSuchAlgorithmException, - NoSuchProviderException, SignatureException { - cert.verify(key, sigProvider); - } - public PublicKey getPublicKey() { return cert.getPublicKey(); } - public String toString() { return cert.toString(); } - } -} diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/Distrust.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Distrust.java similarity index 54% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/Distrust.java rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Distrust.java index a9a47bf834cc1..18178f65ec116 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/Distrust.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Distrust.java @@ -25,7 +25,7 @@ import java.math.BigInteger; import java.security.*; import java.security.cert.*; -import java.time.*; +import java.time.ZonedDateTime; import java.util.*; import javax.net.ssl.*; import sun.security.validator.Validator; @@ -34,95 +34,80 @@ import jdk.test.lib.security.SecurityUtils; /** - * @test - * @bug 8337664 - * @summary Check that TLS Server certificates chaining back to distrusted - * Entrust roots are invalid - * @library /test/lib - * @modules java.base/sun.security.validator - * @run main/othervm Distrust after policyOn invalid - * @run main/othervm Distrust after policyOff valid - * @run main/othervm Distrust before policyOn valid - * @run main/othervm Distrust before policyOff valid + * Helper class that provides methods to facilitate testing of distrusted roots. */ - -public class Distrust { +public final class Distrust { private static final String TEST_SRC = System.getProperty("test.src", "."); private static CertificateFactory cf; - // Each of the roots have a test certificate chain stored in a file - // named "-chain.pem". - private static String[] rootsToTest = new String[] { - "entrustevca", "entrustrootcaec1", "entrustrootcag2", "entrustrootcag4", - "entrust2048ca", "affirmtrustcommercialca", "affirmtrustnetworkingca", - "affirmtrustpremiumca", "affirmtrustpremiumeccca" }; - - // A date that is after the restrictions take effect - private static final Date NOVEMBER_1_2024 = - Date.from(LocalDate.of(2024, 11, 1) - .atStartOfDay(ZoneOffset.UTC) - .toInstant()); - - // A date that is a second before the restrictions take effect - private static final Date BEFORE_NOVEMBER_1_2024 = - Date.from(LocalDate.of(2024, 11, 1) - .atStartOfDay(ZoneOffset.UTC) - .minusSeconds(1) - .toInstant()); - - public static void main(String[] args) throws Exception { + private final boolean before; + private final boolean policyOn; + private final boolean isValid; - cf = CertificateFactory.getInstance("X.509"); - - boolean before = args[0].equals("before"); - boolean policyOn = args[1].equals("policyOn"); - boolean isValid = args[2].equals("valid"); + public Distrust(String[] args) { + before = args[0].equals("before"); + policyOn = args[1].equals("policyOn"); + isValid = args[2].equals("valid"); if (!policyOn) { // disable policy (default is on) Security.setProperty("jdk.security.caDistrustPolicies", ""); } + } + + public Date getNotBefore(ZonedDateTime distrustDate) { + ZonedDateTime notBefore = before ? distrustDate.minusSeconds(1) : distrustDate; + return Date.from(notBefore.toInstant()); + } - Date notBefore = before ? BEFORE_NOVEMBER_1_2024 : NOVEMBER_1_2024; + public void testCodeSigningChain(String certPath, String name, Date validationDate) + throws Exception { + System.err.println("Testing " + name + " code-signing chain"); + Validator v = Validator.getInstance(Validator.TYPE_PKIX, + Validator.VAR_CODE_SIGNING, + getParams()); + // set validation date so this will still pass when cert expires + v.setValidationDate(validationDate); + v.validate(loadCertificateChain(certPath, name)); + } - X509TrustManager pkixTM = getTMF("PKIX", null); - X509TrustManager sunX509TM = getTMF("SunX509", null); - for (String test : rootsToTest) { + public void testCertificateChain(String certPath, Date notBefore, X509TrustManager[] tms, + String... tests) throws Exception { + for (String test : tests) { System.err.println("Testing " + test); - X509Certificate[] chain = loadCertificateChain(test); + X509Certificate[] chain = loadCertificateChain(certPath, test); - testTM(sunX509TM, chain, notBefore, isValid); - testTM(pkixTM, chain, notBefore, isValid); + for (X509TrustManager tm : tms) { + testTM(tm, chain, notBefore, isValid); + } } } - private static X509TrustManager getTMF(String type, - PKIXBuilderParameters params) throws Exception { + public X509TrustManager getTMF(String type, PKIXBuilderParameters params) throws Exception { TrustManagerFactory tmf = TrustManagerFactory.getInstance(type); if (params == null) { - tmf.init((KeyStore)null); + tmf.init((KeyStore) null); } else { tmf.init(new CertPathTrustManagerParameters(params)); } TrustManager[] tms = tmf.getTrustManagers(); for (TrustManager tm : tms) { - X509TrustManager xtm = (X509TrustManager)tm; - return xtm; + return (X509TrustManager) tm; } - throw new Exception("No TrustManager for " + type); + throw new RuntimeException("No TrustManager for " + type); } - private static PKIXBuilderParameters getParams() throws Exception { + public PKIXBuilderParameters getParams() throws Exception { PKIXBuilderParameters pbp = - new PKIXBuilderParameters(SecurityUtils.getCacertsKeyStore(), - new X509CertSelector()); + new PKIXBuilderParameters(SecurityUtils.getCacertsKeyStore(), + new X509CertSelector()); pbp.setRevocationEnabled(false); return pbp; } - private static void testTM(X509TrustManager xtm, X509Certificate[] chain, - Date notBefore, boolean valid) throws Exception { + public void testTM(X509TrustManager xtm, X509Certificate[] chain, + Date notBefore, boolean valid) { // Check if TLS Server certificate (the first element of the chain) // is issued after the specified notBefore date (should be rejected // unless distrust property is false). To do this, we need to @@ -130,67 +115,54 @@ private static void testTM(X509TrustManager xtm, X509Certificate[] chain, // after then. chain[0] = new DistrustedTLSServerCert(chain[0], notBefore); + // Wrap the intermediate and root CA certs in NonExpiringTLSServerCert + // so it will never throw a CertificateExpiredException + for (int i = 1; i < chain.length; i++) { + chain[i] = new NonExpiringTLSServerCert(chain[i]); + } + try { xtm.checkServerTrusted(chain, "ECDHE_RSA"); if (!valid) { - throw new Exception("chain should be invalid"); + throw new RuntimeException("chain should be invalid"); } } catch (CertificateException ce) { - // expired TLS certificates should not be treated as failure - if (expired(ce)) { - System.err.println("Test is N/A, chain is expired"); - return; - } if (valid) { - throw new Exception("Unexpected exception, chain " + - "should be valid", ce); + throw new RuntimeException("Unexpected exception, chain " + + "should be valid", ce); } if (ce instanceof ValidatorException) { - ValidatorException ve = (ValidatorException)ce; + ValidatorException ve = (ValidatorException) ce; if (ve.getErrorType() != ValidatorException.T_UNTRUSTED_CERT) { ce.printStackTrace(System.err); - throw new Exception("Unexpected exception: " + ce); + throw new RuntimeException("Unexpected exception: " + ce); } } else { - throw new Exception("Unexpected exception: " + ce); + throw new RuntimeException(ce); } } } - // check if a cause of exception is an expired cert - private static boolean expired(CertificateException ce) { - if (ce instanceof CertificateExpiredException) { - return true; - } - Throwable t = ce.getCause(); - while (t != null) { - if (t instanceof CertificateExpiredException) { - return true; - } - t = t.getCause(); - } - return false; - } - - private static X509Certificate[] loadCertificateChain(String name) + private X509Certificate[] loadCertificateChain(String certPath, String name) throws Exception { - try (InputStream in = new FileInputStream(TEST_SRC + File.separator + - name + "-chain.pem")) { + if (cf == null) { + cf = CertificateFactory.getInstance("X.509"); + } + try (InputStream in = new FileInputStream(TEST_SRC + File.separator + certPath + + File.separator + name + "-chain.pem")) { Collection certs = - (Collection)cf.generateCertificates(in); + (Collection) cf.generateCertificates(in); return certs.toArray(new X509Certificate[0]); } } - private static class DistrustedTLSServerCert extends X509Certificate { + private static class NonExpiringTLSServerCert extends X509Certificate { private final X509Certificate cert; - private final Date notBefore; - DistrustedTLSServerCert(X509Certificate cert, Date notBefore) { + NonExpiringTLSServerCert(X509Certificate cert) { this.cert = cert; - this.notBefore = notBefore; } public Set getCriticalExtensionOIDs() { - return cert.getCriticalExtensionOIDs(); + return cert.getCriticalExtensionOIDs(); } public byte[] getExtensionValue(String oid) { return cert.getExtensionValue(oid); @@ -201,19 +173,17 @@ public Set getNonCriticalExtensionOIDs() { public boolean hasUnsupportedCriticalExtension() { return cert.hasUnsupportedCriticalExtension(); } - public void checkValidity() throws CertificateExpiredException, - CertificateNotYetValidException { + public void checkValidity() { // always pass } - public void checkValidity(Date date) throws CertificateExpiredException, - CertificateNotYetValidException { + public void checkValidity(Date date) { // always pass } public int getVersion() { return cert.getVersion(); } public BigInteger getSerialNumber() { return cert.getSerialNumber(); } public Principal getIssuerDN() { return cert.getIssuerDN(); } public Principal getSubjectDN() { return cert.getSubjectDN(); } - public Date getNotBefore() { return notBefore; } + public Date getNotBefore() { return cert.getNotBefore(); } public Date getNotAfter() { return cert.getNotAfter(); } public byte[] getTBSCertificate() throws CertificateEncodingException { return cert.getTBSCertificate(); @@ -234,16 +204,25 @@ public byte[] getEncoded() throws CertificateEncodingException { return cert.getEncoded(); } public void verify(PublicKey key) throws CertificateException, - InvalidKeyException, NoSuchAlgorithmException, - NoSuchProviderException, SignatureException { + InvalidKeyException, NoSuchAlgorithmException, + NoSuchProviderException, SignatureException { cert.verify(key); } public void verify(PublicKey key, String sigProvider) throws - CertificateException, InvalidKeyException, NoSuchAlgorithmException, - NoSuchProviderException, SignatureException { + CertificateException, InvalidKeyException, NoSuchAlgorithmException, + NoSuchProviderException, SignatureException { cert.verify(key, sigProvider); } public PublicKey getPublicKey() { return cert.getPublicKey(); } public String toString() { return cert.toString(); } } + + private static class DistrustedTLSServerCert extends NonExpiringTLSServerCert { + private final Date notBefore; + DistrustedTLSServerCert(X509Certificate cert, Date notBefore) { + super(cert); + this.notBefore = notBefore; + } + public Date getNotBefore() { return notBefore; } + } } diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java new file mode 100644 index 0000000000000..07127742ff6c4 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.time.*; +import java.util.*; +import javax.net.ssl.*; + +/** + * @test + * @bug 8337664 + * @summary Check that TLS Server certificates chaining back to distrusted + * Entrust roots are invalid + * @library /test/lib + * @modules java.base/sun.security.validator + * @run main/othervm Entrust after policyOn invalid + * @run main/othervm Entrust after policyOff valid + * @run main/othervm Entrust before policyOn valid + * @run main/othervm Entrust before policyOff valid + */ + +public class Entrust { + + private static final String certPath = "chains" + File.separator + "entrust"; + + // Each of the roots have a test certificate chain stored in a file + // named "-chain.pem". + private static String[] rootsToTest = new String[]{ + "entrustevca", "entrustrootcaec1", "entrustrootcag2", "entrustrootcag4", + "entrust2048ca", "affirmtrustcommercialca", "affirmtrustnetworkingca", + "affirmtrustpremiumca", "affirmtrustpremiumeccca"}; + + // Date when the restrictions take effect + private static final ZonedDateTime DISTRUST_DATE = + LocalDate.of(2024, 11, 1).atStartOfDay(ZoneOffset.UTC); + + public static void main(String[] args) throws Exception { + Distrust distrust = new Distrust(args); + + X509TrustManager[] tms = new X509TrustManager[]{ + distrust.getTMF("PKIX", null), + distrust.getTMF("SunX509", null) + }; + + Date notBefore = distrust.getNotBefore(DISTRUST_DATE); + distrust.testCertificateChain(certPath, notBefore, tms, rootsToTest); + } +} diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java new file mode 100644 index 0000000000000..4e099a8de8de6 --- /dev/null +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Symantec.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.net.ssl.X509TrustManager; +import java.io.File; +import java.time.*; +import java.util.*; + + +/** + * @test + * @bug 8207258 8216280 + * @summary Check that TLS Server certificates chaining back to distrusted + * Symantec roots are invalid + * @library /test/lib + * @modules java.base/sun.security.validator + * @run main/othervm Symantec after policyOn invalid + * @run main/othervm Symantec after policyOff valid + * @run main/othervm Symantec before policyOn valid + * @run main/othervm Symantec before policyOff valid + */ + +public class Symantec { + + private static final String certPath = "chains" + File.separator + "symantec"; + + // Each of the roots have a test certificate chain stored in a file + // named "-chain.pem". + private static final String[] rootsToTest = new String[]{ + "geotrustprimarycag2", "geotrustprimarycag3", "geotrustuniversalca", + "thawteprimaryrootca", "thawteprimaryrootcag2", "thawteprimaryrootcag3", + "verisignclass3g3ca", "verisignclass3g4ca", "verisignclass3g5ca", + "verisignuniversalrootca" + }; + + // Each of the subCAs with a delayed distrust date have a test certificate + // chain stored in a file named "-chain.pem". + private static String[] subCAsToTest = new String[]{"appleistca8g1"}; + + // Date when the restrictions take effect + private static final ZonedDateTime ROOTS_DISTRUST_DATE = + LocalDate.of(2019, 4, 17).atStartOfDay(ZoneOffset.UTC); + + // Date when the subCA restrictions take effect + private static final ZonedDateTime SUBCA_DISTRUST_DATE = + LocalDate.of(2020, 1, 1).atStartOfDay(ZoneOffset.UTC); + + public static void main(String[] args) throws Exception { + Distrust distrust = new Distrust(args); + X509TrustManager[] tms = new X509TrustManager[]{ + distrust.getTMF("PKIX", null), + distrust.getTMF("SunX509", null) + }; + + // test chains issued through roots + Date notBefore = distrust.getNotBefore(ROOTS_DISTRUST_DATE); + distrust.testCertificateChain(certPath, notBefore, tms, rootsToTest); + + // test chain if params are passed to TrustManager + System.err.println("Testing verisignuniversalrootca with params"); + X509TrustManager[] tmsParams = new X509TrustManager[]{ + distrust.getTMF("PKIX", distrust.getParams()) + }; + distrust.testCertificateChain(certPath, notBefore, tmsParams, + "verisignuniversalrootca"); + + // test code-signing chain (should be valid as restrictions don't apply) + Date validationDate = new Date(1544197375493L); + distrust.testCodeSigningChain(certPath, "verisignclass3g5ca-codesigning", validationDate); + + // test chains issued through subCAs + notBefore = distrust.getNotBefore(SUBCA_DISTRUST_DATE); + distrust.testCertificateChain(certPath, notBefore, tms, subCAsToTest); + } +} diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustcommercialca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustcommercialca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustcommercialca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustcommercialca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustnetworkingca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustnetworkingca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustnetworkingca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustnetworkingca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustpremiumca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustpremiumca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustpremiumca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustpremiumca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustpremiumeccca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustpremiumeccca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/affirmtrustpremiumeccca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/affirmtrustpremiumeccca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrust2048ca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/entrust2048ca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrust2048ca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/entrust2048ca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustevca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/entrustevca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustevca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/entrustevca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcaec1-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/entrustrootcaec1-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcaec1-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/entrustrootcaec1-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcag2-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/entrustrootcag2-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcag2-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/entrustrootcag2-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcag4-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/entrustrootcag4-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Entrust/entrustrootcag4-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/entrust/entrustrootcag4-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/appleistca8g1-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/appleistca8g1-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/appleistca8g1-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/appleistca8g1-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustprimarycag2-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/geotrustprimarycag2-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustprimarycag2-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/geotrustprimarycag2-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustprimarycag3-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/geotrustprimarycag3-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustprimarycag3-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/geotrustprimarycag3-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustuniversalca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/geotrustuniversalca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/geotrustuniversalca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/geotrustuniversalca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/thawteprimaryrootca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/thawteprimaryrootca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/thawteprimaryrootca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/thawteprimaryrootca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/thawteprimaryrootcag2-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/thawteprimaryrootcag2-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/thawteprimaryrootcag2-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/thawteprimaryrootcag2-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/thawteprimaryrootcag3-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/thawteprimaryrootcag3-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/thawteprimaryrootcag3-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/thawteprimaryrootcag3-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/verisignclass3g3ca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/verisignclass3g3ca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/verisignclass3g3ca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/verisignclass3g3ca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/verisignclass3g4ca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/verisignclass3g4ca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/verisignclass3g4ca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/verisignclass3g4ca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/verisignclass3g5ca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/verisignclass3g5ca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/verisignclass3g5ca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/verisignclass3g5ca-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/verisignclass3g5ca-codesigning-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/verisignclass3g5ca-codesigning-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/verisignclass3g5ca-codesigning-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/verisignclass3g5ca-codesigning-chain.pem diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/verisignuniversalrootca-chain.pem b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/verisignuniversalrootca-chain.pem similarity index 100% rename from test/jdk/sun/security/ssl/X509TrustManagerImpl/Symantec/verisignuniversalrootca-chain.pem rename to test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/chains/symantec/verisignuniversalrootca-chain.pem From e36ce5f0341e8d0ec06cb12d0b2c0aa084401021 Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Thu, 26 Sep 2024 15:11:03 +0000 Subject: [PATCH 022/188] 8336942: Improve test coverage for class loading elements with annotations of different retentions Reviewed-by: vromero --- .../processing/model/type/BasicAnnoTests.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java index acd91eac8c785..904e4e78cad1f 100644 --- a/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java +++ b/test/langtools/tools/javac/processing/model/type/BasicAnnoTests.java @@ -41,6 +41,8 @@ import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; @@ -93,13 +95,15 @@ public class BasicAnnoTests extends JavacTestingAbstractProcessor { private static final Map> nameToAnnotation = Map.ofEntries(new NameToAnnotationEntry("java.lang.Override", Override.class), new NameToAnnotationEntry("java.lang.annotation.Repeatable", Repeatable.class), + new NameToAnnotationEntry("java.lang.annotation.Retention", Target.class), new NameToAnnotationEntry("java.lang.annotation.Target", Target.class), new NameToAnnotationEntry("BasicAnnoTests.Test", BasicAnnoTests.Test.class), new NameToAnnotationEntry("BasicAnnoTests.Tests",BasicAnnoTests.Tests.class), new NameToAnnotationEntry("BasicAnnoTests.TA", BasicAnnoTests.TA.class), new NameToAnnotationEntry("BasicAnnoTests.TB", BasicAnnoTests.TB.class), new NameToAnnotationEntry("BasicAnnoTests.TC", BasicAnnoTests.TC.class), - new NameToAnnotationEntry("BasicAnnoTests.TCs", BasicAnnoTests.TCs.class)); + new NameToAnnotationEntry("BasicAnnoTests.TCs", BasicAnnoTests.TCs.class), + new NameToAnnotationEntry("BasicAnnoTests.TD", BasicAnnoTests.TD.class)); static class NameToAnnotationEntry extends AbstractMap.SimpleEntry> { public NameToAnnotationEntry(String key, Class entry) { @@ -520,6 +524,12 @@ R scan(Iterable iter, P p) { TC[] value(); } + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.RUNTIME) + public @interface TD { + int value(); + } + // Test cases // TODO: add more cases for arrays @@ -657,6 +667,10 @@ public class Inner6 {} @Test(posn=1, annoType=TA.class, expect="23") public Set<@TA(23) ? super Object> f9; + @Test(posn=0, annoType=TA.class, expect="1") + @Test(posn=0, annoType=TD.class, expect="2") + public @TA(1) @TD(2) int f10; + // Test type use annotations on uses of type variables @Test(posn=6, annoType = TA.class, expect = "25") @Test(posn=6, annoType = TB.class, expect = "26") From 376056ca48fb5dbe3d57cea01a9fbf2ea4c35616 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 26 Sep 2024 15:14:21 +0000 Subject: [PATCH 023/188] 8336468: Reflection and MethodHandles should use more precise initializer checks Reviewed-by: liach, coleenp --- src/hotspot/share/classfile/javaClasses.cpp | 3 +- src/hotspot/share/prims/jni.cpp | 4 ++- src/hotspot/share/prims/jvm.cpp | 35 +++++++++++---------- src/hotspot/share/prims/methodHandles.cpp | 3 +- src/hotspot/share/runtime/reflection.cpp | 10 +++--- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index b6ef682ae0965..0ad36cd21dbf3 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -3052,9 +3052,10 @@ void java_lang_ClassFrameInfo::serialize_offsets(SerializeClosure* f) { static int get_flags(const methodHandle& m) { int flags = (jushort)( m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS ); - if (m->is_initializer()) { + if (m->is_object_initializer()) { flags |= java_lang_invoke_MemberName::MN_IS_CONSTRUCTOR; } else { + // Note: Static initializers can be here. Record them as plain methods. flags |= java_lang_invoke_MemberName::MN_IS_METHOD; } if (m->caller_sensitive()) { diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 1f115c783e6d7..a869e9821a0b2 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -444,9 +444,11 @@ JNI_ENTRY(jobject, jni_ToReflectedMethod(JNIEnv *env, jclass cls, jmethodID meth methodHandle m (THREAD, Method::resolve_jmethod_id(method_id)); assert(m->is_static() == (isStatic != 0), "jni_ToReflectedMethod access flags doesn't match"); oop reflection_method; - if (m->is_initializer()) { + if (m->is_object_initializer()) { reflection_method = Reflection::new_constructor(m, CHECK_NULL); } else { + // Note: Static initializers can theoretically be here, if JNI users manage + // to get their jmethodID. Record them as plain methods. reflection_method = Reflection::new_method(m, false, CHECK_NULL); } ret = JNIHandles::make_local(THREAD, reflection_method); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index bf9874956bae2..a246c2c50d674 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -1826,14 +1826,6 @@ JVM_ENTRY(jobjectArray, JVM_GetRecordComponents(JNIEnv* env, jclass ofClass)) } JVM_END -static bool select_method(const methodHandle& method, bool want_constructor) { - if (want_constructor) { - return (method->is_initializer() && !method->is_static()); - } else { - return (!method->is_initializer() && !method->is_overpass()); - } -} - static jobjectArray get_class_declared_methods_helper( JNIEnv *env, jclass ofClass, jboolean publicOnly, @@ -1866,14 +1858,22 @@ static jobjectArray get_class_declared_methods_helper( GrowableArray* idnums = new GrowableArray(methods_length); int num_methods = 0; + // Select methods matching the criteria. for (int i = 0; i < methods_length; i++) { - methodHandle method(THREAD, methods->at(i)); - if (select_method(method, want_constructor)) { - if (!publicOnly || method->is_public()) { - idnums->push(method->method_idnum()); - ++num_methods; - } + Method* method = methods->at(i); + if (want_constructor && !method->is_object_initializer()) { + continue; + } + if (!want_constructor && + (method->is_object_initializer() || method->is_static_initializer() || + method->is_overpass())) { + continue; } + if (publicOnly && !method->is_public()) { + continue; + } + idnums->push(method->method_idnum()); + ++num_methods; } // Allocate result @@ -2175,10 +2175,11 @@ static jobject get_method_at_helper(const constantPoolHandle& cp, jint index, bo THROW_MSG_NULL(vmSymbols::java_lang_RuntimeException(), "Unable to look up method in target class"); } oop method; - if (!m->is_initializer() || m->is_static()) { - method = Reflection::new_method(m, true, CHECK_NULL); - } else { + if (m->is_object_initializer()) { method = Reflection::new_constructor(m, CHECK_NULL); + } else { + // new_method accepts as Method here + method = Reflection::new_method(m, true, CHECK_NULL); } return JNIHandles::make_local(THREAD, method); } diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 4f33055d6a3fe..498da559cf526 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -313,8 +313,9 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) { case CallInfo::direct_call: vmindex = Method::nonvirtual_vtable_index; if (m->is_static()) { + assert(!m->is_static_initializer(), "Cannot be static initializer"); flags |= IS_METHOD | (JVM_REF_invokeStatic << REFERENCE_KIND_SHIFT); - } else if (m->is_initializer()) { + } else if (m->is_object_initializer()) { flags |= IS_CONSTRUCTOR | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT); } else { // "special" reflects that this is a direct call, not that it diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index ab3d82ad7e2a4..15172b7f4c3d8 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -766,10 +766,10 @@ static Handle new_type(Symbol* signature, Klass* k, TRAPS) { } oop Reflection::new_method(const methodHandle& method, bool for_constant_pool_access, TRAPS) { - // Allow sun.reflect.ConstantPool to refer to methods as java.lang.reflect.Methods. - assert(!method()->is_initializer() || - (for_constant_pool_access && method()->is_static()), - "should call new_constructor instead"); + // Allow jdk.internal.reflect.ConstantPool to refer to methods as java.lang.reflect.Methods. + assert(!method()->is_object_initializer() && + (for_constant_pool_access || !method()->is_static_initializer()), + "Should not be the initializer"); InstanceKlass* holder = method->method_holder(); int slot = method->method_idnum(); @@ -817,7 +817,7 @@ oop Reflection::new_method(const methodHandle& method, bool for_constant_pool_ac oop Reflection::new_constructor(const methodHandle& method, TRAPS) { - assert(method()->is_initializer(), "should call new_method instead"); + assert(method()->is_object_initializer(), "Should be the initializer"); InstanceKlass* holder = method->method_holder(); int slot = method->method_idnum(); From aeaa4f78ebd634c2020d0f0dd100fcb55d5130af Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 26 Sep 2024 15:20:51 +0000 Subject: [PATCH 024/188] 8336895: BufferedReader doesn't read full \r\n line ending when it doesn't fit in buffer Reviewed-by: jpai, alanb --- .../classes/java/io/BufferedInputStream.java | 5 +++ .../classes/java/io/BufferedOutputStream.java | 7 +++- .../share/classes/java/io/BufferedReader.java | 23 ++++++++----- .../share/classes/java/io/BufferedWriter.java | 34 +++++++++++-------- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/java.base/share/classes/java/io/BufferedInputStream.java b/src/java.base/share/classes/java/io/BufferedInputStream.java index cfc2a3d2c75b9..c401873ce12e4 100644 --- a/src/java.base/share/classes/java/io/BufferedInputStream.java +++ b/src/java.base/share/classes/java/io/BufferedInputStream.java @@ -50,6 +50,11 @@ * reread before new bytes are taken from * the contained input stream. * + * @apiNote + * Once wrapped in a {@code BufferedInputStream}, the underlying + * {@code InputStream} should not be used directly nor wrapped with + * another stream. + * * @author Arthur van Hoff * @since 1.0 */ diff --git a/src/java.base/share/classes/java/io/BufferedOutputStream.java b/src/java.base/share/classes/java/io/BufferedOutputStream.java index ecc1e8a8a4845..687f0c91bc4f7 100644 --- a/src/java.base/share/classes/java/io/BufferedOutputStream.java +++ b/src/java.base/share/classes/java/io/BufferedOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,11 @@ * output stream without necessarily causing a call to the underlying * system for each byte written. * + * @apiNote + * Once wrapped in a {@code BufferedOutputStream}, the underlying + * {@code OutputStream} should not be used directly nor wrapped with + * another stream. + * * @author Arthur van Hoff * @since 1.0 */ diff --git a/src/java.base/share/classes/java/io/BufferedReader.java b/src/java.base/share/classes/java/io/BufferedReader.java index 2cd027c8bd8a2..c2f6b89e08622 100644 --- a/src/java.base/share/classes/java/io/BufferedReader.java +++ b/src/java.base/share/classes/java/io/BufferedReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,8 +43,9 @@ * *

    In general, each read request made of a Reader causes a corresponding * read request to be made of the underlying character or byte stream. It is - * therefore advisable to wrap a BufferedReader around any Reader whose read() - * operations may be costly, such as FileReaders and InputStreamReaders. For + * therefore advisable to wrap a {@code BufferedReader} around any + * {@code Reader} whose {@code read()} operations may be costly, such as + * {@code FileReader}s and {@code InputStreamReader}s. For * example, * * {@snippet lang=java : @@ -52,12 +53,18 @@ * } * * will buffer the input from the specified file. Without buffering, each - * invocation of read() or readLine() could cause bytes to be read from the - * file, converted into characters, and then returned, which can be very - * inefficient. + * invocation of {@code read()} or {@code readLine()} could cause bytes to be + * read from the file, converted into characters, and then returned, which can + * be very inefficient. * - *

    Programs that use DataInputStreams for textual input can be localized by - * replacing each DataInputStream with an appropriate BufferedReader. + *

    Programs that use {@code DataInputStream}s for textual input can be + * localized by replacing each {@code DataInputStream} with an appropriate + * {@code BufferedReader}. + * + * @apiNote + * Once wrapped in a {@code BufferedReader}, the underlying + * {@code Reader} should not be used directly nor wrapped with + * another reader. * * @see FileReader * @see InputStreamReader diff --git a/src/java.base/share/classes/java/io/BufferedWriter.java b/src/java.base/share/classes/java/io/BufferedWriter.java index 4904f7180724a..17862a265ae82 100644 --- a/src/java.base/share/classes/java/io/BufferedWriter.java +++ b/src/java.base/share/classes/java/io/BufferedWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,25 +37,31 @@ *

    The buffer size may be specified, or the default size may be accepted. * The default is large enough for most purposes. * - *

    A newLine() method is provided, which uses the platform's own notion of - * line separator as defined by the system property {@code line.separator}. - * Not all platforms use the newline character ('\n') to terminate lines. - * Calling this method to terminate each output line is therefore preferred to - * writing a newline character directly. + *

    A {@code newLine()} method is provided, which uses the platform's own + * notion of line separator as defined by the system property + * {@linkplain System#lineSeparator() line.separator}. Not all platforms use the newline character ('\n') + * to terminate lines. Calling this method to terminate each output line is + * therefore preferred to writing a newline character directly. * - *

    In general, a Writer sends its output immediately to the underlying - * character or byte stream. Unless prompt output is required, it is advisable - * to wrap a BufferedWriter around any Writer whose write() operations may be - * costly, such as FileWriters and OutputStreamWriters. For example, + *

    In general, a {@code Writer} sends its output immediately to the + * underlying character or byte stream. Unless prompt output is required, it + * is advisable to wrap a {@code BufferedWriter} around any {@code Writer} whose + * {@code write()} operations may be costly, such as {@code FileWriter}s and + * {@code OutputStreamWriter}s. For example, * * {@snippet lang=java : * PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out"))); * } * - * will buffer the PrintWriter's output to the file. Without buffering, each - * invocation of a print() method would cause characters to be converted into - * bytes that would then be written immediately to the file, which can be very - * inefficient. + * will buffer the {@code PrintWriter}'s output to the file. Without buffering, + * each invocation of a {@code print()} method would cause characters to be + * converted into bytes that would then be written immediately to the file, + * which can be very inefficient. + * + * @apiNote + * Once wrapped in a {@code BufferedWriter}, the underlying + * {@code Writer} should not be used directly nor wrapped with + * another writer. * * @see PrintWriter * @see FileWriter From aceae76fb5853ab65851225aeb35a425af8f7af8 Mon Sep 17 00:00:00 2001 From: Maxim Kartashev Date: Thu, 26 Sep 2024 15:40:31 +0000 Subject: [PATCH 025/188] 8339460: CDS error when module is located in a directory with space in the name Reviewed-by: ccheung, iklam --- src/hotspot/share/cds/classListParser.cpp | 4 +- src/hotspot/share/cds/classListWriter.cpp | 2 + src/hotspot/share/cds/filemap.cpp | 2 +- src/hotspot/share/classfile/classLoader.cpp | 48 ++++- src/hotspot/share/classfile/classLoader.hpp | 2 +- .../share/classfile/classLoaderExt.cpp | 10 +- test/hotspot/jtreg/TEST.groups | 1 + .../cds/appcds/complexURI/ComplexURITest.java | 167 ++++++++++++++++++ .../appcds/complexURI/mypackage/Another.java | 27 +++ .../cds/appcds/complexURI/mypackage/Main.java | 37 ++++ 10 files changed, 289 insertions(+), 11 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index f8d24295a12e5..694a179d7ee6c 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -508,7 +508,9 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS THROW_NULL(vmSymbols::java_lang_ClassNotFoundException()); } - InstanceKlass* k = UnregisteredClasses::load_class(class_name, _source, CHECK_NULL); + ResourceMark rm; + char * source_path = os::strdup_check_oom(ClassLoader::uri_to_path(_source)); + InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL); if (k->local_interfaces()->length() != _interfaces->length()) { print_specified_interfaces(); print_actual_interfaces(k); diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 78cd092445b70..1b9f589f1c5e5 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -174,6 +174,8 @@ void ClassListWriter::write_to_stream(const InstanceKlass* k, outputStream* stre } } + // NB: the string following "source: " is not really a proper file name, but rather + // a truncated URI referring to a file. It must be decoded after reading. #ifdef _WINDOWS // "file:/C:/dir/foo.jar" -> "C:/dir/foo.jar" stream->print(" source: %s", cfs->source() + 6); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index c935541d7cf0a..78613ae4b36c4 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -581,7 +581,7 @@ int FileMapInfo::get_module_shared_path_index(Symbol* location) { // skip_uri_protocol was also called during dump time -- see ClassLoaderExt::process_module_table() ResourceMark rm; - const char* file = ClassLoader::skip_uri_protocol(location->as_C_string()); + const char* file = ClassLoader::uri_to_path(location->as_C_string()); for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) { SharedClassPathEntry* ent = shared_path(i); if (!ent->is_non_existent()) { diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index 5309fcd20a8be..487d69a6f4fc9 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -81,6 +81,9 @@ #include "utilities/ostream.hpp" #include "utilities/utf8.hpp" +#include +#include + // Entry point in java.dll for path canonicalization typedef int (*canonicalize_fn_t)(const char *orig, char *out, int len); @@ -1209,7 +1212,7 @@ InstanceKlass* ClassLoader::load_class(Symbol* name, PackageEntry* pkg_entry, bo } #if INCLUDE_CDS -char* ClassLoader::skip_uri_protocol(char* source) { +static const char* skip_uri_protocol(const char* source) { if (strncmp(source, "file:", 5) == 0) { // file: protocol path could start with file:/ or file:/// // locate the char after all the forward slashes @@ -1228,6 +1231,47 @@ char* ClassLoader::skip_uri_protocol(char* source) { return source; } +static char decode_percent_encoded(const char *str, size_t& index) { + if (str[index] == '%' + && isxdigit(str[index + 1]) + && isxdigit(str[index + 2])) { + char hex[3]; + hex[0] = str[index + 1]; + hex[1] = str[index + 2]; + hex[2] = '\0'; + index += 2; + return (char) strtol(hex, NULL, 16); + } + return str[index]; +} + +char* ClassLoader::uri_to_path(const char* uri) { + const size_t len = strlen(uri) + 1; + char* path = NEW_RESOURCE_ARRAY(char, len); + + uri = skip_uri_protocol(uri); + + if (strncmp(uri, "//", 2) == 0) { + // Skip the empty "authority" part + uri += 2; + } + +#ifdef _WINDOWS + if (uri[0] == '/') { + // Absolute path name on Windows does not begin with a slash + uri += 1; + } +#endif + + size_t path_index = 0; + for (size_t i = 0; i < strlen(uri); ++i) { + char decoded = decode_percent_encoded(uri, i); + path[path_index++] = decoded; + } + path[path_index] = '\0'; + return path; +} + // Record the shared classpath index and loader type for classes loaded // by the builtin loaders at dump time. void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, @@ -1261,7 +1305,7 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik, // Save the path from the file: protocol or the module name from the jrt: protocol // if no protocol prefix is found, path is the same as stream->source(). This path // must be valid since the class has been successfully parsed. - char* path = skip_uri_protocol(src); + const char* path = ClassLoader::uri_to_path(src); assert(path != nullptr, "sanity"); for (int i = 0; i < FileMapInfo::get_number_of_shared_paths(); i++) { SharedClassPathEntry* ent = FileMapInfo::shared_path(i); diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp index af625082ddabf..e44059b724769 100644 --- a/src/hotspot/share/classfile/classLoader.hpp +++ b/src/hotspot/share/classfile/classLoader.hpp @@ -382,7 +382,7 @@ class ClassLoader: AllStatic { // entries during shared classpath setup time. static int num_module_path_entries(); static void exit_with_path_failure(const char* error, const char* message); - static char* skip_uri_protocol(char* source); + static char* uri_to_path(const char* uri); static void record_result(JavaThread* current, InstanceKlass* ik, const ClassFileStream* stream, bool redefined); #endif diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp index 3cd7dd7cd3ba6..997f9d76676fa 100644 --- a/src/hotspot/share/classfile/classLoaderExt.cpp +++ b/src/hotspot/share/classfile/classLoaderExt.cpp @@ -100,12 +100,10 @@ void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable* ModulePathsGatherer(JavaThread* current, GrowableArray* module_paths) : _current(current), _module_paths(module_paths) {} void do_module(ModuleEntry* m) { - char* path = m->location()->as_C_string(); - if (strncmp(path, "file:", 5) == 0) { - path = ClassLoader::skip_uri_protocol(path); - char* path_copy = NEW_RESOURCE_ARRAY(char, strlen(path) + 1); - strcpy(path_copy, path); - _module_paths->append(path_copy); + char* uri = m->location()->as_C_string(); + if (strncmp(uri, "file:", 5) == 0) { + char* path = ClassLoader::uri_to_path(uri); + _module_paths->append(path); } } }; diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 101cbe76afdda..4ab4ba68692c1 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -435,6 +435,7 @@ hotspot_cds_only = \ hotspot_appcds_dynamic = \ runtime/cds/appcds/ \ -runtime/cds/appcds/cacheObject \ + -runtime/cds/appcds/complexURI \ -runtime/cds/appcds/customLoader \ -runtime/cds/appcds/dynamicArchive \ -runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java \ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java new file mode 100644 index 0000000000000..409e37e10a164 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/ComplexURITest.java @@ -0,0 +1,167 @@ +/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024 JetBrains s.r.o. + * 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 Verifies that CDS works with jar located in directories + * with names that need escaping + * @bug 8339460 + * @requires vm.cds + * @requires vm.cds.custom.loaders + * @requires vm.flagless + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @compile mypackage/Main.java mypackage/Another.java + * @run main/othervm ComplexURITest + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.Platform; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; + +public class ComplexURITest { + final static String moduleName = "mymodule"; + + public static void main(String[] args) throws Exception { + System.setProperty("test.noclasspath", "true"); + String jarFile = JarBuilder.build(moduleName, "mypackage/Main", "mypackage/Another"); + + Path subDir = Path.of(".", "dir with space"); + Files.createDirectory(subDir); + Path newJarFilePath = subDir.resolve(moduleName + ".jar"); + Files.move(Path.of(jarFile), newJarFilePath); + jarFile = newJarFilePath.toString(); + + final String listFileName = "test-classlist.txt"; + final String staticArchiveName = "test-static.jsa"; + final String dynamicArchiveName = "test-dynamic.jsa"; + + // Verify static archive creation and use + File fileList = new File(listFileName); + delete(fileList.toPath()); + File staticArchive = new File(staticArchiveName); + delete(staticArchive.toPath()); + + createClassList(jarFile, listFileName); + if (!fileList.exists()) { + throw new RuntimeException("No class list created at " + fileList); + } + + createArchive(jarFile, listFileName, staticArchiveName); + if (!staticArchive.exists()) { + throw new RuntimeException("No shared classes archive created at " + staticArchive); + } + + useArchive(jarFile, staticArchiveName); + + // Verify dynamic archive creation and use + File dynamicArchive = new File(dynamicArchiveName); + delete(dynamicArchive.toPath()); + + createDynamicArchive(jarFile, dynamicArchiveName); + if (!dynamicArchive.exists()) { + throw new RuntimeException("No dynamic archive created at " + dynamicArchive); + } + + testDynamicArchive(jarFile, dynamicArchiveName); + } + + private static void delete(Path path) throws Exception { + if (Files.exists(path)) { + if (Platform.isWindows()) { + Files.setAttribute(path, "dos:readonly", false); + } + Files.delete(path); + } + } + + private static void createClassList(String jarFile, String list) throws Exception { + String[] launchArgs = { + "-XX:DumpLoadedClassList=" + list, + "--module-path", + jarFile, + "--module", + moduleName + "/mypackage.Main"}; + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs); + OutputAnalyzer output = TestCommon.executeAndLog(pb, "create-list"); + output.shouldHaveExitValue(0); + } + + private static void createArchive(String jarFile, String list, String archive) throws Exception { + String[] launchArgs = { + "-Xshare:dump", + "-XX:SharedClassListFile=" + list, + "-XX:SharedArchiveFile=" + archive, + "--module-path", + jarFile, + "--module", + moduleName + "/mypackage.Main"}; + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs); + OutputAnalyzer output = TestCommon.executeAndLog(pb, "dump-archive"); + output.shouldHaveExitValue(0); + } + + private static void useArchive(String jarFile, String archive) throws Exception { + String[] launchArgs = { + "-Xshare:on", + "-XX:SharedArchiveFile=" + archive, + "--module-path", + jarFile, + "--module", + moduleName + "/mypackage.Main"}; + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs); + OutputAnalyzer output = TestCommon.executeAndLog(pb, "use-archive"); + output.shouldHaveExitValue(0); + } + + private static void createDynamicArchive(String jarFile, String archive) throws Exception { + String[] launchArgs = { + "-XX:ArchiveClassesAtExit=" + archive, + "--module-path", + jarFile, + "--module", + moduleName + "/mypackage.Main"}; + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs); + OutputAnalyzer output = TestCommon.executeAndLog(pb, "dynamic-archive"); + output.shouldHaveExitValue(0); + } + + private static void testDynamicArchive(String jarFile, String archive) throws Exception { + String[] launchArgs = { + "-XX:SharedArchiveFile=" + archive, + "-XX:+PrintSharedArchiveAndExit", + "--module-path", + jarFile, + "--module", + moduleName + "/mypackage.Main"}; + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(launchArgs); + OutputAnalyzer output = TestCommon.executeAndLog(pb, "dynamic-archive"); + output.shouldHaveExitValue(0); + output.shouldContain("archive is valid"); + output.shouldContain(": mypackage.Main app_loader"); + output.shouldContain(": mypackage.Another unregistered_loader"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java new file mode 100644 index 0000000000000..106dfd4904c7d --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Another.java @@ -0,0 +1,27 @@ +/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024 JetBrains s.r.o. + * 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 mypackage; + +public class Another { +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java new file mode 100644 index 0000000000000..fdb79e895d240 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/complexURI/mypackage/Main.java @@ -0,0 +1,37 @@ +/* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024 JetBrains s.r.o. + * 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 mypackage; + +import java.net.URL; +import java.net.URLClassLoader; + +public class Main { + public static void main(String[] args) throws Exception { + URL url1 = Main.class.getProtectionDomain().getCodeSource().getLocation(); + System.out.println("Will load Another from " + url1); + ClassLoader cl = URLClassLoader.newInstance(new URL[] { url1 }, null); + var anotherClass = cl.loadClass("mypackage.Another"); + System.out.println("Class " + anotherClass + " loaded successfully"); + } +} From 8225a5f58a62ddf4acbb879bfcb53cf7bfd8542f Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 26 Sep 2024 16:03:04 +0000 Subject: [PATCH 026/188] 8340981: Update citations to "Hacker's Delight" Reviewed-by: bpb, iris, liach, jwaters --- src/java.base/share/classes/java/lang/Integer.java | 9 +++++---- src/java.base/share/classes/java/lang/Long.java | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 7a65046181f00..fccdd697c7238 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,8 +63,9 @@ *

    Implementation note: The implementations of the "bit twiddling" * methods (such as {@link #highestOneBit(int) highestOneBit} and * {@link #numberOfTrailingZeros(int) numberOfTrailingZeros}) are - * based on material from Henry S. Warren, Jr.'s Hacker's - * Delight, (Addison Wesley, 2002). + * based on material from Henry S. Warren, Jr.'s Hacker's + * Delight, (Addison Wesley, 2002) and Hacker's + * Delight, Second Edition, (Pearson Education, 2013). * * @author Lee Boynton * @author Arthur van Hoff @@ -1736,7 +1737,7 @@ public static int reverse(int i) { * compress(expand(x, m), m) == x & compress(m, m) * } *

    - * The Sheep And Goats (SAG) operation (see Hacker's Delight, section 7.7) + * The Sheep And Goats (SAG) operation (see Hacker's Delight, Second Edition, section 7.7) * can be implemented as follows: * {@snippet lang="java" : * int compressLeft(int i, int mask) { diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index ee9533b29eb53..ff34da232f9ab 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -63,8 +63,9 @@ *

    Implementation note: The implementations of the "bit twiddling" * methods (such as {@link #highestOneBit(long) highestOneBit} and * {@link #numberOfTrailingZeros(long) numberOfTrailingZeros}) are - * based on material from Henry S. Warren, Jr.'s Hacker's - * Delight, (Addison Wesley, 2002). + * based on material from Henry S. Warren, Jr.'s Hacker's + * Delight, (Addison Wesley, 2002) and Hacker's + * Delight, Second Edition, (Pearson Education, 2013). * * @author Lee Boynton * @author Arthur van Hoff @@ -1749,7 +1750,7 @@ public static long reverse(long i) { * compress(expand(x, m), m) == x & compress(m, m) * } *

    - * The Sheep And Goats (SAG) operation (see Hacker's Delight, section 7.7) + * The Sheep And Goats (SAG) operation (see Hacker's Delight, Second Edition, section 7.7) * can be implemented as follows: * {@snippet lang="java" : * long compressLeft(long i, long mask) { From bb040ef4cc2b626f282cbf6af5b359d1c2505385 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 26 Sep 2024 16:04:45 +0000 Subject: [PATCH 027/188] 8340983: Use index and definition tags in Object and Double Reviewed-by: bpb, liach --- src/java.base/share/classes/java/lang/Double.java | 6 +++--- src/java.base/share/classes/java/lang/Object.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Double.java b/src/java.base/share/classes/java/lang/Double.java index 9b11964d9e6fa..e789a6777175e 100644 --- a/src/java.base/share/classes/java/lang/Double.java +++ b/src/java.base/share/classes/java/lang/Double.java @@ -148,7 +148,7 @@ * relations that can be defined over floating-point values: * *

    - *
    numerical equality ({@code ==} + *
    {@index "numerical equality"} ({@code ==} * operator): (Not an equivalence relation)
    *
    Two floating-point values represent the same extended real * number. The extended real numbers are the real numbers augmented @@ -158,7 +158,7 @@ * number and is not equal to any value, including itself. *
    * - *
    bit-wise equivalence:
    + *
    {@index "bit-wise equivalence"}:
    *
    The bits of the two floating-point values are the same. This * equivalence relation for {@code double} values {@code a} and {@code * b} is implemented by the expression @@ -168,7 +168,7 @@ * is distinguished from every other bit pattern encoding a NaN. *
    * - *
    representation equivalence:
    + *
    {@index "representation equivalence"}:
    *
    The two floating-point values represent the same IEEE 754 * datum. In particular, for {@linkplain #isFinite(double) * finite} values, the sign, {@linkplain Math#getExponent(double) diff --git a/src/java.base/share/classes/java/lang/Object.java b/src/java.base/share/classes/java/lang/Object.java index d9813df57a4f0..7909f05304268 100644 --- a/src/java.base/share/classes/java/lang/Object.java +++ b/src/java.base/share/classes/java/lang/Object.java @@ -109,7 +109,7 @@ public Object() {} /** * Indicates whether some other object is "equal to" this one. *

    - * The {@code equals} method implements an equivalence relation + * The {@code equals} method implements an {@index "equivalence relation"} * on non-null object references: *

      *
    • It is reflexive: for any non-null reference value From a02d895f7ad59fe33f8a761dbd7bceb0b8dfefc0 Mon Sep 17 00:00:00 2001 From: Ravi Gupta Date: Thu, 26 Sep 2024 16:31:31 +0000 Subject: [PATCH 028/188] 8333403: Write a test to check various components events are triggered properly Reviewed-by: aivanov --- .../awt/Component/ComponentEventTest.java | 357 ++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 test/jdk/java/awt/Component/ComponentEventTest.java diff --git a/test/jdk/java/awt/Component/ComponentEventTest.java b/test/jdk/java/awt/Component/ComponentEventTest.java new file mode 100644 index 0000000000000..bfbfed336a017 --- /dev/null +++ b/test/jdk/java/awt/Component/ComponentEventTest.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.InputEvent; +import java.lang.reflect.InvocationTargetException; + +import jdk.test.lib.Platform; + +/* + * @test + * @key headful + * @bug 8333403 + * @summary Test performs various operations to check components events are triggered properly. + * @library /test/lib + * @build jdk.test.lib.Platform + * @run main ComponentEventTest + */ +public class ComponentEventTest { + + private static final int DELAY = 500; + + private static Frame frame; + private static Robot robot; + + private static Component[] components; + + private static volatile Point centerPoint; + + private static volatile boolean componentHidden; + private static volatile boolean componentShown; + private static volatile boolean componentMoved; + private static volatile boolean componentResized; + + private static final ComponentListener componentListener = + new ComponentListener() { + + @Override + public void componentShown(ComponentEvent e) { + System.out.println("ComponentShown: " + e.getSource()); + componentShown = true; + } + + @Override + public void componentResized(ComponentEvent e) { + System.out.println("ComponentResized: " + e.getSource()); + componentResized = true; + } + + @Override + public void componentMoved(ComponentEvent e) { + System.out.println("ComponentMoved: " + e.getSource()); + componentMoved = true; + } + + @Override + public void componentHidden(ComponentEvent e) { + System.out.println("ComponentHidden: " + e.getSource()); + componentHidden = true; + } + }; + + private static void initializeGUI() { + frame = new Frame("Component Event Test"); + frame.setLayout(new FlowLayout()); + + Panel panel = new Panel(); + Button button = new Button("Button"); + Label label = new Label("Label"); + List list = new List(); + list.add("One"); + list.add("Two"); + list.add("Three"); + Choice choice = new Choice(); + choice.add("Red"); + choice.add("Orange"); + choice.add("Yellow"); + Checkbox checkbox = new Checkbox("Checkbox"); + Scrollbar scrollbar = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, 255); + TextField textfield = new TextField(15); + TextArea textarea = new TextArea(5, 15); + + components = new Component[] { panel, button, label, list, choice, + checkbox, scrollbar, textfield, textarea, frame }; + + for (int i = 0; i < components.length - 1; i++) { + components[i].addComponentListener(componentListener); + frame.add(components[i]); + } + frame.addComponentListener(componentListener); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + + EventQueue.invokeAndWait(ComponentEventTest::initializeGUI); + robot.waitForIdle(); + robot.delay(DELAY); + + doTest(); + + System.out.println("Test PASSED"); + } finally { + EventQueue.invokeAndWait(ComponentEventTest::disposeFrame); + } + } + + private static void doTest() + throws InvocationTargetException, InterruptedException { + // Click the frame to ensure it gains focus + clickFrame(); + + robot.delay(DELAY); + + for (int i = 0; i < components.length; i++) { + for (boolean state : new boolean[] { true, false }) { + doTest(components[i], state); + } + } + + robot.delay(DELAY); + + System.out.println("Iconify frame"); + resetValues(); + testIconifyFrame(); + + System.out.println("Deiconify frame"); + resetValues(); + testDeiconifyFrame(); + } + + private static void clickFrame() + throws InvocationTargetException, InterruptedException { + EventQueue.invokeAndWait(() -> { + Point location = frame.getLocationOnScreen(); + Dimension size = frame.getSize(); + centerPoint = new Point(location.x + size.width / 2, + location.y + size.height / 2); + }); + + robot.mouseMove(centerPoint.x, centerPoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + private static void testIconifyFrame() + throws InvocationTargetException, InterruptedException { + EventQueue.invokeAndWait(() -> frame.setExtendedState(Frame.ICONIFIED)); + + robot.waitForIdle(); + robot.delay(DELAY); + if (componentShown || componentHidden || componentMoved + || componentResized) { + throw new RuntimeException( + "ComponentEvent triggered when frame is iconified"); + } + } + + private static void testDeiconifyFrame() + throws InvocationTargetException, InterruptedException { + EventQueue.invokeAndWait(() -> frame.setExtendedState(Frame.NORMAL)); + + robot.waitForIdle(); + robot.delay(DELAY); + + /* + * Because of the different behavior between MS Windows and other OS, we + * receive native events WM_SIZE and WM_MOVE on Windows when the frame + * state changes from iconified to normal. AWT sends these events to + * components when it receives the events from the native system. See + * JDK-6754618 for more information. + */ + + if (componentShown || componentHidden) { + throw new RuntimeException( + "FAIL: componentShown or componentHidden triggered " + + "when frame set to normal"); + } + + if (Platform.isWindows() && (!componentMoved || !componentResized)) { + throw new RuntimeException( + "FAIL: componentMoved or componentResized wasn't triggered " + + "when frame set to normal"); + } + if (!Platform.isWindows() && (componentMoved || componentResized)) { + throw new RuntimeException( + "FAIL: componentMoved or componentResized triggered " + + "when frame set to normal"); + } + } + + private static void doTest(final Component currentComponent, boolean enable) + throws InvocationTargetException, InterruptedException { + + System.out.println("Component " + currentComponent); + System.out.println(" enabled " + enable); + + EventQueue.invokeAndWait(() -> { + currentComponent.setEnabled(enable); + revalidateFrame(); + }); + + robot.delay(DELAY); + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setVisible(false); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (!componentHidden) { + throw new RuntimeException("FAIL: ComponentHidden not triggered for" + + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setVisible(false); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (componentHidden) { + throw new RuntimeException("FAIL: ComponentHidden triggered when " + + "setVisible(false) called for a hidden " + + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setVisible(true); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (!componentShown) { + throw new RuntimeException("FAIL: ComponentShown not triggered for " + + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setVisible(true); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (componentShown) { + throw new RuntimeException("FAIL: ComponentShown triggered when " + + "setVisible(true) called for a shown " + + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setLocation(currentComponent.getLocation().x + 1, + currentComponent.getLocation().y); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (!componentMoved) { + throw new RuntimeException("FAIL: ComponentMoved not triggered for " + + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setSize(currentComponent.getSize().width + 1, + currentComponent.getSize().height); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (!componentResized) { + throw new RuntimeException("FAIL: ComponentResized not triggered " + + "when size increases for " + currentComponent.getClass()); + } + + resetValues(); + EventQueue.invokeAndWait(() -> { + currentComponent.setSize(currentComponent.getSize().width - 1, + currentComponent.getSize().height); + revalidateFrame(); + }); + + robot.delay(DELAY); + if (!componentResized) { + throw new RuntimeException("FAIL: ComponentResized not triggered " + + "when size decreases for " + currentComponent.getClass()); + } + + System.out.println("\n"); + } + + private static void revalidateFrame() { + frame.invalidate(); + frame.validate(); + } + + private static void resetValues() { + componentShown = false; + componentHidden = false; + componentMoved = false; + componentResized = false; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + } + } +} From 1447967f53fe27f67e4bb766464f941e39506d41 Mon Sep 17 00:00:00 2001 From: Fernando Guallini Date: Thu, 26 Sep 2024 16:47:49 +0000 Subject: [PATCH 029/188] 8339261: Logs truncated in test javax/net/ssl/DTLS/DTLSRehandshakeTest.java Reviewed-by: rhalade, hchao --- test/jdk/javax/net/ssl/DTLS/TEST.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/javax/net/ssl/DTLS/TEST.properties b/test/jdk/javax/net/ssl/DTLS/TEST.properties index ceb6c8c9c42c7..a50cba09c0f81 100644 --- a/test/jdk/javax/net/ssl/DTLS/TEST.properties +++ b/test/jdk/javax/net/ssl/DTLS/TEST.properties @@ -6,3 +6,4 @@ modules = \ java.security.jgss/sun.security.krb5.internal:+open \ java.security.jgss/sun.security.krb5.internal.ktab \ java.base/sun.security.util +maxOutputSize = 2500000 From 5d062e248ec4be7b35f85c341e76aa6d8d6d8b2b Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 26 Sep 2024 19:36:26 +0000 Subject: [PATCH 030/188] 8340576: Some JVMCI flags are inconsistent Reviewed-by: never --- src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp | 2 +- src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 2 +- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 2 +- src/hotspot/share/compiler/oopMap.inline.hpp | 6 ++---- src/hotspot/share/jvmci/jvmci_globals.cpp | 4 ++-- src/hotspot/share/jvmci/jvmci_globals.hpp | 6 +++--- src/hotspot/share/runtime/deoptimization.cpp | 2 +- src/hotspot/share/runtime/escapeBarrier.hpp | 4 ++-- src/hotspot/share/runtime/sharedRuntime.cpp | 2 +- 9 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 1b02108b00f94..52996f4c4a503 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -2234,7 +2234,7 @@ void SharedRuntime::generate_deopt_blob() { int reexecute_offset = __ pc() - start; #if INCLUDE_JVMCI && !defined(COMPILER1) - if (EnableJVMCI && UseJVMCICompiler) { + if (UseJVMCICompiler) { // JVMCI does not use this kind of deoptimization __ should_not_reach_here(); } diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 879fd92272279..27da26d404cc0 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -2110,7 +2110,7 @@ void SharedRuntime::generate_deopt_blob() { int reexecute_offset = __ pc() - start; #if INCLUDE_JVMCI && !defined(COMPILER1) - if (EnableJVMCI && UseJVMCICompiler) { + if (UseJVMCICompiler) { // JVMCI does not use this kind of deoptimization __ should_not_reach_here(); } diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 4bd91f640fca7..174e2e0277903 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -2674,7 +2674,7 @@ void SharedRuntime::generate_deopt_blob() { int reexecute_offset = __ pc() - start; #if INCLUDE_JVMCI && !defined(COMPILER1) - if (EnableJVMCI && UseJVMCICompiler) { + if (UseJVMCICompiler) { // JVMCI does not use this kind of deoptimization __ should_not_reach_here(); } diff --git a/src/hotspot/share/compiler/oopMap.inline.hpp b/src/hotspot/share/compiler/oopMap.inline.hpp index f2a3b3ba834df..05ef53f823142 100644 --- a/src/hotspot/share/compiler/oopMap.inline.hpp +++ b/src/hotspot/share/compiler/oopMap.inline.hpp @@ -66,12 +66,10 @@ void OopMapDo::iterate_oops_do(const frame continue; #ifndef COMPILER2 - COMPILER1_PRESENT(ShouldNotReachHere();) #if INCLUDE_JVMCI - if (UseJVMCICompiler) { - ShouldNotReachHere(); - } + if (!EnableJVMCI) #endif + ShouldNotReachHere(); #endif // !COMPILER2 address loc = fr->oopmapreg_to_location(omv.reg(), reg_map); diff --git a/src/hotspot/share/jvmci/jvmci_globals.cpp b/src/hotspot/share/jvmci/jvmci_globals.cpp index 36740560dd23f..2ae38044df0ff 100644 --- a/src/hotspot/share/jvmci/jvmci_globals.cpp +++ b/src/hotspot/share/jvmci/jvmci_globals.cpp @@ -26,6 +26,7 @@ #include "compiler/compilerDefinitions.hpp" #include "gc/shared/gcConfig.hpp" #include "jvm.h" +#include "jvmci/jvmci.hpp" #include "jvmci/jvmci_globals.hpp" #include "logging/log.hpp" #include "runtime/arguments.hpp" @@ -90,8 +91,7 @@ bool JVMCIGlobals::check_jvmci_flags_are_consistent() { if (EnableJVMCI) { if (FLAG_IS_DEFAULT(UseJVMCINativeLibrary) && !UseJVMCINativeLibrary) { - char path[JVM_MAXPATHLEN]; - if (os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), JVMCI_SHARED_LIBRARY_NAME)) { + if (JVMCI::shared_library_exists()) { // If a JVMCI native library is present, // we enable UseJVMCINativeLibrary by default. FLAG_SET_DEFAULT(UseJVMCINativeLibrary, true); diff --git a/src/hotspot/share/jvmci/jvmci_globals.hpp b/src/hotspot/share/jvmci/jvmci_globals.hpp index 30f2e6c2c73e0..d6f9ddd6739d4 100644 --- a/src/hotspot/share/jvmci/jvmci_globals.hpp +++ b/src/hotspot/share/jvmci/jvmci_globals.hpp @@ -45,7 +45,7 @@ class fileStream; constraint) \ \ product(bool, EnableJVMCI, false, EXPERIMENTAL, \ - "Enable JVMCI") \ + "Enable JVMCI. Defaults to true if UseJVMCICompiler is true.") \ \ product(bool, UseGraalJIT, false, EXPERIMENTAL, \ "Select the Graal JVMCI compiler. This is an alias for: " \ @@ -140,8 +140,8 @@ class fileStream; product(bool, UseJVMCINativeLibrary, false, EXPERIMENTAL, \ "Execute JVMCI Java code from a shared library (\"libjvmci\") " \ "instead of loading it from class files and executing it " \ - "on the HotSpot heap. Defaults to true if EnableJVMCI is " \ - "true and a JVMCI native library is available.") \ + "on the HotSpot heap. Defaults to true if UseJVMCICompiler or " \ + "EnableJVMCI is true and a JVMCI native library is available.") \ \ product(double, JVMCINativeLibraryThreadFraction, 0.33, EXPERIMENTAL, \ "The fraction of compiler threads used by libjvmci. " \ diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 7961e56598f25..2006f340450e5 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -447,7 +447,7 @@ bool Deoptimization::deoptimize_objects_internal(JavaThread* thread, GrowableArr RegisterMap map(chunk->at(0)->register_map()); bool deoptimized_objects = false; - bool const jvmci_enabled = JVMCI_ONLY(UseJVMCICompiler) NOT_JVMCI(false); + bool const jvmci_enabled = JVMCI_ONLY(EnableJVMCI) NOT_JVMCI(false); // Reallocate the non-escaping objects and restore their fields. if (jvmci_enabled COMPILER2_PRESENT(|| (DoEscapeAnalysis && EliminateAllocations) diff --git a/src/hotspot/share/runtime/escapeBarrier.hpp b/src/hotspot/share/runtime/escapeBarrier.hpp index df32deef98639..454e0b555e118 100644 --- a/src/hotspot/share/runtime/escapeBarrier.hpp +++ b/src/hotspot/share/runtime/escapeBarrier.hpp @@ -71,7 +71,7 @@ class EscapeBarrier : StackObj { // Revert ea based optimizations for given deoptee thread EscapeBarrier(bool barrier_active, JavaThread* calling_thread, JavaThread* deoptee_thread) : _calling_thread(calling_thread), _deoptee_thread(deoptee_thread), - _barrier_active(barrier_active && (JVMCI_ONLY(UseJVMCICompiler) NOT_JVMCI(false) + _barrier_active(barrier_active && (JVMCI_ONLY(EnableJVMCI) NOT_JVMCI(false) COMPILER2_PRESENT(|| DoEscapeAnalysis))) { if (_barrier_active) sync_and_suspend_one(); @@ -80,7 +80,7 @@ class EscapeBarrier : StackObj { // Revert ea based optimizations for all java threads EscapeBarrier(bool barrier_active, JavaThread* calling_thread) : _calling_thread(calling_thread), _deoptee_thread(nullptr), - _barrier_active(barrier_active && (JVMCI_ONLY(UseJVMCICompiler) NOT_JVMCI(false) + _barrier_active(barrier_active && (JVMCI_ONLY(EnableJVMCI) NOT_JVMCI(false) COMPILER2_PRESENT(|| DoEscapeAnalysis))) { if (_barrier_active) sync_and_suspend_all(); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index d9b38133f9944..6ca7f42e038f5 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -651,7 +651,7 @@ void SharedRuntime::throw_and_post_jvmti_exception(JavaThread* current, Handle h } #if INCLUDE_JVMCI - if (EnableJVMCI && UseJVMCICompiler) { + if (EnableJVMCI) { vframeStream vfst(current, true); methodHandle method = methodHandle(current, vfst.method()); int bci = vfst.bci(); From 2349bb7ace0c40c0f19dee81b4a86bed0e855043 Mon Sep 17 00:00:00 2001 From: "Todd V. Jonker" Date: Thu, 26 Sep 2024 21:38:08 +0000 Subject: [PATCH 031/188] 8340974: Ambiguous name of jtreg property vm.libgraal.enabled Reviewed-by: dnsimon, phh --- test/hotspot/jtreg/TEST.ROOT | 2 +- test/jtreg-ext/requires/VMProps.java | 7 +++---- test/lib/jdk/test/whitebox/code/Compiler.java | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 74540b6ad45dc..5ed0227068cf6 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -81,7 +81,7 @@ requires.properties= \ vm.jvmti \ vm.graal.enabled \ jdk.hasLibgraal \ - vm.libgraal.enabled \ + vm.libgraal.jit \ vm.compiler1.enabled \ vm.compiler2.enabled \ vm.musl \ diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 5aa703c5b26c2..539a1f23208c3 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -128,8 +128,7 @@ public Map call() { map.put("vm.graal.enabled", this::isGraalEnabled); // jdk.hasLibgraal is true if the libgraal shared library file is present map.put("jdk.hasLibgraal", this::hasLibgraal); - // vm.libgraal.enabled is true if libgraal is used as JIT - map.put("vm.libgraal.enabled", this::isLibgraalEnabled); + map.put("vm.libgraal.jit", this::isLibgraalJIT); map.put("vm.compiler1.enabled", this::isCompiler1Enabled); map.put("vm.compiler2.enabled", this::isCompiler2Enabled); map.put("docker.support", this::dockerSupport); @@ -560,8 +559,8 @@ protected String hasLibgraal() { * * @return true if libgraal is used as JIT compiler. */ - protected String isLibgraalEnabled() { - return "" + Compiler.isLibgraalEnabled(); + protected String isLibgraalJIT() { + return "" + Compiler.isLibgraalJIT(); } /** diff --git a/test/lib/jdk/test/whitebox/code/Compiler.java b/test/lib/jdk/test/whitebox/code/Compiler.java index 2f8447700d57d..69d79ab9d7104 100644 --- a/test/lib/jdk/test/whitebox/code/Compiler.java +++ b/test/lib/jdk/test/whitebox/code/Compiler.java @@ -91,12 +91,12 @@ public static boolean isGraalEnabled() { /** * Check if libgraal is used as JIT compiler. * - * libraal is enabled if isGraalEnabled is true and: + * libraal JIT is enabled if isGraalEnabled is true and: * - UseJVMCINativeLibrary flag is true * * @return true if libgraal is used as JIT compiler. */ - public static boolean isLibgraalEnabled() { + public static boolean isLibgraalJIT() { if (!isGraalEnabled()) { return false; } From e6373b52380b35ed13b5ea308dfd5ade454f0e99 Mon Sep 17 00:00:00 2001 From: Coleen Phillimore Date: Thu, 26 Sep 2024 21:54:30 +0000 Subject: [PATCH 032/188] 8340679: Misc tests fail assert(!set || SafepointSynchronize::is_at_safepoint()) failed: set once or at safepoint Reviewed-by: matsaave, iklam --- .../share/classfile/systemDictionary.cpp | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index bcddddc0c7c78..7b307a0b8a37c 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1069,7 +1069,7 @@ bool SystemDictionary::check_shared_class_super_type(InstanceKlass* klass, Insta } Klass *found = resolve_with_circularity_detection(klass->name(), super_type->name(), - class_loader, protection_domain, is_superclass, CHECK_0); + class_loader, protection_domain, is_superclass, CHECK_false); if (found == super_type) { return true; } else { @@ -1088,16 +1088,21 @@ bool SystemDictionary::check_shared_class_super_types(InstanceKlass* ik, Handle // If unexpected superclass or interfaces are found, we cannot // load from the shared archive. - if (ik->super() != nullptr && - !check_shared_class_super_type(ik, InstanceKlass::cast(ik->super()), - class_loader, protection_domain, true, THREAD)) { - return false; + if (ik->super() != nullptr) { + bool check_super = check_shared_class_super_type(ik, InstanceKlass::cast(ik->super()), + class_loader, protection_domain, true, + CHECK_false); + if (!check_super) { + return false; + } } Array* interfaces = ik->local_interfaces(); int num_interfaces = interfaces->length(); for (int index = 0; index < num_interfaces; index++) { - if (!check_shared_class_super_type(ik, interfaces->at(index), class_loader, protection_domain, false, THREAD)) { + bool check_interface = check_shared_class_super_type(ik, interfaces->at(index), class_loader, protection_domain, false, + CHECK_false); + if (!check_interface) { return false; } } @@ -1153,7 +1158,8 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik, return nullptr; } - if (!check_shared_class_super_types(ik, class_loader, protection_domain, THREAD)) { + bool check = check_shared_class_super_types(ik, class_loader, protection_domain, CHECK_NULL); + if (!check) { ik->set_shared_loading_failed(); return nullptr; } From 1bc13a1c10a580f84f1b7686c95344ec2633f611 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 26 Sep 2024 22:37:45 +0000 Subject: [PATCH 033/188] 8340552: Harden TzdbZoneRulesCompiler against missing zone names Reviewed-by: andrew, jlu, naoto --- .../build/tools/tzdb/TzdbZoneRulesCompiler.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java b/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java index 630d3a390d18a..426d0bb10ede1 100644 --- a/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java +++ b/make/jdk/src/classes/build/tools/tzdb/TzdbZoneRulesCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -273,7 +273,7 @@ private void outputFile(Path dstFile, String version, // link version-region-rules out.writeShort(builtZones.size()); for (Map.Entry entry : builtZones.entrySet()) { - int regionIndex = Arrays.binarySearch(regionArray, entry.getKey()); + int regionIndex = findRegionIndex(regionArray, entry.getKey()); int rulesIndex = rulesList.indexOf(entry.getValue()); out.writeShort(regionIndex); out.writeShort(rulesIndex); @@ -281,8 +281,8 @@ private void outputFile(Path dstFile, String version, // alias-region out.writeShort(links.size()); for (Map.Entry entry : links.entrySet()) { - int aliasIndex = Arrays.binarySearch(regionArray, entry.getKey()); - int regionIndex = Arrays.binarySearch(regionArray, entry.getValue()); + int aliasIndex = findRegionIndex(regionArray, entry.getKey()); + int regionIndex = findRegionIndex(regionArray, entry.getValue()); out.writeShort(aliasIndex); out.writeShort(regionIndex); } @@ -294,6 +294,14 @@ private void outputFile(Path dstFile, String version, } } + private static int findRegionIndex(String[] regionArray, String region) { + int index = Arrays.binarySearch(regionArray, region); + if (index < 0) { + throw new IllegalArgumentException("Unknown region: " + region); + } + return index; + } + /** Whether to output verbose messages. */ private boolean verbose; From 85dba479256a59ea66997d5c408f290e6b5ad384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 27 Sep 2024 06:34:02 +0000 Subject: [PATCH 034/188] 8325090: javadoc fails when -subpackages option is used with non-modular -source Reviewed-by: liach, jjg --- .../javadoc/internal/tool/ElementsTable.java | 12 +-- .../SubpackageNoModules.java | 74 +++++++++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) create mode 100644 test/langtools/jdk/javadoc/tool/subpackageNoModules/SubpackageNoModules.java diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java index a531a987f0d40..0ec72e4ae1cf3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -870,10 +870,12 @@ private List getFiles(ModulePackage modpkg, private ModuleSymbol findModuleOfPackageName(String packageName) { Name pack = names.fromString(packageName); - for (ModuleSymbol msym : modules.allModules()) { - PackageSymbol p = syms.getPackage(msym, pack); - if (p != null && !p.members().isEmpty()) { - return msym; + if (modules.modulesInitialized()) { + for (ModuleSymbol msym : modules.allModules()) { + PackageSymbol p = syms.getPackage(msym, pack); + if (p != null && !p.members().isEmpty()) { + return msym; + } } } return null; diff --git a/test/langtools/jdk/javadoc/tool/subpackageNoModules/SubpackageNoModules.java b/test/langtools/jdk/javadoc/tool/subpackageNoModules/SubpackageNoModules.java new file mode 100644 index 0000000000000..164ec1f19e494 --- /dev/null +++ b/test/langtools/jdk/javadoc/tool/subpackageNoModules/SubpackageNoModules.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8325090 + * @summary javadoc fails when -subpackages option is used with non-modular -source + * @modules jdk.javadoc/jdk.javadoc.internal.api + * jdk.javadoc/jdk.javadoc.internal.tool + * @library /tools/lib + * @build toolbox.TestRunner toolbox.ToolBox + * @run main SubpackageNoModules + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import toolbox.*; +import toolbox.Task.Expect; + +public class SubpackageNoModules extends TestRunner { + + final ToolBox tb = new ToolBox(); + + public SubpackageNoModules() { + super(System.err); + } + + public static void main(String[] args) throws Exception { + SubpackageNoModules t = new SubpackageNoModules(); + t.runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testSubpackageNoModules(Path base) throws Exception { + Files.createDirectories(base); + tb.writeFile(base.resolve("pkg/A.java"), "package pkg;\npublic class A {}\n"); + + Path outDir = base.resolve("out"); + Files.createDirectory(outDir); + // Combine -subpackages option with -source release that doesn't support modules + new JavadocTask(tb) + .outdir(outDir) + .sourcepath(base) + .options("-source", "8", + "-subpackages", "pkg") + .run(Expect.SUCCESS); + // Check for presence of generated docs + if (!Files.isRegularFile(outDir.resolve("pkg/A.html"))) { + error("File not found: " + outDir.resolve("pkg/A.html")); + } + } +} From 2a2ecc994e02049d6d84f083b8e92a51368577bf Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 27 Sep 2024 07:27:29 +0000 Subject: [PATCH 035/188] 8339475: Clean up return code handling for pthread calls in library coding Reviewed-by: clanger, jwaters --- src/java.base/macosx/native/libjli/java_md_macosx.m | 11 +++++++---- src/java.base/unix/native/libjli/java_md_common.c | 8 +------- .../macosx/native/libsplashscreen/splashscreen_sys.m | 6 ++++-- .../unix/native/libsplashscreen/splashscreen_sys.c | 5 ++++- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/java.base/macosx/native/libjli/java_md_macosx.m b/src/java.base/macosx/native/libjli/java_md_macosx.m index c5e7ba580a503..d8742aa1204d5 100644 --- a/src/java.base/macosx/native/libjli/java_md_macosx.m +++ b/src/java.base/macosx/native/libjli/java_md_macosx.m @@ -297,6 +297,7 @@ static void ParkEventLoop() { static void MacOSXStartup(int argc, char *argv[]) { // Thread already started? static jboolean started = false; + int rc; if (started) { return; } @@ -309,12 +310,14 @@ static void MacOSXStartup(int argc, char *argv[]) { // Fire up the main thread pthread_t main_thr; - if (pthread_create(&main_thr, NULL, &apple_main, &args) != 0) { - JLI_ReportErrorMessageSys("Could not create main thread: %s\n", strerror(errno)); + rc = pthread_create(&main_thr, NULL, &apple_main, &args); + if (rc != 0) { + JLI_ReportErrorMessageSys("Could not create main thread, return code: %s\n", rc); exit(1); } - if (pthread_detach(main_thr)) { - JLI_ReportErrorMessageSys("pthread_detach() failed: %s\n", strerror(errno)); + rc = pthread_detach(main_thr); + if (rc != 0) { + JLI_ReportErrorMessage("pthread_detach() failed, return code: %s\n", rc); exit(1); } 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 511519ae362ff..453d605f71082 100644 --- a/src/java.base/unix/native/libjli/java_md_common.c +++ b/src/java.base/unix/native/libjli/java_md_common.c @@ -243,13 +243,7 @@ JLI_ReportErrorMessage(const char* fmt, ...) { JNIEXPORT void JNICALL JLI_ReportErrorMessageSys(const char* fmt, ...) { va_list vl; - char *emsg; - - /* - * TODO: its safer to use strerror_r but is not available on - * Solaris 8. Until then.... - */ - emsg = strerror(errno); + char *emsg = strerror(errno); if (emsg != NULL) { fprintf(stderr, "%s\n", emsg); } diff --git a/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m b/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m index 66e0c362318d7..e74f8ee50fb04 100644 --- a/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m +++ b/src/java.desktop/macosx/native/libsplashscreen/splashscreen_sys.m @@ -271,11 +271,13 @@ static int isInAquaSession() { SplashCreateThread(Splash * splash) { pthread_t thr; pthread_attr_t attr; - int rc; int rslt = pthread_attr_init(&attr); if (rslt != 0) return; - rc = pthread_create(&thr, &attr, SplashScreenThread, (void *) splash); + rslt = pthread_create(&thr, &attr, SplashScreenThread, (void *) splash); + if (rslt != 0) { + fprintf(stderr, "Could not create SplashScreen thread, error number:%d\n", rslt); + } pthread_attr_destroy(&attr); } diff --git a/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c b/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c index 5a008d10a482c..e89d813fff460 100644 --- a/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c +++ b/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c @@ -741,7 +741,10 @@ SplashCreateThread(Splash * splash) { int rslt = pthread_attr_init(&attr); if (rslt != 0) return; - pthread_create(&thr, &attr, SplashScreenThread, (void *) splash); + rslt = pthread_create(&thr, &attr, SplashScreenThread, (void *) splash); + if (rslt != 0) { + fprintf(stderr, "Could not create SplashScreen thread, error number:%d\n", rslt); + } pthread_attr_destroy(&attr); } From 9003e2c519e63fa547e2f072e47f74057094efa2 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 27 Sep 2024 08:28:59 +0000 Subject: [PATCH 036/188] 8341027: Crash in java/runtime/Unsafe/InternalErrorTest when running with -XX:-UseCompressedClassPointers Reviewed-by: aboldtch, coleenp --- test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java b/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java index fcf48a7a2d775..01b051af8e550 100644 --- a/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java +++ b/test/hotspot/jtreg/runtime/Unsafe/InternalErrorTest.java @@ -147,7 +147,8 @@ public static void test(MappedByteBuffer buffer, Unsafe unsafe, long mapAddr, lo break; case 1: // testing Unsafe.copySwapMemory, trying to access next page after truncation. - unsafe.copySwapMemory(null, mapAddr + pageSize, new byte[4000], 16, 2000, 2); + int destOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET; + unsafe.copySwapMemory(null, mapAddr + pageSize, new byte[4000], destOffset, 2000, 2); break; case 2: // testing Unsafe.copySwapMemory, trying to access next page after truncation. From 6587909c7db6482bda92d314096a2a1795900ffd Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 27 Sep 2024 09:44:00 +0000 Subject: [PATCH 037/188] 8341015: OopStorage location decoder crashes accessing non-initalized OopStorage Reviewed-by: kbarrett, tschatzl --- src/hotspot/share/gc/shared/oopStorageSet.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shared/oopStorageSet.cpp b/src/hotspot/share/gc/shared/oopStorageSet.cpp index c6947590d96fb..e3a9fccbad3dc 100644 --- a/src/hotspot/share/gc/shared/oopStorageSet.cpp +++ b/src/hotspot/share/gc/shared/oopStorageSet.cpp @@ -86,7 +86,9 @@ bool OopStorageSet::print_containing(const void* addr, outputStream* st) { if (addr != nullptr) { const void* aligned_addr = align_down(addr, alignof(oop)); for (OopStorage* storage : Range()) { - if (storage->print_containing((oop*) aligned_addr, st)) { + // Check for null for extra safety: might get here while handling error + // before storage initialization. + if ((storage != nullptr) && storage->print_containing((oop*) aligned_addr, st)) { if (aligned_addr != addr) { st->print_cr(" (unaligned)"); } else { From 25e892911dabe32cc0d13b0d4322c5d89585b8f1 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 27 Sep 2024 10:58:10 +0000 Subject: [PATCH 038/188] 8340620: Fix -Wzero-as-null-pointer-constant warnings for CompressedOops Reviewed-by: shade, stefank, mli, amitkumar --- src/hotspot/cpu/ppc/ppc.ad | 8 ++++---- src/hotspot/cpu/s390/s390.ad | 4 ++-- src/hotspot/share/oops/compressedOops.cpp | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 612b7bf898c08..ca9abfa3719b4 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -6598,7 +6598,7 @@ instruct encodeP_not_null_Ex(iRegNdst dst, iRegPsrc src) %{ instruct encodeP_not_null_base_null(iRegNdst dst, iRegPsrc src) %{ match(Set dst (EncodeP src)); predicate(CompressedOops::shift() != 0 && - CompressedOops::base() ==0); + CompressedOops::base() == nullptr); format %{ "SRDI $dst, $src, #3 \t// encodeP, $src != nullptr" %} size(4); @@ -6695,7 +6695,7 @@ instruct decodeN_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ predicate((n->bottom_type()->is_oopptr()->ptr() != TypePtr::NotNull && n->bottom_type()->is_oopptr()->ptr() != TypePtr::Constant) && CompressedOops::shift() != 0 && - CompressedOops::base() != 0); + CompressedOops::base() != nullptr); ins_cost(4 * DEFAULT_COST); // Should be more expensive than decodeN_Disjoint_isel_Ex. effect(TEMP crx); @@ -6707,7 +6707,7 @@ instruct decodeN_Ex(iRegPdst dst, iRegNsrc src, flagsReg crx) %{ instruct decodeN_nullBase(iRegPdst dst, iRegNsrc src) %{ match(Set dst (DecodeN src)); predicate(CompressedOops::shift() != 0 && - CompressedOops::base() == 0); + CompressedOops::base() == nullptr); format %{ "SLDI $dst, $src, #3 \t// DecodeN (zerobased)" %} size(4); @@ -6825,7 +6825,7 @@ instruct decodeN_notNull_addBase_Ex(iRegPdst dst, iRegNsrc src) %{ predicate((n->bottom_type()->is_oopptr()->ptr() == TypePtr::NotNull || n->bottom_type()->is_oopptr()->ptr() == TypePtr::Constant) && CompressedOops::shift() != 0 && - CompressedOops::base() != 0); + CompressedOops::base() != nullptr); ins_cost(2 * DEFAULT_COST); format %{ "DecodeN $dst, $src \t// $src != nullptr, postalloc expanded" %} diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 4de1a4e7b7f35..1bc9484215005 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -4628,7 +4628,7 @@ instruct encodeP(iRegN dst, iRegP src, flagsReg cr) %{ match(Set dst (EncodeP src)); effect(KILL cr); predicate((n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull) && - (CompressedOops::base() == 0 || + (CompressedOops::base() == nullptr || CompressedOops::base_disjoint() || !ExpandLoadingBaseEncode)); ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST); @@ -4651,7 +4651,7 @@ instruct encodeP_NN(iRegN dst, iRegP src, flagsReg cr) %{ match(Set dst (EncodeP src)); effect(KILL cr); predicate((n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull) && - (CompressedOops::base() == 0 || + (CompressedOops::base() == nullptr || CompressedOops::base_disjoint() || !ExpandLoadingBaseEncode_NN)); ins_cost(MEMORY_REF_COST+3 * DEFAULT_COST); diff --git a/src/hotspot/share/oops/compressedOops.cpp b/src/hotspot/share/oops/compressedOops.cpp index 98a4438383a79..ec41dd8521918 100644 --- a/src/hotspot/share/oops/compressedOops.cpp +++ b/src/hotspot/share/oops/compressedOops.cpp @@ -61,7 +61,7 @@ void CompressedOops::initialize(const ReservedHeapSpace& heap_space) { } if ((uint64_t)heap_space.end() <= OopEncodingHeapMax) { // Did reserve heap below 32Gb. Can use base == 0; - set_base(0); + set_base(nullptr); } else { set_base((address)heap_space.compressed_oop_base()); } @@ -115,7 +115,7 @@ CompressedOops::Mode CompressedOops::mode() { return DisjointBaseNarrowOop; } - if (base() != 0) { + if (base() != nullptr) { return HeapBasedNarrowOop; } @@ -166,7 +166,7 @@ void CompressedOops::print_mode(outputStream* st) { st->print(", Compressed Oops mode: %s", mode_to_string(mode())); - if (base() != 0) { + if (base() != nullptr) { st->print(": " PTR_FORMAT, p2i(base())); } From 12de4fbce7a314a1c5c84340526cd65b9a4a29d1 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Fri, 27 Sep 2024 15:02:01 +0000 Subject: [PATCH 039/188] 8340826: Should not send unload notification for scratch classes Reviewed-by: sspitsyn, coleenp --- src/hotspot/share/code/dependencyContext.cpp | 6 +++++- src/hotspot/share/code/dependencyContext.hpp | 3 ++- .../share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp | 3 +++ src/hotspot/share/oops/instanceKlass.cpp | 7 +++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/code/dependencyContext.cpp b/src/hotspot/share/code/dependencyContext.cpp index d7ce8e92acf37..0e6b99d172dcb 100644 --- a/src/hotspot/share/code/dependencyContext.cpp +++ b/src/hotspot/share/code/dependencyContext.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -227,6 +227,10 @@ void DependencyContext::remove_and_mark_for_deoptimization_all_dependents(Deopti } #ifndef PRODUCT +bool DependencyContext::is_empty() { + return dependencies() == nullptr; +} + void DependencyContext::print_dependent_nmethods(bool verbose) { int idx = 0; for (nmethodBucket* b = dependencies_not_unloading(); b != nullptr; b = b->next_not_unloading()) { diff --git a/src/hotspot/share/code/dependencyContext.hpp b/src/hotspot/share/code/dependencyContext.hpp index e8d2ac41d0d1d..13b845cb59dde 100644 --- a/src/hotspot/share/code/dependencyContext.hpp +++ b/src/hotspot/share/code/dependencyContext.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -124,6 +124,7 @@ class DependencyContext : public StackObj { #ifndef PRODUCT void print_dependent_nmethods(bool verbose); + bool is_empty(); #endif //PRODUCT bool is_dependent_nmethod(nmethod* nm); }; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 279b871d8181a..a53eaa474f3f0 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -484,6 +484,9 @@ static void do_primitives() { static void do_unloading_klass(Klass* klass) { assert(klass != nullptr, "invariant"); assert(_subsystem_callback != nullptr, "invariant"); + if (klass->is_instance_klass() && InstanceKlass::cast(klass)->is_scratch_class()) { + return; + } if (JfrKlassUnloading::on_unload(klass)) { _subsystem_callback->do_artifact(klass); } diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index fd198f54fc957..5e226a90764ee 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2721,6 +2721,13 @@ static void clear_all_breakpoints(Method* m) { #endif void InstanceKlass::unload_class(InstanceKlass* ik) { + + if (ik->is_scratch_class()) { + assert(ik->dependencies().is_empty(), "dependencies should be empty for scratch classes"); + return; + } + assert(ik->is_loaded(), "class should be loaded " PTR_FORMAT, p2i(ik)); + // Release dependencies. ik->dependencies().remove_all_dependents(); From 68c4f36857a8ce62731cc73e251e969d48e526ef Mon Sep 17 00:00:00 2001 From: Liam Miller-Cushon Date: Fri, 27 Sep 2024 16:21:05 +0000 Subject: [PATCH 040/188] 8340024: In ClassReader, extract a constant for the superclass supertype_index Reviewed-by: vromero --- .../classes/com/sun/tools/javac/jvm/ClassReader.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 2373f869b0a34..6abf9f057b043 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -2352,6 +2352,12 @@ private TypeAnnotationSymbolVisitor(List attributes) { this.attributes = attributes; } + /** + * A supertype_index value of 65535 specifies that the annotation appears on the superclass + * in an extends clause of a class declaration, see JVMS 4.7.20.1 + */ + public static final int SUPERCLASS_INDEX = 65535; + @Override public Void visitClassSymbol(Symbol.ClassSymbol s, Void unused) { ClassType t = (ClassType) s.type; @@ -2361,7 +2367,7 @@ public Void visitClassSymbol(Symbol.ClassSymbol s, Void unused) { interfaces.add(addTypeAnnotations(itf, classExtends(i++))); } t.interfaces_field = interfaces.toList(); - t.supertype_field = addTypeAnnotations(t.supertype_field, classExtends(65535)); + t.supertype_field = addTypeAnnotations(t.supertype_field, classExtends(SUPERCLASS_INDEX)); if (t.typarams_field != null) { t.typarams_field = rewriteTypeParameters( From 5aae3d40856d92e1e0ff744cb1a0d3421c3dfd5b Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Fri, 27 Sep 2024 16:26:30 +0000 Subject: [PATCH 041/188] 8341096: ProblemList compiler/cha/TypeProfileFinalMethod.java in Xcomp mode Reviewed-by: azvegint --- test/hotspot/jtreg/ProblemList-Xcomp.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index 384374b4f76ce..cb6bb2b4cca58 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -50,6 +50,8 @@ vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 829 vmTestbase/nsk/stress/thread/thread006.java 8321476 linux-all +compiler/cha/TypeProfileFinalMethod.java 8341039 generic-all + gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64 runtime/condy/escapeAnalysis/TestEscapeCondy.java 8339694 generic-all From 824a297aae15ba16cf6d7aded4b95fc9d6bf55e5 Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Fri, 27 Sep 2024 16:57:02 +0000 Subject: [PATCH 042/188] 8341057: Add 2 SSL.com TLS roots Reviewed-by: mullan --- .../share/data/cacerts/ssltlsrootecc2022 | 21 ++++++++++ .../share/data/cacerts/ssltlsrootrsa2022 | 39 +++++++++++++++++++ .../certification/CAInterop.java | 29 ++++++++++++++ .../security/lib/cacerts/VerifyCACerts.java | 13 ++++--- 4 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/java.base/share/data/cacerts/ssltlsrootecc2022 create mode 100644 src/java.base/share/data/cacerts/ssltlsrootrsa2022 diff --git a/src/java.base/share/data/cacerts/ssltlsrootecc2022 b/src/java.base/share/data/cacerts/ssltlsrootecc2022 new file mode 100644 index 0000000000000..706e6aefb4ee0 --- /dev/null +++ b/src/java.base/share/data/cacerts/ssltlsrootecc2022 @@ -0,0 +1,21 @@ +Owner: CN=SSL.com TLS ECC Root CA 2022, O=SSL Corporation, C=US +Issuer: CN=SSL.com TLS ECC Root CA 2022, O=SSL Corporation, C=US +Serial number: 1403f5abfb378b17405be243b2a5d1c4 +Valid from: Thu Aug 25 16:33:48 GMT 2022 until: Sun Aug 19 16:33:47 GMT 2046 +Signature algorithm name: SHA384withECDSA +Subject Public Key Algorithm: 384-bit EC (secp384r1) key +Version: 3 +-----BEGIN CERTIFICATE----- +MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw +CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT +U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2 +MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh +dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG +ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm +acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN +SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME +GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW +uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp +15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN +b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g== +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/ssltlsrootrsa2022 b/src/java.base/share/data/cacerts/ssltlsrootrsa2022 new file mode 100644 index 0000000000000..ad456b0b5f472 --- /dev/null +++ b/src/java.base/share/data/cacerts/ssltlsrootrsa2022 @@ -0,0 +1,39 @@ +Owner: CN=SSL.com TLS RSA Root CA 2022, O=SSL Corporation, C=US +Issuer: CN=SSL.com TLS RSA Root CA 2022, O=SSL Corporation, C=US +Serial number: 6fbedaad73bd0840e28b4dbed4f75b91 +Valid from: Thu Aug 25 16:34:22 GMT 2022 until: Sun Aug 19 16:34:21 GMT 2046 +Signature algorithm name: SHA256withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO +MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD +DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX +DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw +b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC +AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP +L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY +t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins +S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3 +PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO +L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3 +R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w +dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS ++YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS +d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG +AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f +gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j +BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z +NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt +hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM +QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf +R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ +DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW +P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy +lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq +bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w +AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q +r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji +Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU +98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA= +-----END CERTIFICATE----- diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java index ab04391b1f385..924f58cc80f25 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java @@ -535,6 +535,28 @@ * @run main/othervm/manual -Djava.security.debug=certpath CAInterop globalsigne46 CRL */ +/* + * @test id=ssltlsrootecc2022 + * @bug 8341057 + * @summary Interoperability tests with SSL TLS 2022 root CAs + * @library /test/lib + * @build jtreg.SkippedException ValidatePathWithURL CAInterop + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop ssltlsrootecc2022 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop ssltlsrootecc2022 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop ssltlsrootecc2022 CRL + */ + +/* + * @test id=ssltlsrootrsa2022 + * @bug 8341057 + * @summary Interoperability tests with SSL TLS 2022 root CAs + * @library /test/lib + * @build jtreg.SkippedException ValidatePathWithURL CAInterop + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop ssltlsrootrsa2022 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp -Dcom.sun.security.ocsp.useget=false CAInterop ssltlsrootrsa2022 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop ssltlsrootrsa2022 CRL + */ + /** * Collection of certificate validation tests for interoperability with external CAs. * These tests are marked as manual as they depend on external infrastructure and may fail @@ -713,6 +735,13 @@ private CATestURLs getTestURLs(String alias) { new CATestURLs("https://valid.e46.roots.globalsign.com", "https://revoked.e46.roots.globalsign.com"); + case "ssltlsrootecc2022" -> + new CATestURLs("https://test-root-2022-ecc.ssl.com", + "https://revoked-root-2022-ecc.ssl.com"); + case "ssltlsrootrsa2022" -> + new CATestURLs("https://test-root-2022-rsa.ssl.com", + "https://revoked-root-2022-rsa.ssl.com"); + default -> throw new RuntimeException("No test setup found for: " + alias); }; } diff --git a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java index 83427f1a33aba..d64c5d7c52b0b 100644 --- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java +++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java @@ -19,17 +19,16 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ -/** +/* * @test * @bug 8189131 8198240 8191844 8189949 8191031 8196141 8204923 8195774 8199779 * 8209452 8209506 8210432 8195793 8216577 8222089 8222133 8222137 8222136 * 8223499 8225392 8232019 8234245 8233223 8225068 8225069 8243321 8243320 * 8243559 8225072 8258630 8259312 8256421 8225081 8225082 8225083 8245654 * 8305975 8304760 8307134 8295894 8314960 8317373 8317374 8318759 8319187 - * 8321408 8316138 + * 8321408 8316138 8341057 * @summary Check root CA entries in cacerts file */ import java.io.ByteArrayInputStream; @@ -48,12 +47,12 @@ public class VerifyCACerts { + File.separator + "security" + File.separator + "cacerts"; // The numbers of certs now. - private static final int COUNT = 110; + private static final int COUNT = 112; // SHA-256 of cacerts, can be generated with // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 private static final String CHECKSUM - = "BD:80:65:81:68:E5:6C:51:64:ED:B9:08:53:9F:BB:2F:D9:6C:5D:D4:06:D4:16:59:39:10:8E:F8:24:81:8B:78"; + = "21:68:E7:16:5B:94:23:D2:60:5C:BB:F2:AF:C1:66:5C:EC:36:BC:20:FF:5C:54:AF:91:D1:2C:38:AE:55:D3:27"; // Hex formatter to upper case with ":" delimiter private static final HexFormat HEX = HexFormat.ofDelimiter(":").withUpperCase(); @@ -282,6 +281,10 @@ public class VerifyCACerts { "4F:A3:12:6D:8D:3A:11:D1:C4:85:5A:4F:80:7C:BA:D6:CF:91:9D:3A:5A:88:B0:3B:EA:2C:63:72:D9:3C:40:C9"); put("globalsigne46 [jdk]", "CB:B9:C4:4D:84:B8:04:3E:10:50:EA:31:A6:9F:51:49:55:D7:BF:D2:E2:C6:B4:93:01:01:9A:D6:1D:9F:50:58"); + put("ssltlsrootecc2022 [jdk]", + "C3:2F:FD:9F:46:F9:36:D1:6C:36:73:99:09:59:43:4B:9A:D6:0A:AF:BB:9E:7C:F3:36:54:F1:44:CC:1B:A1:43"); + put("ssltlsrootrsa2022 [jdk]", + "8F:AF:7D:2E:2C:B4:70:9B:B8:E0:B3:36:66:BF:75:A5:DD:45:B5:DE:48:0F:8E:A8:D4:BF:E6:BE:BC:17:F2:ED"); } }; From 65200a9589e46956a2194b20c4c90d003351a539 Mon Sep 17 00:00:00 2001 From: Xiaolong Peng Date: Fri, 27 Sep 2024 17:06:18 +0000 Subject: [PATCH 043/188] 8340490: Shenandoah: Optimize ShenandoahPacer Reviewed-by: shade, kdnilsen --- .../share/gc/shenandoah/shenandoahHeap.cpp | 2 +- .../share/gc/shenandoah/shenandoahPacer.cpp | 52 ++++++++----------- .../share/gc/shenandoah/shenandoahPacer.hpp | 4 +- 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 4ab17aabcc5ea..7ae4a1cf8b3dc 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -693,7 +693,7 @@ void ShenandoahHeap::notify_mutator_alloc_words(size_t words, bool waste) { if (ShenandoahPacing) { control_thread()->pacing_notify_alloc(words); if (waste) { - pacer()->claim_for_alloc(words, true); + pacer()->claim_for_alloc(words); } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp b/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp index 0fc6744c15ae7..e67d3d197d42d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp @@ -189,7 +189,8 @@ void ShenandoahPacer::restart_with(size_t non_taxable_bytes, double tax_rate) { _need_notify_waiters.try_set(); } -bool ShenandoahPacer::claim_for_alloc(size_t words, bool force) { +template +bool ShenandoahPacer::claim_for_alloc(size_t words) { assert(ShenandoahPacing, "Only be here when pacing is enabled"); intptr_t tax = MAX2(1, words * Atomic::load(&_tax_rate)); @@ -198,7 +199,7 @@ bool ShenandoahPacer::claim_for_alloc(size_t words, bool force) { intptr_t new_val = 0; do { cur = Atomic::load(&_budget); - if (cur < tax && !force) { + if (cur < tax && !FORCE) { // Progress depleted, alas. return false; } @@ -207,6 +208,9 @@ bool ShenandoahPacer::claim_for_alloc(size_t words, bool force) { return true; } +template bool ShenandoahPacer::claim_for_alloc(size_t words); +template bool ShenandoahPacer::claim_for_alloc(size_t words); + void ShenandoahPacer::unpace_for_alloc(intptr_t epoch, size_t words) { assert(ShenandoahPacing, "Only be here when pacing is enabled"); @@ -227,18 +231,11 @@ void ShenandoahPacer::pace_for_alloc(size_t words) { assert(ShenandoahPacing, "Only be here when pacing is enabled"); // Fast path: try to allocate right away - bool claimed = claim_for_alloc(words, false); + bool claimed = claim_for_alloc(words); if (claimed) { return; } - // Forcefully claim the budget: it may go negative at this point, and - // GC should replenish for this and subsequent allocations. After this claim, - // we would wait a bit until our claim is matched by additional progress, - // or the time budget depletes. - claimed = claim_for_alloc(words, true); - assert(claimed, "Should always succeed"); - // Threads that are attaching should not block at all: they are not // fully initialized yet. Blocking them would be awkward. // This is probably the path that allocates the thread oop itself. @@ -249,32 +246,25 @@ void ShenandoahPacer::pace_for_alloc(size_t words) { JavaThread* current = JavaThread::current(); if (current->is_attaching_via_jni() || !current->is_active_Java_thread()) { + claim_for_alloc(words); return; } - double start = os::elapsedTime(); - - size_t max_ms = ShenandoahPacingMaxDelay; - size_t total_ms = 0; - - while (true) { + jlong const max_delay = ShenandoahPacingMaxDelay * NANOSECS_PER_MILLISEC; + jlong const start_time = os::elapsed_counter(); + while (!claimed && (os::elapsed_counter() - start_time) < max_delay) { // We could instead assist GC, but this would suffice for now. - size_t cur_ms = (max_ms > total_ms) ? (max_ms - total_ms) : 1; - wait(cur_ms); - - double end = os::elapsedTime(); - total_ms = (size_t)((end - start) * 1000); - - if (total_ms > max_ms || Atomic::load(&_budget) >= 0) { - // Exiting if either: - // a) Spent local time budget to wait for enough GC progress. - // Breaking out and allocating anyway, which may mean we outpace GC, - // and start Degenerated GC cycle. - // b) The budget had been replenished, which means our claim is satisfied. - ShenandoahThreadLocalData::add_paced_time(JavaThread::current(), end - start); - break; - } + wait(1); + claimed = claim_for_alloc(words); + } + if (!claimed) { + // Spent local time budget to wait for enough GC progress. + // Force allocating anyway, which may mean we outpace GC, + // and start Degenerated GC cycle. + claimed = claim_for_alloc(words); + assert(claimed, "Should always succeed"); } + ShenandoahThreadLocalData::add_paced_time(current, (double)(os::elapsed_counter() - start_time) / NANOSECS_PER_SEC); } void ShenandoahPacer::wait(size_t time_ms) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp b/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp index 1c2bf00eb56ba..44ad2700f8704 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahPacer.hpp @@ -107,7 +107,9 @@ class ShenandoahPacer : public CHeapObj { inline void report_alloc(size_t words); - bool claim_for_alloc(size_t words, bool force); + template + bool claim_for_alloc(size_t words); + void pace_for_alloc(size_t words); void unpace_for_alloc(intptr_t epoch, size_t words); From f554c3ffce7599fdb535b03db4a6ea96870b3c2d Mon Sep 17 00:00:00 2001 From: Rajan Halade Date: Fri, 27 Sep 2024 17:16:13 +0000 Subject: [PATCH 044/188] 8341059: Change Entrust TLS distrust date to November 12, 2024 Reviewed-by: mullan --- .../classes/sun/security/validator/CADistrustPolicy.java | 2 +- .../classes/sun/security/validator/EntrustTLSPolicy.java | 8 ++++---- src/java.base/share/conf/security/java.security | 2 +- .../ssl/X509TrustManagerImpl/distrust/Entrust.java | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java b/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java index 0b27a13e17f58..17b9e7248c06c 100644 --- a/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java +++ b/src/java.base/share/classes/sun/security/validator/CADistrustPolicy.java @@ -57,7 +57,7 @@ void checkDistrust(String variant, X509Certificate[] chain) /** * Distrust TLS Server certificates anchored by an Entrust root CA and - * issued after October 31, 2024. If enabled, this policy is currently + * issued after November 11, 2024. If enabled, this policy is currently * enforced by the PKIX and SunX509 TrustManager implementations * of the SunJSSE provider implementation. */ diff --git a/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java b/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java index 49b75627fd880..4c4906d8eb398 100644 --- a/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java +++ b/src/java.base/share/classes/sun/security/validator/EntrustTLSPolicy.java @@ -88,8 +88,8 @@ final class EntrustTLSPolicy { // Any TLS Server certificate that is anchored by one of the Entrust // roots above and is issued after this date will be distrusted. - private static final LocalDate OCTOBER_31_2024 = - LocalDate.of(2024, Month.OCTOBER, 31); + private static final LocalDate NOVEMBER_11_2024 = + LocalDate.of(2024, Month.NOVEMBER, 11); /** * This method assumes the eeCert is a TLS Server Cert and chains back to @@ -111,8 +111,8 @@ static void checkDistrust(X509Certificate[] chain) Date notBefore = chain[0].getNotBefore(); LocalDate ldNotBefore = LocalDate.ofInstant(notBefore.toInstant(), ZoneOffset.UTC); - // reject if certificate is issued after October 31, 2024 - checkNotBefore(ldNotBefore, OCTOBER_31_2024, anchor); + // reject if certificate is issued after November 11, 2024 + checkNotBefore(ldNotBefore, NOVEMBER_11_2024, anchor); } } diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 9651ae2d373d4..9d07cb85a47ca 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1358,7 +1358,7 @@ jdk.sasl.disabledMechanisms= # Distrust after December 31, 2019. # # ENTRUST_TLS : Distrust TLS Server certificates anchored by -# an Entrust root CA and issued after October 31, 2024. +# an Entrust root CA and issued after November 11, 2024. # # Leading and trailing whitespace surrounding each value are ignored. # Unknown values are ignored. If the property is commented out or set to the diff --git a/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java index 07127742ff6c4..809674e8f209c 100644 --- a/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java +++ b/test/jdk/sun/security/ssl/X509TrustManagerImpl/distrust/Entrust.java @@ -28,7 +28,7 @@ /** * @test - * @bug 8337664 + * @bug 8337664 8341059 * @summary Check that TLS Server certificates chaining back to distrusted * Entrust roots are invalid * @library /test/lib @@ -52,7 +52,7 @@ public class Entrust { // Date when the restrictions take effect private static final ZonedDateTime DISTRUST_DATE = - LocalDate.of(2024, 11, 1).atStartOfDay(ZoneOffset.UTC); + LocalDate.of(2024, 11, 12).atStartOfDay(ZoneOffset.UTC); public static void main(String[] args) throws Exception { Distrust distrust = new Distrust(args); From a7bfced60540fe8d4fa7360bff512337ea47b890 Mon Sep 17 00:00:00 2001 From: Yagmur Eren Date: Fri, 27 Sep 2024 17:36:48 +0000 Subject: [PATCH 045/188] 8337679: Memset warning in src/hotspot/share/adlc/adlArena.cpp Reviewed-by: stefank, thartmann, jwaters --- src/hotspot/share/adlc/adlArena.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hotspot/share/adlc/adlArena.cpp b/src/hotspot/share/adlc/adlArena.cpp index d5a1dd500fa66..ebd1f74911d57 100644 --- a/src/hotspot/share/adlc/adlArena.cpp +++ b/src/hotspot/share/adlc/adlArena.cpp @@ -63,8 +63,6 @@ void AdlChunk::chop() { AdlChunk *k = this; while( k ) { AdlChunk *tmp = k->_next; - // clear out this chunk (to detect allocation bugs) - memset(k, 0xBE, k->_len); free(k); // Free chunk (was malloc'd) k = tmp; } From 082125d61e4b7e0fd53528c0271ca8be621f242b Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Fri, 27 Sep 2024 18:26:08 +0000 Subject: [PATCH 046/188] 8340404: CharsetProvider specification updates Reviewed-by: alanb, naoto --- .../java/nio/charset/spi/CharsetProvider.java | 32 ++++++--- .../spi/CharsetProviderAsModuleTest.java | 60 ++++++++++++++++ .../nio/charset/spi/provider/module-info.java | 25 +++++++ .../charset/spi/provider/spi/BazProvider.java | 71 +++++++++++++++++++ 4 files changed, 178 insertions(+), 10 deletions(-) create mode 100644 test/jdk/java/nio/charset/spi/CharsetProviderAsModuleTest.java create mode 100644 test/jdk/java/nio/charset/spi/provider/module-info.java create mode 100644 test/jdk/java/nio/charset/spi/provider/spi/BazProvider.java diff --git a/src/java.base/share/classes/java/nio/charset/spi/CharsetProvider.java b/src/java.base/share/classes/java/nio/charset/spi/CharsetProvider.java index 11d36ee242d56..114558d93927f 100644 --- a/src/java.base/share/classes/java/nio/charset/spi/CharsetProvider.java +++ b/src/java.base/share/classes/java/nio/charset/spi/CharsetProvider.java @@ -33,17 +33,29 @@ * Charset service-provider class. * *

      A charset provider is a concrete subclass of this class that has a - * zero-argument constructor and some number of associated charset - * implementation classes. Charset providers may be installed in an instance - * of the Java platform as extensions. Providers may also be made available by - * adding them to the application class path or by some other - * platform-specific means. Charset providers are looked up via the current - * thread's {@link java.lang.Thread#getContextClassLoader() context class - * loader}. + * zero-argument constructor and some number of associated {@code Charset} + * implementation classes. Charset providers are deployed on the application + * module path or the application class path. In order to be looked up, charset + * providers must be visible to the {@link ClassLoader#getSystemClassLoader() system + * class loader}. See {@link java.util.ServiceLoader##developing-service-providers + * Deploying Service Providers} for further detail on deploying a charset + * provider as a module or on the class path. * - *

      A charset provider identifies itself with a provider-configuration file - * named {@code java.nio.charset.spi.CharsetProvider} in the resource - * directory {@code META-INF/services}. The file should contain a list of + *

      For a charset provider deployed in a module, the provides + * directive must be specified in the module declaration. The provides directive + * specifies both the service and the service provider. In this case, the service + * is {@code java.nio.charset.spi.CharsetProvider}. + * + *

      As an example, a charset provider deployed as a module might specify the + * following directive: + *

      {@code
      + *     provides java.nio.charset.spi.CharsetProvider with com.example.ExternalCharsetProvider;
      + * }
      + * + *

      For a charset provider deployed on the class path, it identifies itself + * with a provider-configuration file named {@code + * java.nio.charset.spi.CharsetProvider} in the resource directory + * {@code META-INF/services}. The file should contain a list of * fully-qualified concrete charset-provider class names, one per line. A line * is terminated by any one of a line feed ({@code '\n'}), a carriage return * ({@code '\r'}), or a carriage return followed immediately by a line feed. diff --git a/test/jdk/java/nio/charset/spi/CharsetProviderAsModuleTest.java b/test/jdk/java/nio/charset/spi/CharsetProviderAsModuleTest.java new file mode 100644 index 0000000000000..ba6aae234c6dc --- /dev/null +++ b/test/jdk/java/nio/charset/spi/CharsetProviderAsModuleTest.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8340404 + * @summary Check that a CharsetProvider SPI can be deployed as a module + * @build provider/* + * @run main/othervm CharsetProviderAsModuleTest + */ + +import java.nio.charset.Charset; + +public class CharsetProviderAsModuleTest { + + // Basic test ensures that our BAZ charset is loaded via the BazProvider + public static void main(String[] args) { + var cs = Charset.availableCharsets(); + Charset bazCs; + // check provider is providing BAZ via charsets() + if (!cs.containsKey("BAZ")) { + throw new RuntimeException("SPI BazProvider did not provide BAZ Charset"); + } else { + bazCs = cs.get("BAZ"); + // check provider is in a named module + if (!bazCs.getClass().getModule().isNamed()) { + throw new RuntimeException("BazProvider is not a named module"); + } + var aliases = bazCs.aliases(); + // check BAZ cs aliases were loaded correctly + if (!aliases.contains("BAZ-1") || !aliases.contains("BAZ-2")) { + throw new RuntimeException("BAZ Charset did not provide correct aliases"); + } + // check provider implements charsetForName() + if (!bazCs.equals(Charset.forName("BAZ"))) { + throw new RuntimeException("SPI BazProvider provides bad charsetForName()"); + } + } + } +} diff --git a/test/jdk/java/nio/charset/spi/provider/module-info.java b/test/jdk/java/nio/charset/spi/provider/module-info.java new file mode 100644 index 0000000000000..5cfe6db92db9f --- /dev/null +++ b/test/jdk/java/nio/charset/spi/provider/module-info.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +module provider { + provides java.nio.charset.spi.CharsetProvider with spi.BazProvider; +} diff --git a/test/jdk/java/nio/charset/spi/provider/spi/BazProvider.java b/test/jdk/java/nio/charset/spi/provider/spi/BazProvider.java new file mode 100644 index 0000000000000..7def239e64c0f --- /dev/null +++ b/test/jdk/java/nio/charset/spi/provider/spi/BazProvider.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package spi; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.spi.CharsetProvider; +import java.util.Collections; +import java.util.Iterator; + +// Provides some simple BAZ related attributes to our provider +public class BazProvider extends CharsetProvider { + + @Override + public Iterator charsets() { + return Collections.singleton(new BazCharset()).iterator(); + } + + @Override + public Charset charsetForName(String charsetName) { + if (charsetName.equals("BAZ")) { + return new BazCharset(); + } else { + return null; + } + } + + public static class BazCharset extends Charset { + + public BazCharset() { + super("BAZ", new String[] { "BAZ-1", "BAZ-2" }); + } + + // Overrides to satisfy Charset + @Override + public boolean contains(Charset cs) { + return false; + } + + @Override + public CharsetDecoder newDecoder() { + return null; + } + + @Override + public CharsetEncoder newEncoder() { + return null; + } + } +} From ed140f5d5e2dec1217e2efbee815d84306de0563 Mon Sep 17 00:00:00 2001 From: Boris Ulasevich Date: Fri, 27 Sep 2024 23:11:41 +0000 Subject: [PATCH 047/188] 8341101: [ARM32] Error: ShouldNotReachHere() in TemplateInterpreterGenerator::generate_math_entry after 8338694 Reviewed-by: shade --- src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index 679f07a028e2c..ec9d237e50da0 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -175,6 +175,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M break; case Interpreter::java_lang_math_fmaD: case Interpreter::java_lang_math_fmaF: + case Interpreter::java_lang_math_tanh: // TODO: Implement intrinsic break; default: From 73ebb848fdb66861e912ea747c039ddd1f7a5f48 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 27 Sep 2024 23:34:04 +0000 Subject: [PATCH 048/188] 8340721: Clarify special case handling of unboxedType and getWildcardType Reviewed-by: prappo, mcimadamore --- .../classes/javax/lang/model/util/Types.java | 14 +- .../model/util/types/TestInvalidInputs.java | 184 ++++++++++++++++++ 2 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java index 266d63178ba08..232e15a84bd6a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java @@ -50,6 +50,11 @@ *

      Compatibility Note: Methods may be added to this interface * in future releases of the platform. * + * @apiNote + * In the reference implementation, handling {@linkplain ErrorType + * error types} generally does not cause an {@code + * IllegalArgumentException} from the methods in this interface. + * * @see javax.annotation.processing.ProcessingEnvironment#getTypeUtils * @since 1.6 */ @@ -198,8 +203,10 @@ public interface Types { * * @param t the type to be unboxed * @return the type of an unboxed value of type {@code t} + * * @throws IllegalArgumentException if the given type has no - * unboxing conversion + * unboxing conversion. Only types for the wrapper classes + * have an unboxing conversion. * @jls 5.1.8 Unboxing Conversion */ PrimitiveType unboxedType(TypeMirror t); @@ -268,7 +275,10 @@ public interface Types { * * @param extendsBound the extends (upper) bound, or {@code null} if none * @param superBound the super (lower) bound, or {@code null} if none - * @throws IllegalArgumentException if bounds are not valid + * + * @throws IllegalArgumentException if bounds are not valid. Invalid bounds + * include all types that are not {@linkplain ReferenceType + * reference types}. * @jls 4.5.1 Type Arguments of Parameterized Types */ WildcardType getWildcardType(TypeMirror extendsBound, diff --git a/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java b/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java new file mode 100644 index 0000000000000..3cc1e246e41d9 --- /dev/null +++ b/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8340721 + * @summary Test invalid inputs to javax.lang.model.util.Types methods + * @library /tools/javac/lib + * @modules java.compiler + * @build JavacTestingAbstractProcessor TestInvalidInputs + * @compile -processor TestInvalidInputs -proc:only TestInvalidInputs.java + */ + +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; + +/** + * Test if exceptions are thrown for invalid arguments as expected. + */ +public class TestInvalidInputs extends JavacTestingAbstractProcessor { + + // Reference types are ArrayType, DeclaredType, ErrorType, NullType, and TypeVariable + + private TypeMirror objectType; // Notable DeclaredType + private TypeMirror stringType; // Another notable DeclaredType + private ArrayType arrayType; + // private ErrorType errorType; // skip for now + private ExecutableType executableType; + private IntersectionType intersectionType; + + private NoType noTypeVoid; + private NoType noTypeNone; + private NoType noTypePackage; + private NoType noTypeModule; + + private NullType nullType; + private PrimitiveType primitiveType; + private UnionType unionType; + private WildcardType wildcardType; + + /** + * Check expected behavior on classes and packages. + */ + public boolean process(Set annotations, + RoundEnvironment roundEnv) { + if (!roundEnv.processingOver()) { + initializeTypes(); + testUnboxedType(); + testGetWildcardType(); + } + return true; + } + + void initializeTypes() { + objectType = elements.getTypeElement("java.lang.Object").asType(); + stringType = elements.getTypeElement("java.lang.String").asType(); + + arrayType = types.getArrayType(objectType); // Object[] + executableType = extractExecutableType(); + intersectionType = extractIntersectionType(); + + noTypeVoid = types.getNoType(TypeKind.VOID); + noTypeNone = types.getNoType(TypeKind.NONE); + noTypePackage = (NoType)(elements.getPackageElement("java.lang").asType()); + noTypeModule = (NoType)(elements.getModuleElement("java.base").asType()); + + nullType = types.getNullType(); + primitiveType = types.getPrimitiveType(TypeKind.DOUBLE); + // unionType; // more work here + wildcardType = types.getWildcardType(objectType, null); + + return; + } + + ExecutableType extractExecutableType() { + var typeElement = elements.getTypeElement("TestInvalidInputs.InvalidInputsHost"); + for (var method : ElementFilter.methodsIn(typeElement.getEnclosedElements())) { + if ("foo7".equals(method.getSimpleName().toString())) { + return (ExecutableType)method.asType(); + } + } + throw new RuntimeException("Expected method not found"); + } + + IntersectionType extractIntersectionType() { + var typeElement = elements.getTypeElement("TestInvalidInputs.InvalidInputsHost"); + for (var method : ElementFilter.methodsIn(typeElement.getEnclosedElements())) { + if ("foo9".equals(method.getSimpleName().toString())) { + return (IntersectionType) ((TypeVariable)method.getReturnType()).getUpperBound(); + } + } + throw new RuntimeException("Expected method not found"); + } + + /* + * Class to host inputs for testing. + */ + class InvalidInputsHost { + // Use a method to get an ExecutableType + public static String foo7(int arg) {return null;} + + // Type variable with intersection type + public static S foo9() {return null;} + } + + /** + * @throws IllegalArgumentException if the given type has no + * unboxing conversion, including for types that are not + * {@linkplain ReferenceType reference types} + */ + void testUnboxedType() { + // Only DeclaredType's for wrapper classes should have unboxing conversions defined. + + // Reference types are ArrayType, DeclaredType, ErrorType, NullType, TypeVariable + // non-reference: ExecutableType, IntersectionType, NoType, PrimitiveType, UnionType, WildcardType + var invalidInputs = List.of(objectType, stringType, arrayType, + executableType, intersectionType, + noTypeVoid, noTypeNone, noTypePackage, noTypeModule, nullType, + primitiveType, /*unionType, */ wildcardType); + + for (TypeMirror tm : invalidInputs) { + try { + PrimitiveType pt = types.unboxedType(tm); + throw new RuntimeException("Should not reach " + tm); + } catch(IllegalArgumentException iae) { + ; // Expected + } + } + return; + } + + /** + * @throws IllegalArgumentException if bounds are not valid, + * including for types that are not {@linkplain ReferenceType + * reference types} + */ + void testGetWildcardType() { + // Reference types are ArrayType, DeclaredType, ErrorType, NullType, TypeVariable + // non-reference: ExecutableType, IntersectionType, NoType, PrimitiveType, UnionType, WildcardType + var invalidInputs = List.of(executableType, intersectionType, + noTypeVoid, noTypeNone, noTypePackage, noTypeModule, nullType, + primitiveType, /*unionType, */ wildcardType); + + for (TypeMirror tm : invalidInputs) { + try { + WildcardType wc1 = types.getWildcardType(tm, null); + throw new RuntimeException("Should not reach " + tm); + } catch(IllegalArgumentException iae) { + ; // Expected + } + + try { + WildcardType wc2 = types.getWildcardType(null, tm); + throw new RuntimeException("Should not reach " + tm); + } catch(IllegalArgumentException iae) { + ; // Expected + } + } + return; + } +} From ade17ecb6cb5125d048401a878b557e5afefc08c Mon Sep 17 00:00:00 2001 From: Phil Race Date: Sun, 29 Sep 2024 17:05:01 +0000 Subject: [PATCH 049/188] 8340560: Open Source several AWT/2D font and rendering tests Reviewed-by: kizune --- test/jdk/sun/awt/font/CacheFlushTest.java | 106 ++++++++++ test/jdk/sun/awt/font/TestArabicHebrew.java | 215 ++++++++++++++++++++ test/jdk/sun/awt/font/TestDevTransform.java | 155 ++++++++++++++ test/jdk/sun/awt/windows/TestPen.java | 102 ++++++++++ 4 files changed, 578 insertions(+) create mode 100644 test/jdk/sun/awt/font/CacheFlushTest.java create mode 100644 test/jdk/sun/awt/font/TestArabicHebrew.java create mode 100644 test/jdk/sun/awt/font/TestDevTransform.java create mode 100644 test/jdk/sun/awt/windows/TestPen.java diff --git a/test/jdk/sun/awt/font/CacheFlushTest.java b/test/jdk/sun/awt/font/CacheFlushTest.java new file mode 100644 index 0000000000000..f3b3293127530 --- /dev/null +++ b/test/jdk/sun/awt/font/CacheFlushTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4286726 + * @summary Java2D raster printing: large text may overflow glyph cache. + * Draw a large glyphvector, the 'A' glyph should appear and not get flushed. +*/ + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.Point2D; +import java.awt.image.BufferedImage; +import java.util.HashMap; + +/** + * Draw a very large glyphvector on a surface. + * If the cache was flushed the first glyph is not rendered. + * Note: the implementation no longer uses glyphs for rendering large text, + * but in principle the test is still useful. + */ +public class CacheFlushTest { + + static final int WIDTH = 400, HEIGHT = 600; + static final int FONTSIZE = 250; + static final String TEST = "ABCDEFGHIJKLMNOP"; + static final HashMap HINTS = new HashMap<>(); + + static { + HINTS.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + HINTS.put(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + HINTS.put(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); + } + + public static void main(String args[]) { + BufferedImage bi = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); + + Graphics2D g2d = bi.createGraphics(); + g2d.addRenderingHints(HINTS); + g2d.setColor(Color.white); + g2d.fillRect(0, 0, WIDTH, HEIGHT); + g2d.setColor(Color.black); + + FontRenderContext frc = g2d.getFontRenderContext(); + Font font = new Font(Font.DIALOG, Font.PLAIN, 250); + GlyphVector gv = font.createGlyphVector(frc, TEST); + + /* Set the positions of all but the first glyph to be offset vertically but + * FONTSIZE pixels. So if the first glyph "A" is not flushed we can tell this + * by checking for non-white pixels in the range for the default y offset of 0 + * from the specified y location. + */ + Point2D.Float pt = new Point2D.Float(20f, FONTSIZE); + for (int i = 1; i < gv.getNumGlyphs(); ++i) { + gv.setGlyphPosition(i, pt); + pt.x += 25f; + pt.y = FONTSIZE; + } + g2d.drawGlyphVector(gv, 20, FONTSIZE); + /* Now expect to find at least one black pixel in the rect (0,0) -> (WIDTH, FONTSIZE) */ + boolean found = false; + int blackPixel = Color.black.getRGB(); + for (int y = 0; y < FONTSIZE; y++) { + for (int x = 0; x < WIDTH; x++) { + if (bi.getRGB(x, y) == blackPixel) { + found = true; + break; + } + } + if (found == true) { + break; + } + } + if (!found) { + throw new RuntimeException("NO BLACK PIXELS"); + } + } +} diff --git a/test/jdk/sun/awt/font/TestArabicHebrew.java b/test/jdk/sun/awt/font/TestArabicHebrew.java new file mode 100644 index 0000000000000..61cbe931c32c4 --- /dev/null +++ b/test/jdk/sun/awt/font/TestArabicHebrew.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4198081 + * @key headful + * @summary Arabic characters should appear instead of boxes and be correctly shaped. + * Hebrew characters should appear instead of boxes. + * Test is made headful so there's no excuse for test systems not having the fonts. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.Rectangle2D; + +public class TestArabicHebrew extends Panel { + + static volatile Frame frame; + static volatile Font font = new Font(Font.DIALOG, Font.PLAIN, 36); + + static void createUI() { + frame = new Frame("Test Arabic/Hebrew"); + frame.setLayout(new BorderLayout()); + TestArabicHebrew panel = new TestArabicHebrew(); + frame.add(panel, BorderLayout.CENTER); + frame.pack(); + frame.setVisible(true); + } + + public static void main(String args[]) throws Exception { + EventQueue.invokeAndWait(TestArabicHebrew::createUI); + try { + checkStrings(); + } finally { + if (frame != null && args.length == 0) { + EventQueue.invokeAndWait(frame::dispose); + } + } + } + + static void checkString(String script, String str) { + int index = font.canDisplayUpTo(str); + if (index != -1) { + throw new RuntimeException("Cannot display char " + index + " for " + script); + } + } + + static void checkStrings() { + checkString("Arabic", arabic); + checkString("Hebrew", hebrew); + checkString("Latin-1 Supplement", latin1sup); + } + + // Table of arabic unicode characters - minimal support level + // Includes arabic chars from basic block up to 0652 and + // corresponding shaped characters from the arabic + // extended-B block from fe80 to fefc (does include lam-alef + // ligatures). + // Does not include arabic-indic digits nor "arabic extended" + // range. + + static final String arabic = + "\u060c\u061b\u061f\u0621\u0622\u0623\u0624\u0625\u0626\u0627" + + "\u0628\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631" + + "\u0632\u0633\u0634\u0635\u0636\u0637\u0638\u0639\u063a\u0640" + + "\u0641\u0642\u0643\u0644\u0645\u0646\u0647\u0648\u0649\u064a" + + "\u064b\u064c\u064d\u064e\u064f\u0650\u0651\u0652\ufe80\ufe81" + + "\ufe82\ufe83\ufe84\ufe85\ufe86\ufe87\ufe88\ufe89\ufe8a\ufe8b" + + "\ufe8c\ufe8d\ufe8e\ufe8f\ufe90\ufe91\ufe92\ufe93\ufe94\ufe95" + + "\ufe96\ufe97\ufe98\ufe99\ufe9a\ufe9b\ufe9c\ufe9d\ufe9e\ufe9f" + + "\ufea0\ufea1\ufea2\ufea3\ufea4\ufea5\ufea6\ufea7\ufea8\ufea9" + + "\ufeaa\ufeab\ufeac\ufead\ufeae\ufeaf\ufeb0\ufeb1\ufeb2\ufeb3" + + "\ufeb4\ufeb5\ufeb6\ufeb7\ufeb8\ufeb9\ufeba\ufebb\ufebc\ufebd" + + "\ufebe\ufebf\ufec0\ufec1\ufec2\ufec3\ufec4\ufec5\ufec6\ufec7" + + "\ufec8\ufec9\ufeca\ufecb\ufecc\ufecd\ufece\ufecf\ufed0\ufed1" + + "\ufed2\ufed3\ufed4\ufed5\ufed6\ufed7\ufed8\ufed9\ufeda\ufedb" + + "\ufedc\ufedd\ufede\ufedf\ufee0\ufee1\ufee2\ufee3\ufee4\ufee5" + + "\ufee6\ufee7\ufee8\ufee9\ufeea\ufeeb\ufeec\ufeed\ufeee\ufeef" + + "\ufef0\ufef1\ufef2\ufef3\ufef4\ufef5\ufef6\ufef7\ufef8\ufef9" + + "\ufefa\ufefb\ufefc"; + + // hebrew table includes all characters in hebrew block + + static final String hebrew = + "\u0591\u0592\u0593\u0594\u0595\u0596\u0597\u0598\u0599\u059a" + + "\u059b\u059c\u059d\u059e\u059f\u05a0\u05a1\u05a3\u05a4\u05a5" + + "\u05a6\u05a7\u05a8\u05a9\u05aa\u05ab\u05ac\u05ad\u05ae\u05af" + + "\u05b0\u05b1\u05b2\u05b3\u05b4\u05b5\u05b6\u05b7\u05b8\u05b9" + + "\u05bb\u05bc\u05bd\u05be\u05bf\u05c0\u05c1\u05c2\u05c3\u05c4" + + "\u05d0\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9" + + "\u05da\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3" + + "\u05e4\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\u05f0\u05f1\u05f2" + + "\u05f3\u05f4"; + + // latin 1 supplement table includes all non-control characters + // in this range. Included because of comment in code that claims + // some problems displaying this range with some SJIS fonts. + + static final String latin1sup = + "\u00a0\u00a1\u00a2\u00a3\u00a4\u00a5\u00a6\u00a7" + + "\u00a8\u00a9\u00aa\u00ab\u00ac\u00ad\u00ae\u00af\u00b0\u00b1" + + "\u00b2\u00b3\u00b4\u00b5\u00b6\u00b7\u00b8\u00b9\u00ba\u00bb" + + "\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5" + + "\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf" + + "\u00d0\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9" + + "\u00da\u00db\u00dc\u00dd\u00de\u00df\u00e0\u00e1\u00e2\u00e3" + + "\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed" + + "\u00ee\u00ef\u00f0\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7" + + "\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u00fe\u00ff"; + + public TestArabicHebrew() { + setLayout(new GridLayout(3, 1)); + + FontRenderContext frc = new FontRenderContext(null, false, false); + add(new SubGlyphPanel("Arabic", arabic, font, frc)); + add(new SubGlyphPanel("Hebrew", hebrew, font, frc)); + add(new SubGlyphPanel("Latin-1 Supplement", latin1sup, font, frc)); + } + + static class SubGlyphPanel extends Panel { + String title; + Dimension extent; + GlyphVector[] vectors; + + static final int kGlyphsPerLine = 20; + + SubGlyphPanel(String title, String chars, Font font, FontRenderContext frc) { + + this.title = title; + setBackground(Color.white); + + double width = 0; + double height = 0; + + int max = chars.length(); + vectors = new GlyphVector[(max + kGlyphsPerLine - 1) / kGlyphsPerLine]; + for (int i = 0; i < vectors.length; i++) { + int start = i * 20; + int limit = Math.min(max, (i + 1) * kGlyphsPerLine); + String substr = ""; + for (int j = start; j < limit; ++j) { + substr = substr.concat(chars.charAt(j) + " "); + } + GlyphVector gv = font.createGlyphVector(frc, substr); + vectors[i] = gv; + Rectangle2D bounds = gv.getLogicalBounds(); + + width = Math.max(width, bounds.getWidth()); + height += bounds.getHeight(); + } + + extent = new Dimension((int)(width + 1), (int)(height + 1 + 30)); // room for title + + setSize(getPreferredSize()); + } + + public Dimension getPreferredSize() { + return new Dimension(extent); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public Dimension getMaximumSize() { + return getPreferredSize(); + } + + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D)g; + + g.drawString(title, 10, 20); + + float x = 10; + float y = 30; + for (int i = 0; i < vectors.length; ++i) { + GlyphVector gv = vectors[i]; + Rectangle2D bounds = gv.getLogicalBounds(); + g2d.drawGlyphVector(gv, x, (float)(y - bounds.getY())); + y += bounds.getHeight(); + } + } + } +} diff --git a/test/jdk/sun/awt/font/TestDevTransform.java b/test/jdk/sun/awt/font/TestDevTransform.java new file mode 100644 index 0000000000000..035cb0b13d73a --- /dev/null +++ b/test/jdk/sun/awt/font/TestDevTransform.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4269775 + * @summary Check that different text rendering APIs agree + */ + +/** + * Draw into an image rendering the same text string nine different + * ways: as a TextLayout, a simple String, and a GlyphVector, each + * with three different x scale factors. The expectation is that each + * set of three strings would appear the same although offset in y to + * avoid overlap. The bug was that the y positions of the individual characters + * of the TextLayout and GlyphVector were wrong, so the strings appeared + * to be rendered at different angles. + */ + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.util.HashMap; + +public class TestDevTransform { + + static HashMap hints = new HashMap<>(); + + static { + hints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + hints.put(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); + } + + static String test = "This is only a test"; + static double angle = Math.PI / 6.0; // Rotate 30 degrees + static final int W = 400, H = 400; + + static void draw(Graphics2D g2d, TextLayout layout, + float x, float y, float scalex) { + AffineTransform saveTransform = g2d.getTransform(); + g2d.translate(x, y); + g2d.rotate(angle); + g2d.scale(scalex, 1f); + layout.draw(g2d, 0f, 0f); + g2d.setTransform(saveTransform); + } + + static void draw(Graphics2D g2d, String string, + float x, float y, float scalex) { + AffineTransform saveTransform = g2d.getTransform(); + g2d.translate(x, y); + g2d.rotate(angle); + g2d.scale(scalex, 1f); + g2d.drawString(string, 0f, 0f); + g2d.setTransform(saveTransform); + } + + static void draw(Graphics2D g2d, GlyphVector gv, + float x, float y, float scalex) { + AffineTransform saveTransform = g2d.getTransform(); + g2d.translate(x, y); + g2d.rotate(angle); + g2d.scale(scalex, 1f); + g2d.drawGlyphVector(gv, 0f, 0f); + g2d.setTransform(saveTransform); + } + + static void init(Graphics2D g2d) { + g2d.setColor(Color.white); + g2d.fillRect(0, 0, W, H); + g2d.setColor(Color.black); + g2d.scale(1.481f, 1.481); // Convert to 108 dpi + g2d.addRenderingHints(hints); + Font font = new Font(Font.DIALOG, Font.PLAIN, 12); + g2d.setFont(font); + } + + static void compare(BufferedImage bi1, BufferedImage bi2) { + for (int x = 0; x < bi1.getWidth(); x++) { + for (int y = 0; y < bi1.getHeight(); y++) { + if (bi1.getRGB(x, y) != bi2.getRGB(x, y)) { + throw new RuntimeException("Different rendering"); + } + } + } + } + + public static void main(String args[]) { + + BufferedImage tl_Image = new BufferedImage(W, H, BufferedImage.TYPE_INT_RGB); + { + Graphics2D tl_g2d = tl_Image.createGraphics(); + init(tl_g2d); + FontRenderContext frc = tl_g2d.getFontRenderContext(); + // Specify font from graphics to be sure it is the same as the other cases. + TextLayout tl = new TextLayout(test, tl_g2d.getFont(), frc); + draw(tl_g2d, tl, 10f, 12f, 3.0f); + draw(tl_g2d, tl, 10f, 24f, 1.0f); + draw(tl_g2d, tl, 10f, 36f, 0.33f); + } + + BufferedImage st_Image = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB); + { + Graphics2D st_g2d = st_Image.createGraphics(); + init(st_g2d); + draw(st_g2d, test, 10f, 12f, 3.0f); + draw(st_g2d, test, 10f, 24f, 1.0f); + draw(st_g2d, test, 10f, 36f, .33f); + } + + BufferedImage gv_Image = new BufferedImage(400, 400, BufferedImage.TYPE_INT_RGB); + { + Graphics2D gv_g2d = gv_Image.createGraphics(); + init(gv_g2d); + FontRenderContext frc = gv_g2d.getFontRenderContext(); + GlyphVector gv = gv_g2d.getFont().createGlyphVector(frc, test); + draw(gv_g2d, gv, 10f, 12f, 3.0f); + draw(gv_g2d, gv, 10f, 24f, 1.0f); + draw(gv_g2d, gv, 10f, 36f, .33f); + } + + compare(tl_Image, st_Image); + compare(gv_Image, st_Image); + } +} diff --git a/test/jdk/sun/awt/windows/TestPen.java b/test/jdk/sun/awt/windows/TestPen.java new file mode 100644 index 0000000000000..25b7304bdc862 --- /dev/null +++ b/test/jdk/sun/awt/windows/TestPen.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4277201 + * @summary verifies that invoking a fill on a brand new Graphics object + * does not stroke the shape in addition to filling it + * @key headful + */ + +/* + * This test case tests for a problem with initializing GDI graphics + * contexts (HDCs) where a pen is left installed in the graphics object + * even though the AWT believes that there is no Pen installed. The + * result is that when you try to fill a shape, GDI will both fill and + * stroke it. +*/ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; + +public class TestPen extends Panel { + + static volatile TestPen pen; + static volatile Frame frame; + + public TestPen() { + setForeground(Color.black); + setBackground(Color.white); + } + + public Dimension getPreferredSize() { + return new Dimension(200, 200); + } + + public void paint(Graphics g) { + g.setColor(Color.green); + g.fillOval(50, 50, 100, 100); + } + + static void createUI() { + frame = new Frame(); + pen = new TestPen(); + frame.add(pen); + frame.pack(); + frame.setVisible(true); + } + + public static void main(String argv[]) throws Exception { + try { + EventQueue.invokeAndWait(TestPen::createUI); + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(2000); + Point p = pen.getLocationOnScreen(); + Dimension d = pen.getSize(); + Rectangle r = new Rectangle(p.x + 1, p.y + 1, d.width - 2, d.height - 2); + BufferedImage bi = robot.createScreenCapture(r); + int blackPixel = Color.black.getRGB(); + for (int y = 0; y < bi.getHeight(); y++ ) { + for (int x = 0; x < bi.getWidth(); x++ ) { + if (bi.getRGB(x, y) == blackPixel) { + throw new RuntimeException("Black pixel !"); + } + } + } + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + } +} From dd56990962d58e4f482773f67bc43383d7748536 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 30 Sep 2024 02:43:32 +0000 Subject: [PATCH 050/188] 8340639: Open source few more AWT List tests Reviewed-by: prr --- .../java/awt/List/HorizScrollWorkTest.java | 69 +++++++++ .../awt/List/HorizScrollbarEraseTest.java | 139 ++++++++++++++++++ .../java/awt/List/ScrollbarPresenceTest.java | 71 +++++++++ test/jdk/java/awt/List/SetForegroundTest.java | 109 ++++++++++++++ 4 files changed, 388 insertions(+) create mode 100644 test/jdk/java/awt/List/HorizScrollWorkTest.java create mode 100644 test/jdk/java/awt/List/HorizScrollbarEraseTest.java create mode 100644 test/jdk/java/awt/List/ScrollbarPresenceTest.java create mode 100644 test/jdk/java/awt/List/SetForegroundTest.java diff --git a/test/jdk/java/awt/List/HorizScrollWorkTest.java b/test/jdk/java/awt/List/HorizScrollWorkTest.java new file mode 100644 index 0000000000000..6de1de1a4f264 --- /dev/null +++ b/test/jdk/java/awt/List/HorizScrollWorkTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6355467 + * @summary Horizontal scroll bar thumb of a List does not stay at the end + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @requires (os.family == "linux") + * @run main/manual HorizScrollWorkTest +*/ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; + +public class HorizScrollWorkTest { + + private static final String INSTRUCTIONS = """ + This is a linux only test. + Drag and drop the horizontal scroll bar thumb at the right end. + If the thumb does not stay at the right end, then the test failed. Otherwise passed."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("HorizScrollWorkTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(HorizScrollWorkTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("HorizScrollWorkTest Frame"); + List list = new List(4); + + frame.setLayout (new FlowLayout()); + + list.add("veryyyyyyyyyyyyyyyyyyyyyyyyyy longgggggggggggggggggggggg stringggggggggggggggggggggg"); + + frame.add(list); + frame.pack(); + + return frame; + } +} diff --git a/test/jdk/java/awt/List/HorizScrollbarEraseTest.java b/test/jdk/java/awt/List/HorizScrollbarEraseTest.java new file mode 100644 index 0000000000000..2601a7ed0b2e6 --- /dev/null +++ b/test/jdk/java/awt/List/HorizScrollbarEraseTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4895367 + * @summary List scrolling w/ down arrow keys obscures horizontal scrollbar + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @requires (os.family == "linux") + * @run main/manual HorizScrollbarEraseTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.List; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class HorizScrollbarEraseTest { + + private static final String INSTRUCTIONS = """ + This is a Unix-only test. + Do the four mini-tests below. + If the horizontal scrollbar is ever erased by a rectangle + of the background color, the test FAILS. + If the horizontal scrollbars remain painted, test passes."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("HorizScrollbarEraseTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(HorizScrollbarEraseTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("HorizScrollbarEraseTest"); + Panel borderPanel = new Panel(); + borderPanel.setLayout(new BorderLayout()); + Button focusedButton = new Button("Focus starts here"); + borderPanel.add(focusedButton, BorderLayout.NORTH); + + Panel gridPanel = new Panel(); + gridPanel.setLayout(new GridLayout(0, 4)); + borderPanel.add(gridPanel, BorderLayout.CENTER); + + InstructionList il1 = new InstructionList("Tab to Item 2, then \n" + + "press the down" + + "arrow key to scroll down"); + il1.list.select(2); + il1.list.makeVisible(0); + gridPanel.add(il1); + + InstructionList il2 = new InstructionList("Tab to the next List,\n" + + "then press the down\n" + + "arrow key to select\n" + + "the last item."); + il2.list.select(3); + il2.list.makeVisible(0); + gridPanel.add(il2); + + InstructionList il3 = new InstructionList("Click the button to\n" + + "programmatically\n" + + "select item 3 (not showing)"); + Button selectBtn = new Button("Click Me"); + final List selectList = il3.list; + selectBtn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + selectList.select(3); + } + }); + il3.add(selectBtn, BorderLayout.CENTER); + gridPanel.add(il3); + + InstructionList il4 = new InstructionList("Click the button to\nprogrammatically\ndeselect item 3\n(not showing)"); + Button deselectBtn = new Button("Click Me"); + final List deselectList = il4.list; + deselectBtn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + deselectList.deselect(3); + } + }); + il4.add(deselectBtn, BorderLayout.CENTER); + il4.list.select(3); + il4.list.makeVisible(0); + gridPanel.add(il4); + + frame.add(borderPanel); + frame.pack(); + return frame; + + } +} + +class InstructionList extends Panel { + TextArea ta; + public List list; + + public InstructionList(String instructions) { + super(); + setLayout(new BorderLayout()); + ta = new TextArea(instructions, 6, 25, TextArea.SCROLLBARS_NONE); + ta.setFocusable(false); + list = new List(); + for (int i = 0; i < 5; i++) { + list.add("Item " + i + ", a long, long, long, long item"); + } + add(ta, BorderLayout.NORTH); + add(list, BorderLayout.SOUTH); + } +} diff --git a/test/jdk/java/awt/List/ScrollbarPresenceTest.java b/test/jdk/java/awt/List/ScrollbarPresenceTest.java new file mode 100644 index 0000000000000..d82cbb80060ca --- /dev/null +++ b/test/jdk/java/awt/List/ScrollbarPresenceTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6336384 + * @summary ScrollBar does not show up correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollbarPresenceTest +*/ + +import java.awt.Font; +import java.awt.Frame; +import java.awt.List; + +public class ScrollbarPresenceTest { + + private static final String INSTRUCTIONS = """ + You will see a list, + If a vertical scrollbar appears on the list and the list is big enough + to show all items then the test failed else the test passed."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ScrollbarPresenceTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ScrollbarPresenceTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("ScrollbarPresenceTest Frame"); + List list = new List(); + + for (int i = 0; i < 6; i++) { + list.addItem("Row " + i); + } + + list.setFont(new Font("MonoSpaced", Font.PLAIN, 12)); + list.setBounds(30, 30, 128, 104); + frame.add(list); + + frame.pack(); + return frame; + } + +} diff --git a/test/jdk/java/awt/List/SetForegroundTest.java b/test/jdk/java/awt/List/SetForegroundTest.java new file mode 100644 index 0000000000000..7b22e5385088b --- /dev/null +++ b/test/jdk/java/awt/List/SetForegroundTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6246467 + * @summary Tests that list works correctly if user specified foreground colors on XToolkit/Motif + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetForegroundTest + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.ScrollPane; + +public class SetForegroundTest { + + private static final String INSTRUCTIONS = """ + To make sure, that for each component + (Button, Checkbox, Label, List, TextArea, TextField, Choice) + in the frame, + the title exist and the color of the title is red. + If not, the test failed."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("SetForegroundTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(SetForegroundTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame(); + ScrollPane sp = new ScrollPane() { + public Dimension getPreferredSize() { + return new Dimension(180, 180); + } + }; + Panel p = new Panel(); + Component childs[] = new Component[] {new Button("button"), + new Checkbox("checkbox"), + new Label("label"), + new List(3, false), + new TextArea("text area"), + new TextField("text field"), + new Choice()}; + + p.setLayout (new FlowLayout ()); + + sp.add(p); + + sp.validate(); + + frame.add(sp); + for (int i = 0; i < childs.length; i++){ + childs[i].setForeground(Color.red); + } + + for (int i = 0; i < childs.length; i++) { + p.add(childs[i]); + if (childs[i] instanceof List) { + ((List)childs[i]).add("list1"); + ((List)childs[i]).add("list2"); + } else if (childs[i] instanceof Choice) { + ((Choice)childs[i]).add("choice1"); + ((Choice)childs[i]).add("choice2"); + } + } + frame.pack(); + return frame; + } +} From ae4d2f15901bf02efceaac26ee4aa3ae666bf467 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Mon, 30 Sep 2024 02:43:49 +0000 Subject: [PATCH 051/188] 8340621: Open source several AWT List tests Reviewed-by: prr --- .../java/awt/List/DisabledListIsGreyTest.java | 75 ++++++++++ .../java/awt/List/ListFrameResizeTest.java | 104 ++++++++++++++ .../awt/List/MultiSelectionListCrashTest.java | 89 ++++++++++++ .../java/awt/List/ScrollbarPositionTest.java | 104 ++++++++++++++ .../awt/List/SelectedItemVisibilityTest.java | 128 ++++++++++++++++++ 5 files changed, 500 insertions(+) create mode 100644 test/jdk/java/awt/List/DisabledListIsGreyTest.java create mode 100644 test/jdk/java/awt/List/ListFrameResizeTest.java create mode 100644 test/jdk/java/awt/List/MultiSelectionListCrashTest.java create mode 100644 test/jdk/java/awt/List/ScrollbarPositionTest.java create mode 100644 test/jdk/java/awt/List/SelectedItemVisibilityTest.java diff --git a/test/jdk/java/awt/List/DisabledListIsGreyTest.java b/test/jdk/java/awt/List/DisabledListIsGreyTest.java new file mode 100644 index 0000000000000..ec1a257066606 --- /dev/null +++ b/test/jdk/java/awt/List/DisabledListIsGreyTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6354810 + * @summary Items in the list are not grayed out when disabled, XToolkit + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DisabledListIsGreyTest +*/ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; + +public class DisabledListIsGreyTest { + + private static final String INSTRUCTIONS = """ + 1) After the test started you will see two lists. + 2) One of them is enabled, and the second is disabled. + 3) Check that the items of the disabled list are grayed. + 4) If so, the test passed. Otherwise, failed."""; + + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("DisabledListIsGreyTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(DisabledListIsGreyTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("DisabledListIsGreyTest Frame"); + frame.setLayout(new FlowLayout()); + + List list1 = new List(3); + List list2 = new List(3); + for (int i = 0; i < 5; i++) { + list1.addItem("Item " + i); + list2.addItem("Item " + i); + } + frame.add(list1); + + list2.setEnabled(false); + frame.add(list2); + frame.pack(); + return frame; + } + +} diff --git a/test/jdk/java/awt/List/ListFrameResizeTest.java b/test/jdk/java/awt/List/ListFrameResizeTest.java new file mode 100644 index 0000000000000..4655e817da581 --- /dev/null +++ b/test/jdk/java/awt/List/ListFrameResizeTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4085379 + * @summary List component not properly "resized" with GridBagLayout + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ListFrameResizeTest + */ + +import java.awt.Color; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.List; + +public class ListFrameResizeTest { + + private static final String INSTRUCTIONS = """ + This test is for windows only. + + 1. A Frame will appear with a List + (the List occupies the whole Frame) + 2. Minimize the Frame, the Frame is now in the Task Bar (ie.,iconified) + 3. Right click (right mouse button) the icon in the task bar + and click on the 'maximize' menuitem to maximize the Frame + 4. If you notice the List has not been resized + (ie.,if it partly occupies the Frame), then press FAIL else press PASS"."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ListFrameResizeTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ListFrameResizeTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + wintest client = new wintest("ListFrameResizeTest Frame"); + client.resize(500, 300); + client.setBackground(Color.blue); + return client; + } + +} + +class wintest extends Frame { + private List msg; + + public wintest(String title) { + super(title); + msg = new List(); + for (int i = 0; i < 100; i++) { + msg.add("" + i); + } + + GridBagLayout gridbag = new GridBagLayout(); + GridBagConstraints constraints = new GridBagConstraints(); + + setLayout(gridbag); + + constraints.fill = GridBagConstraints.BOTH; + + constraints.anchor = GridBagConstraints.CENTER; + constraints.insets = new Insets(10, 10, 10, 10); + constraints.ipadx = 0; + constraints.ipady = 0; + constraints.weightx = 1; + constraints.weighty = 1; + constraints.gridx = 0; + constraints.gridy = 0; + constraints.gridwidth = GridBagConstraints.REMAINDER; + constraints.gridheight = GridBagConstraints.REMAINDER; + gridbag.setConstraints(msg, constraints); + add(msg); + } +} diff --git a/test/jdk/java/awt/List/MultiSelectionListCrashTest.java b/test/jdk/java/awt/List/MultiSelectionListCrashTest.java new file mode 100644 index 0000000000000..b408a12ebbac7 --- /dev/null +++ b/test/jdk/java/awt/List/MultiSelectionListCrashTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4201967 + * @summary tests that a multiselection list doesn't causes crash when FileDialog is invoked + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiSelectionListCrashTest + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class MultiSelectionListCrashTest { + + private static final String INSTRUCTIONS = """ + Press "Invoke dialog" button to invoke a FileDialog. + When it appears close it by pressing cancel button. + If all remaining frames are enabled and + page fault didn't occur the test passed. Otherwise the test failed. + + Try to invoke a FileDialog several times to verify that the bug doesn't exist."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("MultiSelectionListCrashTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MultiSelectionListCrashTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + + Frame frame = new Frame("MultiSelectionListCrashTest frame"); + Button button = new Button("Invoke dialog"); + button.addActionListener(new FileDialogInvoker(frame)); + List list = new List(4, true); + list.add("Item1"); + list.add("Item2"); + frame.setLayout(new FlowLayout()); + frame.add(button); + frame.add(list); + frame.setSize(200, 200); + return frame; + } +} + +class FileDialogInvoker implements ActionListener { + FileDialog fileDialog; + + public FileDialogInvoker(Frame frame) { + fileDialog = new FileDialog(frame); + } + + public void actionPerformed(ActionEvent e) { + fileDialog.setVisible(true); + } + +} diff --git a/test/jdk/java/awt/List/ScrollbarPositionTest.java b/test/jdk/java/awt/List/ScrollbarPositionTest.java new file mode 100644 index 0000000000000..25167fa56278c --- /dev/null +++ b/test/jdk/java/awt/List/ScrollbarPositionTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4024943 + * @summary Test for position of List scrollbar when it is added + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ScrollbarPositionTest + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.List; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ScrollbarPositionTest { + static int item = 0; + static List list; + static Button addButton, delButton; + + private static final String INSTRUCTIONS = """ + Click on the "Add List Item" button many times + until the vertical scrollbar appears. + Verify that the displayed vertical scrollbar does not take the space + that was occupied by buttons before the scrollbar is shown."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ScrollbarPositionTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ScrollbarPositionTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Panel pan; + + Frame frame = new Frame("ScrollbarPositionTest Frame"); + frame.setLayout(new GridLayout(1, 2)); + list = new List(); + frame.add(list); + frame.add(pan = new Panel()); + pan.setLayout(new GridLayout(4, 1)); + + MyListener listener = new MyListener(); + addButton = new Button("Add List Item"); + addButton.addActionListener(listener); + pan.add(addButton); + + delButton = new Button("Delete List Item"); + delButton.addActionListener(listener); + pan.add(delButton); + + frame.pack(); + return frame; + } + + static class MyListener implements ActionListener { + public void actionPerformed(ActionEvent evt) { + if (evt.getSource() == addButton) { + String s = "item"; + for (int i = 0; i <= item; i++) { + s = s +" "+Integer.toString(i); + } + item++; + list.addItem(s); + } else if (evt.getSource() == delButton) { + int i; + if ((i = list.countItems()) > 0) { + list.delItem(i - 1); + --item; + } + } + } + } +} diff --git a/test/jdk/java/awt/List/SelectedItemVisibilityTest.java b/test/jdk/java/awt/List/SelectedItemVisibilityTest.java new file mode 100644 index 0000000000000..53364e937713c --- /dev/null +++ b/test/jdk/java/awt/List/SelectedItemVisibilityTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4676536 + * @summary REGRESSION: makeVisible() method of List Component does not perform + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SelectedItemVisibilityTest + */ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.List; + +public class SelectedItemVisibilityTest { + + static List list1, list2; + static int visibleItem = 4; + static int selectedItems[] = {6, 7, 8}; + static String selectedItemsStr = ""; + + static { + for (int i = 0 ; i < selectedItems.length ; i++) { + selectedItemsStr += ""+selectedItems[i]+" "; + } + } + + private static final String INSTRUCTIONS = + "You should see two lists.\n" + + "\n" + + "list1: \n" + + "\t1. the first visible item should be " + visibleItem + + "\n\t2. the selected item should be " + selectedItems[0] + + "\n" + + "list2:\n" + + "\t1. the first visible item should be " + visibleItem + + "\n\t2. the selected items should be " + selectedItemsStr + + "\n" + + "\nIf it is so the test passed else failed."; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("SelectedItemVisibilityTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(SelectedItemVisibilityTest::createTestUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + + Frame frame = new Frame("SelectedItemVisibilityTest Frame"); + frame.setLayout(new FlowLayout()); + + // list1 + list1 = new List(4); + for (int i = 0; i < 20; i++) { + list1.add(""+i); + } + list1.makeVisible(visibleItem); + list1.select(selectedItems[0]); + frame.add(new Label("list1:")); + frame.add(list1); + + // list2 + list2 = new List(4); + list2.setMultipleMode(true); + for (int i = 0; i < 20; i++) { + list2.add(""+i); + } + list2.makeVisible(visibleItem); + for (int i = 0 ; i < selectedItems.length ; i++) { + list2.select(selectedItems[i]); + } + frame.add(new Label("list2:")); + frame.add(list2); + frame.setSize(200, 200); + + // common output + String s; + int sel[]; + + PassFailJFrame.log("list1: "); + PassFailJFrame.log("\tgetVisibleIndex="+list1.getVisibleIndex()); + sel = list1.getSelectedIndexes(); + s = "\tgetSelectedIndexes="; + for (int i = 0 ; i < sel.length ; i++) { + s += "" + sel[i] + " "; + } + PassFailJFrame.log(s); + + PassFailJFrame.log("list2: "); + PassFailJFrame.log("\tgetVisibleIndex="+list2.getVisibleIndex()); + sel = list2.getSelectedIndexes(); + s = "\tgetSelectedIndexes="; + for (int i = 0 ; i < sel.length ; i++) { + s += "" + sel[i] + " "; + } + PassFailJFrame.log(s); + return frame; + } +} From 6514aef8403fa5fc09e5c064a783ff0f1fccd0cf Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Mon, 30 Sep 2024 06:20:08 +0000 Subject: [PATCH 052/188] 8340419: ZGC: Create an UseLargePages adaptation of TestAllocateHeapAt.java Reviewed-by: stefank, sjohanss, jsikstro --- .../gc/z/TestAllocateHeapAtWithHugeTLBFS.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 test/hotspot/jtreg/gc/z/TestAllocateHeapAtWithHugeTLBFS.java diff --git a/test/hotspot/jtreg/gc/z/TestAllocateHeapAtWithHugeTLBFS.java b/test/hotspot/jtreg/gc/z/TestAllocateHeapAtWithHugeTLBFS.java new file mode 100644 index 0000000000000..ac647bbd013fd --- /dev/null +++ b/test/hotspot/jtreg/gc/z/TestAllocateHeapAtWithHugeTLBFS.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package gc.z; + +/* + * @test TestAllocateHeapAtWithHugeTLBFS + * @requires vm.gc.ZGenerational & os.family == "linux" + * @summary Test ZGC with -XX:AllocateHeapAt and -XX:+UseLargePages + * @library /test/lib + * @run driver gc.z.TestAllocateHeapAtWithHugeTLBFS true + * @run driver gc.z.TestAllocateHeapAtWithHugeTLBFS false + */ + +import jdk.test.lib.process.ProcessTools; +import jtreg.SkippedException; + +import java.io.File; +import java.io.FileNotFoundException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.Path; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.Scanner; + +public class TestAllocateHeapAtWithHugeTLBFS { + static String find_hugetlbfs_mountpoint() { + Pattern pat = Pattern.compile("\\d+ \\d+ \\d+:\\d+ \\S+ (\\S+) [^-]*- hugetlbfs (.+)"); + try (Scanner scanner = new Scanner(new File("/proc/self/mountinfo"))) { + while (scanner.hasNextLine()) { + final Matcher mat = pat.matcher(scanner.nextLine()); + if (mat.matches() && mat.group(2).contains("pagesize=2M")) { + final Path path = Paths.get(mat.group(1)); + if (Files.isReadable(path) && + Files.isWritable(path) && + Files.isExecutable(path)) { + // Found a usable mount point. + return path.toString(); + } + } + } + } catch (FileNotFoundException e) { + System.out.println("Could not open /proc/self/mountinfo"); + } + return null; + } + public static void main(String[] args) throws Exception { + final boolean exists = Boolean.parseBoolean(args[0]); + final String directory = exists ? find_hugetlbfs_mountpoint() + : "non-existing-directory"; + if (directory == null) { + throw new SkippedException("No valid hugetlbfs mount point found"); + } + final String heapBackingFile = "Heap Backing File: " + directory; + final String failedToCreateFile = "Failed to create file " + directory; + + ProcessTools.executeTestJava( + "-XX:+UseZGC", + "-XX:+ZGenerational", + "-Xlog:gc*", + "-Xms32M", + "-Xmx32M", + "-XX:+UseLargePages", + "-XX:AllocateHeapAt=" + directory, + "-version") + .shouldContain(exists ? heapBackingFile : failedToCreateFile) + .shouldNotContain(exists ? failedToCreateFile : heapBackingFile) + .shouldHaveExitValue(exists ? 0 : 1); + } +} From 822a773873c42ea27a6be90da92b2b2c9fb8caee Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Mon, 30 Sep 2024 06:38:42 +0000 Subject: [PATCH 053/188] 8340605: Open source several AWT PopupMenu tests Reviewed-by: tr --- .../java/awt/PopupMenu/PeripheryOfScreen.java | 82 ++++++++++++++ .../PopupMenu/PopupLeadingSeparatorTest.java | 81 ++++++++++++++ .../java/awt/PopupMenu/PopupMenuShowTest.java | 77 +++++++++++++ .../awt/PopupMenu/PopupMenuWithMenuBar.java | 103 ++++++++++++++++++ .../jdk/java/awt/PopupMenu/PopupOnButton.java | 88 +++++++++++++++ 5 files changed, 431 insertions(+) create mode 100644 test/jdk/java/awt/PopupMenu/PeripheryOfScreen.java create mode 100644 test/jdk/java/awt/PopupMenu/PopupLeadingSeparatorTest.java create mode 100644 test/jdk/java/awt/PopupMenu/PopupMenuShowTest.java create mode 100644 test/jdk/java/awt/PopupMenu/PopupMenuWithMenuBar.java create mode 100644 test/jdk/java/awt/PopupMenu/PopupOnButton.java diff --git a/test/jdk/java/awt/PopupMenu/PeripheryOfScreen.java b/test/jdk/java/awt/PopupMenu/PeripheryOfScreen.java new file mode 100644 index 0000000000000..b169a7d9692a7 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/PeripheryOfScreen.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6267162 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Popup Menu gets hidden below the screen when opened near the periphery + * of the screen, XToolkit Test if popup menu window is adjusted on screen + * when trying to show outside + * @run main/manual PeripheryOfScreen + */ + +public class PeripheryOfScreen { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click on the button to show popup menu in the center of + frame. Move frame beyond the edge of screen and click on + button to show the popup menu and see if popup menu is + adjusted to the edge. + + Press Pass if popup menu behaves as per instruction, otherwise + press Fail. + """; + + PassFailJFrame.builder() + .title("PeripheryOfScreen Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(PeripheryOfScreen::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI () { + Frame f = new Frame("PeripheryOfScreen Test frame"); + Button b = new Button("Click to show popup menu"); + PopupMenu pm = new PopupMenu("Test menu"); + MenuItem i = new MenuItem("Click me"); + pm.add(i); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + pm.show(f, 100, 100); + } + }); + f.add(b); + f.add(pm); + f.setSize(300, 200); + f.toFront(); + return f; + } +} diff --git a/test/jdk/java/awt/PopupMenu/PopupLeadingSeparatorTest.java b/test/jdk/java/awt/PopupMenu/PopupLeadingSeparatorTest.java new file mode 100644 index 0000000000000..c9274e9b807f0 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/PopupLeadingSeparatorTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Component; +import java.awt.Frame; +import java.awt.Font; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4169155 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Popup menus get a leading separator on Motif system + * @run main/manual PopupLeadingSeparatorTest + */ + +public class PopupLeadingSeparatorTest { + public static void main(String[] args) throws Exception { + PopupLeadingSeparatorTest obj = new PopupLeadingSeparatorTest(); + String INSTRUCTIONS = """ + Press mouse button on the frame. Popup menu without leading + separator should appear. + If a PopupMenu behaves same, press Pass, else press Fail. + """; + + PassFailJFrame.builder() + .title("PopupLeadingSeparatorTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(obj::createUI) + .build() + .awaitAndCheck(); + } + + private Frame createUI() { + Frame f = new Frame("PopupLeadingSeparatorTest Test"); + PopupMenu popupMenu = new PopupMenu("Popup Menu Title"); + popupMenu.add(new MenuItem("Item1")); + PopupMenu cascadeMenu = new PopupMenu("Multifont menu"); + cascadeMenu.add(new MenuItem("Item1")); + MenuItem item2 = new MenuItem("Item2"); + item2.setFont(new Font("Serif", Font.BOLD, 36)); + cascadeMenu.add(item2); + + popupMenu.add(cascadeMenu); + f.add(popupMenu); + f.setSize(300, 150); + f.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent evt) { + popupMenu.show((Component) evt.getSource(), evt.getX(), evt.getY()); + } + }); + return f; + } +} diff --git a/test/jdk/java/awt/PopupMenu/PopupMenuShowTest.java b/test/jdk/java/awt/PopupMenu/PopupMenuShowTest.java new file mode 100644 index 0000000000000..b36fdc5d19c22 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/PopupMenuShowTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4168006 4196790 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Popup menu test fails on x86/Solaris 2.6 combination. + * @run main/manual PopupMenuShowTest + */ + +public class PopupMenuShowTest { + public static void main(String[] args) throws Exception { + PopupMenuShowTest obj = new PopupMenuShowTest(); + String INSTRUCTIONS = """ + Press the right mouse button in the PopupTest window. + If a PopupMenu appears, press Pass, else press Fail. + """; + + PassFailJFrame.builder() + .title("PopupMenuShowTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(obj::createUI) + .build() + .awaitAndCheck(); + } + + private Frame createUI() { + Frame f = new Frame("PopupMenuShowTest Test"); + f.setLayout(new FlowLayout()); + f.add(new Label("Press right mouse button inside this frame.")); + f.add(new Label("A pop-up menu should appear.")); + PopupMenu popupMenu = new PopupMenu("Popup Menu Title"); + MenuItem mi = new MenuItem("Menu Item"); + popupMenu.add(mi); + f.add(popupMenu); + f.setSize(400, 350); + f.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + popupMenu.show(e.getComponent(), e.getX(), e.getY()); + } + }); + return f; + } +} diff --git a/test/jdk/java/awt/PopupMenu/PopupMenuWithMenuBar.java b/test/jdk/java/awt/PopupMenu/PopupMenuWithMenuBar.java new file mode 100644 index 0000000000000..1a927e29f84bc --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/PopupMenuWithMenuBar.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4038140 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Test for functionality of PopupMenuWithMenuBar + * @run main/manual PopupMenuWithMenuBar + */ + +public class PopupMenuWithMenuBar { + public static void main(String[] args) throws Exception { + PopupMenuWithMenuBar obj = new PopupMenuWithMenuBar(); + String INSTRUCTIONS = """ + There was a bug that prevented the popup menu from appearing properly + (if even at all) for a frame window when there is also a menu bar. + + Right click inside the frame window to display the popup window. If + the popup menu appears normally, then the test is successful and the + bug has been fixed."""; + + PassFailJFrame.builder() + .title("PopupMenuWithMenuBar Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(obj::createUI) + .build() + .awaitAndCheck(); + } + + private Frame createUI() { + Frame f = new Frame("PopupMenuWithMenuBar Test"); + f.setBounds(10, 10, 300, 250); + MenuBar menuBar = new MenuBar(); + Menu fileMenu = createFileMenu(); + menuBar.add(fileMenu); + f.setMenuBar(menuBar); + PopupMenu popupMenu = createPopupMenu(); + f.add(popupMenu); + f.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + popupMenu.show(f, e.getX(), e.getY()); + } + }); + return f; + } + + private Menu createFileMenu() { + String[] menu1Labels = new String[] + {"Save As", "Save As", "Quit"}; + MenuItem menuItem; + Menu returnMenu = new Menu("File"); + for (int menu1Index = 0; menu1Index < menu1Labels.length; menu1Index++) { + menuItem = new MenuItem(menu1Labels[menu1Index]); + returnMenu.add(menuItem); + } + return returnMenu; + } + + private PopupMenu createPopupMenu() { + String[] popupLabels = new String[] + {"Popup 1", "Popup 2", "Quit"}; + MenuItem menuItem; + PopupMenu returnMenu = new PopupMenu("Popups"); + for (int popupIndex = 0; popupIndex < popupLabels.length; popupIndex++) { + menuItem = new MenuItem(popupLabels[popupIndex]); + returnMenu.add(menuItem); + } + return returnMenu; + } +} diff --git a/test/jdk/java/awt/PopupMenu/PopupOnButton.java b/test/jdk/java/awt/PopupMenu/PopupOnButton.java new file mode 100644 index 0000000000000..581714bf76a85 --- /dev/null +++ b/test/jdk/java/awt/PopupMenu/PopupOnButton.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Frame; +import java.awt.MenuItem; +import java.awt.PopupMenu; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4181790 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Tests a popup menu on a button. + * @run main/manual PopupOnButton + */ + +public class PopupOnButton { + public static void main(String[] args) throws Exception { + PopupOnButton obj = new PopupOnButton(); + String INSTRUCTIONS = """ + Right-click on the button. + Popup Menu should appear and behave fine. + If a PopupMenu appears, press Pass, else press Fail. + """; + + PassFailJFrame.builder() + .title("PopupOnButton Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(obj::createUI) + .build() + .awaitAndCheck(); + } + + private Frame createUI() { + Frame f = new Frame("PopupOnButton Test"); + Button b = new Button("button with popup menu"); + PopupMenu m = new PopupMenu("popup"); + m.add(new MenuItem("item1")); + m.add(new MenuItem("item2")); + m.add(new MenuItem("item3")); + b.add(m); + b.addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + if (e.isPopupTrigger()) { + m.show((Component) e.getSource(), e.getX(), e.getY()); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) { + m.show((Component) e.getSource(), e.getX(), e.getY()); + } + } + }); + + f.add(b); + f.setSize(200, 150); + return f; + } + } From 988a531b097ccbd699d233059d73f41cae24dc5b Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 30 Sep 2024 07:02:55 +0000 Subject: [PATCH 054/188] 8340181: Shenandoah: Cleanup ShenandoahRuntime stubs Reviewed-by: adinn, phh, wkemper --- .../shenandoahBarrierSetAssembler_aarch64.cpp | 10 ++--- .../shenandoahBarrierSetAssembler_ppc.cpp | 8 ++-- .../shenandoahBarrierSetAssembler_riscv.cpp | 10 ++--- .../shenandoahBarrierSetAssembler_x86.cpp | 10 ++--- .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 29 ++++++------- .../shenandoah/c2/shenandoahBarrierSetC2.hpp | 6 +-- .../gc/shenandoah/c2/shenandoahSupport.cpp | 2 +- .../share/gc/shenandoah/shenandoahRuntime.cpp | 41 ++++++++----------- .../share/gc/shenandoah/shenandoahRuntime.hpp | 8 ++-- 9 files changed, 60 insertions(+), 64 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index 06f4382015603..84d06dbcc7bfd 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -67,9 +67,9 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec __ push(saved_regs, sp); if (UseCompressedOops) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry), src, dst, count); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop), src, dst, count); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), src, dst, count); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop), src, dst, count); } __ pop(saved_regs, sp); __ bind(done); @@ -164,9 +164,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, if (expand_call) { assert(pre_val != c_rarg1, "smashed arg"); - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); } __ pop(saved, sp); @@ -698,7 +698,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss __ bind(runtime); __ push_call_clobbered_registers(); __ load_parameter(0, pre_val); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); __ pop_call_clobbered_registers(); __ bind(done); diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp index 3cb5c5a628f39..5315080721249 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp @@ -144,9 +144,9 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler *masm, Dec // Invoke runtime. address jrt_address = nullptr; if (UseCompressedOops) { - jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry); + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop); } else { - jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry); + jrt_address = CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop); } assert(jrt_address != nullptr, "jrt routine cannot be found"); @@ -302,7 +302,7 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_impl(MacroAssembler *masm } // Invoke runtime. - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, R16_thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, R16_thread); // Restore to-be-preserved registers. if (!preserve_gp_registers && preloaded_mode && pre_val->is_volatile()) { @@ -906,7 +906,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss __ push_frame_reg_args(nbytes_save, R11_tmp1); // Invoke runtime. - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), R0_pre_val, R16_thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), R0_pre_val, R16_thread); // Restore to-be-preserved registers. __ pop_frame(); diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp index 9a79a92327723..cc73d14a756f2 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp @@ -70,10 +70,10 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec __ push_reg(saved_regs, sp); if (UseCompressedOops) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry), + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop), src, dst, count); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), src, dst, count); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop), src, dst, count); } __ pop_reg(saved_regs, sp); __ bind(done); @@ -165,9 +165,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, // expand_call should be passed true. if (expand_call) { assert(pre_val != c_rarg1, "smashed arg"); - __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); } __ pop_reg(saved, sp); @@ -645,7 +645,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss __ bind(runtime); __ push_call_clobbered_registers(); __ load_parameter(0, pre_val); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), pre_val, thread); __ pop_call_clobbered_registers(); __ bind(done); diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 47078dff90738..a7682fe0c3879 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -163,12 +163,12 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec assert(dst == rsi, "expected"); assert(count == rdx, "expected"); if (UseCompressedOops) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry), + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop), src, dst, count); } else #endif { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop), src, dst, count); } @@ -296,9 +296,9 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, __ push(thread); __ push(pre_val); #endif - __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), 2); + __ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), 2); } else { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), LP64_ONLY(c_rarg0) NOT_LP64(pre_val), thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), LP64_ONLY(c_rarg0) NOT_LP64(pre_val), thread); } NOT_LP64( __ pop(thread); ) @@ -925,7 +925,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss // load the pre-value __ load_parameter(0, rcx); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), rcx, thread); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), rcx, thread); __ restore_live_registers(true); diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 71174d11a6214..10b80b6802942 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -249,8 +249,9 @@ void ShenandoahBarrierSetC2::satb_write_barrier_pre(GraphKit* kit, } __ else_(); { // logging buffer is full, call the runtime - const TypeFunc *tf = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type(); - __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), "shenandoah_wb_pre", pre_val, tls); + const TypeFunc *tf = ShenandoahBarrierSetC2::write_ref_field_pre_Type(); + __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre), "shenandoah_wb_pre", + pre_val, tls); } __ end_if(); // (!index) } __ end_if(); // (pre_val != nullptr) } __ end_if(); // (!marking) @@ -268,12 +269,12 @@ void ShenandoahBarrierSetC2::satb_write_barrier_pre(GraphKit* kit, bool ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(Node* call) { return call->is_CallLeaf() && - call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry); + call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre); } bool ShenandoahBarrierSetC2::is_shenandoah_clone_call(Node* call) { return call->is_CallLeaf() && - call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::shenandoah_clone_barrier); + call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::clone_barrier); } bool ShenandoahBarrierSetC2::is_shenandoah_lrb_call(Node* call) { @@ -433,7 +434,7 @@ void ShenandoahBarrierSetC2::insert_pre_barrier(GraphKit* kit, Node* base_oop, N #undef __ -const TypeFunc* ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type() { +const TypeFunc* ShenandoahBarrierSetC2::write_ref_field_pre_Type() { const Type **fields = TypeTuple::fields(2); fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value fields[TypeFunc::Parms+1] = TypeRawPtr::NOTNULL; // thread @@ -446,7 +447,7 @@ const TypeFunc* ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type() { return TypeFunc::make(domain, range); } -const TypeFunc* ShenandoahBarrierSetC2::shenandoah_clone_barrier_Type() { +const TypeFunc* ShenandoahBarrierSetC2::clone_barrier_Type() { const Type **fields = TypeTuple::fields(1); fields[TypeFunc::Parms+0] = TypeOopPtr::NOTNULL; // src oop const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+1, fields); @@ -458,7 +459,7 @@ const TypeFunc* ShenandoahBarrierSetC2::shenandoah_clone_barrier_Type() { return TypeFunc::make(domain, range); } -const TypeFunc* ShenandoahBarrierSetC2::shenandoah_load_reference_barrier_Type() { +const TypeFunc* ShenandoahBarrierSetC2::load_reference_barrier_Type() { const Type **fields = TypeTuple::fields(2); fields[TypeFunc::Parms+0] = TypeOopPtr::BOTTOM; // original field value fields[TypeFunc::Parms+1] = TypeRawPtr::BOTTOM; // original load address @@ -797,11 +798,11 @@ void ShenandoahBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCo // Heap is unstable, call into clone barrier stub Node* call = phase->make_leaf_call(unstable_ctrl, mem, - ShenandoahBarrierSetC2::shenandoah_clone_barrier_Type(), - CAST_FROM_FN_PTR(address, ShenandoahRuntime::shenandoah_clone_barrier), - "shenandoah_clone", - TypeRawPtr::BOTTOM, - src_base); + ShenandoahBarrierSetC2::clone_barrier_Type(), + CAST_FROM_FN_PTR(address, ShenandoahRuntime::clone_barrier), + "shenandoah_clone", + TypeRawPtr::BOTTOM, + src_base); call = phase->transform_later(call); ctrl = phase->transform_later(new ProjNode(call, TypeFunc::Control)); @@ -976,7 +977,7 @@ void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase p Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_reshape) const { if (is_shenandoah_wb_pre_call(n)) { - uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type()->domain()->cnt(); + uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_Type()->domain()->cnt(); if (n->req() > cnt) { Node* addp = n->in(cnt); if (has_only_shenandoah_wb_pre_uses(addp)) { @@ -1062,7 +1063,7 @@ bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, ui assert (n->is_Call(), ""); CallNode *call = n->as_Call(); if (ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(call)) { - uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type()->domain()->cnt(); + uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_Type()->domain()->cnt(); if (call->req() > cnt) { assert(call->req() == cnt + 1, "only one extra input"); Node *addp = call->in(cnt); diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp index cbfacea31ab7a..6e241b39ce967 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp @@ -93,9 +93,9 @@ class ShenandoahBarrierSetC2 : public BarrierSetC2 { ShenandoahBarrierSetC2State* state() const; - static const TypeFunc* write_ref_field_pre_entry_Type(); - static const TypeFunc* shenandoah_clone_barrier_Type(); - static const TypeFunc* shenandoah_load_reference_barrier_Type(); + static const TypeFunc* write_ref_field_pre_Type(); + static const TypeFunc* clone_barrier_Type(); + static const TypeFunc* load_reference_barrier_Type(); virtual bool has_load_barrier_nodes() const { return true; } // This is the entry-point for the backend to perform accesses through the Access API. diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 7526f895f2f7f..efa0ced603cda 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -995,7 +995,7 @@ void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node* lo name = "load_reference_barrier_phantom"; } } - Node* call = new CallLeafNode(ShenandoahBarrierSetC2::shenandoah_load_reference_barrier_Type(), calladdr, name, TypeRawPtr::BOTTOM); + Node* call = new CallLeafNode(ShenandoahBarrierSetC2::load_reference_barrier_Type(), calladdr, name, TypeRawPtr::BOTTOM); call->init_req(TypeFunc::Control, ctrl); call->init_req(TypeFunc::I_O, phase->C->top()); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp index 2c727de585799..b217c641824c2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp @@ -31,22 +31,19 @@ #include "oops/oop.inline.hpp" #include "utilities/copy.hpp" -void ShenandoahRuntime::arraycopy_barrier_oop_entry(oop* src, oop* dst, size_t length) { - ShenandoahBarrierSet *bs = ShenandoahBarrierSet::barrier_set(); - bs->arraycopy_barrier(src, dst, length); -} +JRT_LEAF(void, ShenandoahRuntime::arraycopy_barrier_oop(oop* src, oop* dst, size_t length)) + ShenandoahBarrierSet::barrier_set()->arraycopy_barrier(src, dst, length); +JRT_END -void ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length) { - ShenandoahBarrierSet *bs = ShenandoahBarrierSet::barrier_set(); - bs->arraycopy_barrier(src, dst, length); -} +JRT_LEAF(void, ShenandoahRuntime::arraycopy_barrier_narrow_oop(narrowOop* src, narrowOop* dst, size_t length)) + ShenandoahBarrierSet::barrier_set()->arraycopy_barrier(src, dst, length); +JRT_END -// Shenandoah pre write barrier slowpath -JRT_LEAF(void, ShenandoahRuntime::write_ref_field_pre_entry(oopDesc* orig, JavaThread *thread)) +JRT_LEAF(void, ShenandoahRuntime::write_ref_field_pre(oopDesc * orig, JavaThread * thread)) assert(thread == JavaThread::current(), "pre-condition"); assert(orig != nullptr, "should be optimized out"); shenandoah_assert_correct(nullptr, orig); - // store the original value that was in the field reference + // Capture the original value that was in the field reference. assert(ShenandoahThreadLocalData::satb_mark_queue(thread).is_active(), "Shouldn't be here otherwise"); SATBMarkQueue& queue = ShenandoahThreadLocalData::satb_mark_queue(thread); ShenandoahBarrierSet::satb_mark_queue_set().enqueue_known_active(queue, orig); @@ -60,26 +57,24 @@ JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_strong_narrow(oopDe return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); JRT_END -// Shenandoah clone barrier: makes sure that references point to to-space -// in cloned objects. -JRT_LEAF(void, ShenandoahRuntime::shenandoah_clone_barrier(oopDesc* src)) - oop s = oop(src); - shenandoah_assert_correct(nullptr, s); - ShenandoahBarrierSet::barrier_set()->clone_barrier(s); -JRT_END - -JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_weak(oopDesc * src, oop* load_addr)) +JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_weak(oopDesc* src, oop* load_addr)) return (oopDesc*) ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_WEAK_OOP_REF, oop(src), load_addr); JRT_END -JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_weak_narrow(oopDesc * src, narrowOop* load_addr)) +JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_weak_narrow(oopDesc* src, narrowOop* load_addr)) return (oopDesc*) ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_WEAK_OOP_REF, oop(src), load_addr); JRT_END -JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_phantom(oopDesc * src, oop* load_addr)) +JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_phantom(oopDesc* src, oop* load_addr)) return (oopDesc*) ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_PHANTOM_OOP_REF, oop(src), load_addr); JRT_END -JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_phantom_narrow(oopDesc * src, narrowOop* load_addr)) +JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_phantom_narrow(oopDesc* src, narrowOop* load_addr)) return (oopDesc*) ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_PHANTOM_OOP_REF, oop(src), load_addr); JRT_END + +JRT_LEAF(void, ShenandoahRuntime::clone_barrier(oopDesc* src)) + oop s = oop(src); + shenandoah_assert_correct(nullptr, s); + ShenandoahBarrierSet::barrier_set()->clone_barrier(s); +JRT_END diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp index e187e4360b16b..4ad8fc997ea76 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp @@ -33,10 +33,10 @@ class oopDesc; class ShenandoahRuntime : public AllStatic { public: - static void arraycopy_barrier_oop_entry(oop* src, oop* dst, size_t length); - static void arraycopy_barrier_narrow_oop_entry(narrowOop* src, narrowOop* dst, size_t length); + static void arraycopy_barrier_oop(oop* src, oop* dst, size_t length); + static void arraycopy_barrier_narrow_oop(narrowOop* src, narrowOop* dst, size_t length); - static void write_ref_field_pre_entry(oopDesc* orig, JavaThread* thread); + static void write_ref_field_pre(oopDesc* orig, JavaThread* thread); static oopDesc* load_reference_barrier_strong(oopDesc* src, oop* load_addr); static oopDesc* load_reference_barrier_strong_narrow(oopDesc* src, narrowOop* load_addr); @@ -47,7 +47,7 @@ class ShenandoahRuntime : public AllStatic { static oopDesc* load_reference_barrier_phantom(oopDesc* src, oop* load_addr); static oopDesc* load_reference_barrier_phantom_narrow(oopDesc* src, narrowOop* load_addr); - static void shenandoah_clone_barrier(oopDesc* src); + static void clone_barrier(oopDesc* src); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHRUNTIME_HPP From 52ba72823be0c969ab873ead2863ec48f883210b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20L=C3=B6vdahl?= Date: Mon, 30 Sep 2024 08:33:12 +0000 Subject: [PATCH 055/188] 8327114: Attach in Linux may have wrong behaviour when pid == ns_pid (Kubernetes debug container) Co-authored-by: Larry Cable Reviewed-by: kevinw, sgehwolf --- .../sun/tools/attach/VirtualMachineImpl.java | 150 +++++++++++++----- .../docker/TestJcmdWithSideCar.java | 135 +++++++++++----- 2 files changed, 210 insertions(+), 75 deletions(-) diff --git a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java index 4eb29482e29ec..35ce808c18756 100644 --- a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java @@ -28,12 +28,13 @@ import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.spi.AttachProvider; -import java.io.InputStream; -import java.io.IOException; import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.Files; +import java.util.Optional; import static java.nio.charset.StandardCharsets.UTF_8; @@ -47,13 +48,35 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { // location is the same for all processes, otherwise the tools // will not be able to find all Hotspot processes. // Any changes to this needs to be synchronized with HotSpot. - private static final String tmpdir = "/tmp"; + private static final Path TMPDIR = Path.of("/tmp"); + + private static final Path PROC = Path.of("/proc"); + private static final Path NS_MNT = Path.of("ns/mnt"); + private static final Path NS_PID = Path.of("ns/pid"); + private static final Path SELF = PROC.resolve("self"); + private static final Path STATUS = Path.of("status"); + private static final Path ROOT_TMP = Path.of("root/tmp"); + + private static final Optional SELF_MNT_NS; + + static { + Path nsPath = null; + + try { + nsPath = Files.readSymbolicLink(SELF.resolve(NS_MNT)); + } catch (IOException _) { + // do nothing + } finally { + SELF_MNT_NS = Optional.ofNullable(nsPath); + } + } + String socket_path; + /** * Attaches to the target VM */ - VirtualMachineImpl(AttachProvider provider, String vmid) - throws AttachNotSupportedException, IOException + VirtualMachineImpl(AttachProvider provider, String vmid) throws AttachNotSupportedException, IOException { super(provider, vmid); @@ -64,12 +87,12 @@ public class VirtualMachineImpl extends HotSpotVirtualMachine { } // Try to resolve to the "inner most" pid namespace - int ns_pid = getNamespacePid(pid); + final long ns_pid = getNamespacePid(pid); // Find the socket file. If not found then we attempt to start the // attach mechanism in the target VM by sending it a QUIT signal. // Then we attempt to find the socket file again. - File socket_file = findSocketFile(pid, ns_pid); + final File socket_file = findSocketFile(pid, ns_pid); socket_path = socket_file.getPath(); if (!socket_file.exists()) { // Keep canonical version of File, to delete, in case target process ends and /proc link has gone: @@ -211,49 +234,102 @@ protected void close(long fd) throws IOException { } // Return the socket file for the given process. - private File findSocketFile(int pid, int ns_pid) throws IOException { - String root = findTargetProcessTmpDirectory(pid, ns_pid); - return new File(root, ".java_pid" + ns_pid); + private File findSocketFile(long pid, long ns_pid) throws AttachNotSupportedException, IOException { + return new File(findTargetProcessTmpDirectory(pid, ns_pid), ".java_pid" + ns_pid); } // On Linux a simple handshake is used to start the attach mechanism // if not already started. The client creates a .attach_pid file in the // target VM's working directory (or temp directory), and the SIGQUIT handler // checks for the file. - private File createAttachFile(int pid, int ns_pid) throws IOException { - String fn = ".attach_pid" + ns_pid; - String path = "/proc/" + pid + "/cwd/" + fn; - File f = new File(path); + private File createAttachFile(long pid, long ns_pid) throws AttachNotSupportedException, IOException { + Path fn = Path.of(".attach_pid" + ns_pid); + Path path = PROC.resolve(Path.of(Long.toString(pid), "cwd")).resolve(fn); + File f = new File(path.toString()); try { // Do not canonicalize the file path, or we will fail to attach to a VM in a container. f.createNewFile(); - } catch (IOException x) { - String root = findTargetProcessTmpDirectory(pid, ns_pid); - f = new File(root, fn); + } catch (IOException _) { + f = new File(findTargetProcessTmpDirectory(pid, ns_pid), fn.toString()); f.createNewFile(); } return f; } - private String findTargetProcessTmpDirectory(int pid, int ns_pid) throws IOException { - String root; - if (pid != ns_pid) { - // A process may not exist in the same mount namespace as the caller, e.g. - // if we are trying to attach to a JVM process inside a container. - // Instead, attach relative to the target root filesystem as exposed by - // procfs regardless of namespaces. - String procRootDirectory = "/proc/" + pid + "/root"; - if (!Files.isReadable(Path.of(procRootDirectory))) { - throw new IOException( - String.format("Unable to access root directory %s " + - "of target process %d", procRootDirectory, pid)); + private String findTargetProcessTmpDirectory(long pid, long ns_pid) throws AttachNotSupportedException, IOException { + // We need to handle at least 4 different cases: + // 1. Caller and target processes share PID namespace and root filesystem (host to host or container to + // container with both /tmp mounted between containers). + // 2. Caller and target processes share PID namespace and root filesystem but the target process has elevated + // privileges (host to host). + // 3. Caller and target processes share PID namespace but NOT root filesystem (container to container). + // 4. Caller and target processes share neither PID namespace nor root filesystem (host to container). + + Optional target = ProcessHandle.of(pid); + Optional ph = target; + long nsPid = ns_pid; + Optional prevPidNS = Optional.empty(); + + while (ph.isPresent()) { + final var curPid = ph.get().pid(); + final var procPidPath = PROC.resolve(Long.toString(curPid)); + Optional targetMountNS = Optional.empty(); + + try { + // attempt to read the target's mnt ns id + targetMountNS = Optional.ofNullable(Files.readSymbolicLink(procPidPath.resolve(NS_MNT))); + } catch (IOException _) { + // if we fail to read the target's mnt ns id then we either don't have access or it no longer exists! + if (!Files.exists(procPidPath)) { + throw new IOException(String.format("unable to attach, %s non-existent! process: %d terminated", procPidPath, pid)); + } + // the process still exists, but we don't have privileges to read its procfs } - root = procRootDirectory + "/" + tmpdir; + final var sameMountNS = SELF_MNT_NS.isPresent() && SELF_MNT_NS.equals(targetMountNS); + + if (sameMountNS) { + return TMPDIR.toString(); // we share TMPDIR in common! + } else { + // we could not read the target's mnt ns + final var procPidRootTmp = procPidPath.resolve(ROOT_TMP); + if (Files.isReadable(procPidRootTmp)) { + return procPidRootTmp.toString(); // not in the same mnt ns but tmp is accessible via /proc + } + } + + // let's attempt to obtain the pid ns, best efforts to avoid crossing pid ns boundaries (as with a container) + Optional curPidNS = Optional.empty(); + + try { + // attempt to read the target's pid ns id + curPidNS = Optional.ofNullable(Files.readSymbolicLink(procPidPath.resolve(NS_PID))); + } catch (IOException _) { + // if we fail to read the target's pid ns id then we either don't have access or it no longer exists! + if (!Files.exists(procPidPath)) { + throw new IOException(String.format("unable to attach, %s non-existent! process: %d terminated", procPidPath, pid)); + } + // the process still exists, but we don't have privileges to read its procfs + } + + // recurse "up" the process hierarchy if appropriate. PID 1 cannot have a parent in the same namespace + final var havePidNSes = prevPidNS.isPresent() && curPidNS.isPresent(); + final var ppid = ph.get().parent(); + + if (ppid.isPresent() && (havePidNSes && curPidNS.equals(prevPidNS)) || (!havePidNSes && nsPid > 1)) { + ph = ppid; + nsPid = getNamespacePid(ph.get().pid()); // get the ns pid of the parent + prevPidNS = curPidNS; + } else { + ph = Optional.empty(); + } + } + + if (target.orElseThrow(AttachNotSupportedException::new).isAlive()) { + return TMPDIR.toString(); // fallback... } else { - root = tmpdir; + throw new IOException(String.format("unable to attach, process: %d terminated", pid)); } - return root; } /* @@ -270,13 +346,12 @@ private void writeString(int fd, String s) throws IOException { write(fd, b, 0, 1); } - // Return the inner most namespaced PID if there is one, // otherwise return the original PID. - private int getNamespacePid(int pid) throws AttachNotSupportedException, IOException { + private long getNamespacePid(long pid) throws AttachNotSupportedException, IOException { // Assuming a real procfs sits beneath, reading this doesn't block // nor will it consume a lot of memory. - String statusFile = "/proc/" + pid + "/status"; + final var statusFile = PROC.resolve(Long.toString(pid)).resolve(STATUS).toString(); File f = new File(statusFile); if (!f.exists()) { return pid; // Likely a bad pid, but this is properly handled later. @@ -292,8 +367,7 @@ private int getNamespacePid(int pid) throws AttachNotSupportedException, IOExcep // The last entry represents the PID the JVM "thinks" it is. // Even in non-namespaced pids these entries should be // valid. You could refer to it as the inner most pid. - int ns_pid = Integer.parseInt(parts[parts.length - 1]); - return ns_pid; + return Long.parseLong(parts[parts.length - 1]); } } // Old kernels may not have NSpid field (i.e. 3.10). diff --git a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java index 0aa16e8479bd2..2088398834702 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java @@ -38,12 +38,19 @@ * @build EventGeneratorLoop * @run driver TestJcmdWithSideCar */ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.nio.file.Paths; import java.util.Arrays; import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; import java.util.List; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; +import java.util.regex.Pattern; import java.util.stream.Collectors; import jdk.test.lib.Container; import jdk.test.lib.Utils; @@ -60,6 +67,31 @@ public class TestJcmdWithSideCar { private static final long TIME_TO_WAIT_FOR_MAIN_METHOD_START = 50 * 1000; // milliseconds private static final String MAIN_CONTAINER_NAME = "test-container-main"; + private static final String UID = "uid"; + private static final String GID = "gid"; + + private static final Pattern ID_PATTERN = Pattern.compile("uid=(?<" + UID + ">\\d+)\\([^\\)]+\\)\\s+gid=(?<" + GID + ">\\d+).*"); + + private static final Optional USER = ProcessHandle.current().info().user().map( + user -> { + try (var br = new BufferedReader(new InputStreamReader(new ProcessBuilder("id", user).start().getInputStream()))) { + for (final var line : br.lines().toList()) { + final var m = ID_PATTERN.matcher(line); + + if (m.matches()) { + return "--user=" + m.group(UID) + ":" + m.group(GID); + } + } + } catch (IOException e) { + // do nothing... + } + + return null; + } + ); + + private static final String NET_BIND_SERVICE = "--cap-add=NET_BIND_SERVICE"; + public static void main(String[] args) throws Exception { if (!DockerTestUtils.canTestDocker()) { return; @@ -68,24 +100,28 @@ public static void main(String[] args) throws Exception { DockerTestUtils.buildJdkContainerImage(IMAGE_NAME); try { - // Start the loop process in the "main" container, then run test cases - // using a sidecar container. - MainContainer mainContainer = new MainContainer(); - mainContainer.start(); - mainContainer.waitForMainMethodStart(TIME_TO_WAIT_FOR_MAIN_METHOD_START); - - long mainProcPid = testCase01(); - - // Excluding the test case below until JDK-8228850 is fixed - // JDK-8228850: jhsdb jinfo fails with ClassCastException: - // s.j.h.oops.TypeArray cannot be cast to s.j.h.oops.Instance - // mainContainer.assertIsAlive(); - // testCase02(mainProcPid); - - mainContainer.assertIsAlive(); - testCase03(mainProcPid); + for (final boolean elevated : USER.isPresent() ? new Boolean[] { false, true } : new Boolean[] { false }) { + // Start the loop process in the "main" container, then run test cases + // using a sidecar container. + MainContainer mainContainer = new MainContainer(); + mainContainer.start(elevated); + mainContainer.waitForMainMethodStart(TIME_TO_WAIT_FOR_MAIN_METHOD_START); + + for (AttachStrategy attachStrategy : EnumSet.allOf(AttachStrategy.class)) { + long mainProcPid = testCase01(attachStrategy, elevated); + + // Excluding the test case below until JDK-8228850 is fixed + // JDK-8228850: jhsdb jinfo fails with ClassCastException: + // s.j.h.oops.TypeArray cannot be cast to s.j.h.oops.Instance + // mainContainer.assertIsAlive(); + // testCase02(mainProcPid, attachStrategy, elevated); + + mainContainer.assertIsAlive(); + testCase03(mainProcPid, attachStrategy, elevated); + } - mainContainer.waitForAndCheck(TIME_TO_RUN_MAIN_PROCESS * 1000); + mainContainer.waitForAndCheck(TIME_TO_RUN_MAIN_PROCESS * 1000); + } } finally { DockerTestUtils.removeDockerImage(IMAGE_NAME); } @@ -93,21 +129,21 @@ public static void main(String[] args) throws Exception { // Run "jcmd -l" in a sidecar container, find a target process. - private static long testCase01() throws Exception { - OutputAnalyzer out = runSideCar(MAIN_CONTAINER_NAME, "/jdk/bin/jcmd", "-l") + private static long testCase01(AttachStrategy attachStrategy, boolean elevated) throws Exception { + OutputAnalyzer out = runSideCar(MAIN_CONTAINER_NAME, attachStrategy, elevated, "/jdk/bin/jcmd", "-l") .shouldHaveExitValue(0) .shouldContain("sun.tools.jcmd.JCmd"); long pid = findProcess(out, "EventGeneratorLoop"); if (pid == -1) { - throw new RuntimeException("Could not find specified process"); + throw new RuntimeException(attachStrategy + ": Could not find specified process"); } return pid; } // run jhsdb jinfo (jhsdb uses PTRACE) - private static void testCase02(long pid) throws Exception { - runSideCar(MAIN_CONTAINER_NAME, "/jdk/bin/jhsdb", "jinfo", "--pid", "" + pid) + private static void testCase02(long pid, AttachStrategy attachStrategy, boolean elevated) throws Exception { + runSideCar(MAIN_CONTAINER_NAME, attachStrategy, elevated, "/jdk/bin/jhsdb", "jinfo", "--pid", "" + pid) .shouldHaveExitValue(0) .shouldContain("Java System Properties") .shouldContain("VM Flags"); @@ -115,11 +151,11 @@ private static void testCase02(long pid) throws Exception { // test jcmd with some commands (help, start JFR recording) // JCMD will use signal mechanism and Unix Socket - private static void testCase03(long pid) throws Exception { - runSideCar(MAIN_CONTAINER_NAME, "/jdk/bin/jcmd", "" + pid, "help") + private static void testCase03(long pid, AttachStrategy attachStrategy, boolean elevated) throws Exception { + runSideCar(MAIN_CONTAINER_NAME, attachStrategy, elevated, "/jdk/bin/jcmd", "" + pid, "help") .shouldHaveExitValue(0) .shouldContain("VM.version"); - runSideCar(MAIN_CONTAINER_NAME, "/jdk/bin/jcmd", "" + pid, "JFR.start") + runSideCar(MAIN_CONTAINER_NAME, attachStrategy, elevated, "/jdk/bin/jcmd", "" + pid, "JFR.start") .shouldHaveExitValue(0) .shouldContain("Started recording"); } @@ -127,21 +163,36 @@ private static void testCase03(long pid) throws Exception { // JCMD relies on the attach mechanism (com.sun.tools.attach), // which in turn relies on JVMSTAT mechanism, which puts its mapped - // buffers in /tmp directory (hsperfdata_). Thus, in sidecar - // we mount /tmp via --volumes-from from the main container. - private static OutputAnalyzer runSideCar(String mainContainerName, String whatToRun, - String... args) throws Exception { - List cmd = new ArrayList<>(); - String[] command = new String[] { + // buffers in /tmp directory (hsperfdata_). Thus, in the sidecar + // we have two options: + // 1. mount /tmp from the main container using --volumes-from. + // 2. access /tmp from the main container via /proc//root/tmp. + private static OutputAnalyzer runSideCar(String mainContainerName, AttachStrategy attachStrategy, boolean elevated, String whatToRun, String... args) throws Exception { + System.out.println("Attach strategy " + attachStrategy); + + List initialCommands = List.of( Container.ENGINE_COMMAND, "run", "--tty=true", "--rm", "--cap-add=SYS_PTRACE", "--sig-proxy=true", - "--pid=container:" + mainContainerName, - "--volumes-from", mainContainerName, - IMAGE_NAME, whatToRun + "--pid=container:" + mainContainerName + ); + + List attachStrategyCommands = switch (attachStrategy) { + case TMP_MOUNTED_INTO_SIDECAR -> List.of("--volumes-from", mainContainerName); + case ACCESS_TMP_VIA_PROC_ROOT -> List.of(); }; - cmd.addAll(Arrays.asList(command)); + List elevatedOpts = elevated && USER.isPresent() ? List.of(NET_BIND_SERVICE, USER.get()) : Collections.emptyList(); + + List imageAndCommand = List.of( + IMAGE_NAME, whatToRun + ); + + List cmd = new ArrayList<>(); + cmd.addAll(initialCommands); + cmd.addAll(elevatedOpts); + cmd.addAll(attachStrategyCommands); + cmd.addAll(imageAndCommand); cmd.addAll(Arrays.asList(args)); return DockerTestUtils.execute(cmd); } @@ -188,9 +239,15 @@ static class MainContainer { } }; - public Process start() throws Exception { + public Process start(final boolean elevated) throws Exception { // start "main" container (the observee) DockerRunOptions opts = commonDockerOpts("EventGeneratorLoop"); + + if (elevated && USER.isPresent()) { + opts.addDockerOpts(USER.get()); + opts.addDockerOpts(NET_BIND_SERVICE); + } + opts.addDockerOpts("--cap-add=SYS_PTRACE") .addDockerOpts("--name", MAIN_CONTAINER_NAME) .addDockerOpts("--volume", "/tmp") @@ -241,7 +298,7 @@ public void waitForAndCheck(long timeout) throws Exception { try { exitValue = p.exitValue(); } catch(IllegalThreadStateException ex) { - System.out.println("IllegalThreadStateException occured when calling exitValue()"); + System.out.println("IllegalThreadStateException occurred when calling exitValue()"); retryCount--; } } while (exitValue == -1 && retryCount > 0); @@ -253,4 +310,8 @@ public void waitForAndCheck(long timeout) throws Exception { } + private enum AttachStrategy { + TMP_MOUNTED_INTO_SIDECAR, + ACCESS_TMP_VIA_PROC_ROOT + } } From 475b8943c672349609a4839ce0a02ef995764698 Mon Sep 17 00:00:00 2001 From: Mikhail Ablakatov <164922675+mikabl-arm@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:02:59 +0000 Subject: [PATCH 056/188] 8322770: Implement C2 VectorizedHashCode on AArch64 Reviewed-by: aph, adinn --- src/hotspot/cpu/aarch64/aarch64.ad | 78 ++ src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 68 +- .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 91 ++ .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp | 3 + .../cpu/aarch64/stubGenerator_aarch64.cpp | 312 +++++ .../cpu/aarch64/stubRoutines_aarch64.cpp | 7 +- .../cpu/aarch64/stubRoutines_aarch64.hpp | 26 +- .../cpu/aarch64/vm_version_aarch64.cpp | 4 + src/hotspot/share/utilities/intpow.hpp | 46 + test/hotspot/gtest/aarch64/aarch64-asmtest.py | 111 ++ test/hotspot/gtest/aarch64/asmtest.out.h | 1189 +++++++++-------- 11 files changed, 1355 insertions(+), 580 deletions(-) create mode 100644 src/hotspot/share/utilities/intpow.hpp diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 39eae43a287e7..0a93c27c2686b 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -4931,6 +4931,60 @@ operand vRegD_V7() interface(REG_INTER); %} +operand vRegD_V12() +%{ + constraint(ALLOC_IN_RC(v12_reg)); + match(RegD); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vRegD_V13() +%{ + constraint(ALLOC_IN_RC(v13_reg)); + match(RegD); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vRegD_V14() +%{ + constraint(ALLOC_IN_RC(v14_reg)); + match(RegD); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vRegD_V15() +%{ + constraint(ALLOC_IN_RC(v15_reg)); + match(RegD); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vRegD_V16() +%{ + constraint(ALLOC_IN_RC(v16_reg)); + match(RegD); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vRegD_V17() +%{ + constraint(ALLOC_IN_RC(v17_reg)); + match(RegD); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + operand pReg() %{ constraint(ALLOC_IN_RC(pr_reg)); @@ -16551,6 +16605,30 @@ instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, ins_pipe(pipe_class_memory); %} +instruct arrays_hashcode(iRegP_R1 ary, iRegI_R2 cnt, iRegI_R0 result, immI basic_type, + vRegD_V0 vtmp0, vRegD_V1 vtmp1, vRegD_V2 vtmp2, vRegD_V3 vtmp3, + vRegD_V4 vtmp4, vRegD_V5 vtmp5, vRegD_V6 vtmp6, vRegD_V7 vtmp7, + vRegD_V12 vtmp8, vRegD_V13 vtmp9, vRegD_V14 vtmp10, + vRegD_V15 vtmp11, vRegD_V16 vtmp12, vRegD_V17 vtmp13, + rFlagsReg cr) +%{ + match(Set result (VectorizedHashCode (Binary ary cnt) (Binary result basic_type))); + effect(TEMP vtmp0, TEMP vtmp1, TEMP vtmp2, TEMP vtmp3, TEMP vtmp4, TEMP vtmp5, TEMP vtmp6, + TEMP vtmp7, TEMP vtmp8, TEMP vtmp9, TEMP vtmp10, TEMP vtmp11, TEMP vtmp12, TEMP vtmp13, + USE_KILL ary, USE_KILL cnt, USE basic_type, KILL cr); + + format %{ "Array HashCode array[] $ary,$cnt,$result,$basic_type -> $result // KILL all" %} + ins_encode %{ + address tpc = __ arrays_hashcode($ary$$Register, $cnt$$Register, $result$$Register, + (BasicType)$basic_type$$constant); + if (tpc == nullptr) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } + %} + ins_pipe(pipe_class_memory); +%} + instruct count_positives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg cr) %{ match(Set result (CountPositives ary1 len)); diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 28a0cc2c7d940..a5e0e2665af92 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2024, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -287,6 +287,11 @@ class Instruction_aarch64 { f(r->raw_encoding(), lsb + 4, lsb); } + //<0-15>reg: As `rf(FloatRegister)`, but only the lower 16 FloatRegisters are allowed. + void lrf(FloatRegister r, int lsb) { + f(r->raw_encoding(), lsb + 3, lsb); + } + void prf(PRegister r, int lsb) { f(r->raw_encoding(), lsb + 3, lsb); } @@ -765,6 +770,7 @@ class Assembler : public AbstractAssembler { #define f current_insn.f #define sf current_insn.sf #define rf current_insn.rf +#define lrf current_insn.lrf #define srf current_insn.srf #define zrf current_insn.zrf #define prf current_insn.prf @@ -1590,6 +1596,16 @@ class Assembler : public AbstractAssembler { #undef INSN + // Load/store a register, but with a BasicType parameter. Loaded signed integer values are + // extended to 64 bits. + void load(Register Rt, const Address &adr, BasicType bt) { + int op = (is_signed_subword_type(bt) || bt == T_INT) ? 0b10 : 0b01; + ld_st2(Rt, adr, exact_log2(type2aelembytes(bt)), op); + } + void store(Register Rt, const Address &adr, BasicType bt) { + ld_st2(Rt, adr, exact_log2(type2aelembytes(bt)), 0b00); + } + /* SIMD extensions * * We just use FloatRegister in the following. They are exactly the same @@ -2587,6 +2603,7 @@ template INSN(addpv, 0, 0b101111, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D INSN(smullv, 0, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(umullv, 1, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S + INSN(smlalv, 0, 0b100000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(umlalv, 1, 0b100000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(maxv, 0, 0b011001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(minv, 0, 0b011011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S @@ -2860,6 +2877,28 @@ template // FMULX - Vector - Scalar INSN(fmulxvs, 1, 0b1001); +#undef INSN + +#define INSN(NAME, op1, op2) \ + void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, int index) { \ + starti; \ + assert(T == T4H || T == T8H || T == T2S || T == T4S, "invalid arrangement"); \ + assert(index >= 0 && \ + ((T == T2S && index <= 1) || (T != T2S && index <= 3) || (T == T8H && index <= 7)), \ + "invalid index"); \ + assert((T != T4H && T != T8H) || Vm->encoding() < 16, "invalid source SIMD&FP register"); \ + f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01111, 28, 24); \ + if (T == T4H || T == T8H) { \ + f(0b01, 23, 22), f(index & 0b11, 21, 20), lrf(Vm, 16), f(index >> 2 & 1, 11); \ + } else { \ + f(0b10, 23, 22), f(index & 1, 21), rf(Vm, 16), f(index >> 1, 11); \ + } \ + f(op2, 15, 12), f(0, 10), rf(Vn, 5), rf(Vd, 0); \ + } + + // MUL - Vector - Scalar + INSN(mulvs, 0, 0b1000); + #undef INSN // Floating-point Reciprocal Estimate @@ -3023,6 +3062,33 @@ template umov(Xd, Vn, T, index); } + protected: + void _xaddwv(bool is_unsigned, FloatRegister Vd, FloatRegister Vn, SIMD_Arrangement Ta, + FloatRegister Vm, SIMD_Arrangement Tb) { + starti; + assert((Tb >> 1) + 1 == (Ta >> 1), "Incompatible arrangement"); + f(0, 31), f((int)Tb & 1, 30), f(is_unsigned ? 1 : 0, 29), f(0b01110, 28, 24); + f((int)(Ta >> 1) - 1, 23, 22), f(1, 21), rf(Vm, 16), f(0b000100, 15, 10), rf(Vn, 5), rf(Vd, 0); + } + + public: +#define INSN(NAME, assertion, is_unsigned) \ + void NAME(FloatRegister Vd, FloatRegister Vn, SIMD_Arrangement Ta, FloatRegister Vm, \ + SIMD_Arrangement Tb) { \ + assert((assertion), "invalid arrangement"); \ + _xaddwv(is_unsigned, Vd, Vn, Ta, Vm, Tb); \ + } + +public: + + INSN(uaddwv, Tb == T8B || Tb == T4H || Tb == T2S, /*is_unsigned*/true) + INSN(uaddwv2, Tb == T16B || Tb == T8H || Tb == T4S, /*is_unsigned*/true) + INSN(saddwv, Tb == T8B || Tb == T4H || Tb == T2S, /*is_unsigned*/false) + INSN(saddwv2, Tb == T16B || Tb == T8H || Tb == T4S, /*is_unsigned*/false) + +#undef INSN + + private: void _pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) { starti; diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index b4c12ecd4a849..ab2bd7d782c04 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -33,6 +33,7 @@ #include "opto/subnode.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/powerOfTwo.hpp" #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -46,6 +47,96 @@ typedef void (MacroAssembler::* chr_insn)(Register Rt, const Address &adr); +// jdk.internal.util.ArraysSupport.vectorizedHashCode +address C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register result, + BasicType eltype) { + assert_different_registers(ary, cnt, result, rscratch1, rscratch2); + + Register tmp1 = rscratch1, tmp2 = rscratch2; + + Label TAIL, STUB_SWITCH, STUB_SWITCH_OUT, LOOP, BR_BASE, LARGE, DONE; + + // Vectorization factor. Number of array elements loaded to one SIMD&FP registers by the stubs. We + // use 8H load arrangements for chars and shorts and 8B for booleans and bytes. It's possible to + // use 4H for chars and shorts instead, but using 8H gives better performance. + const size_t vf = eltype == T_BOOLEAN || eltype == T_BYTE ? 8 + : eltype == T_CHAR || eltype == T_SHORT ? 8 + : eltype == T_INT ? 4 + : 0; + guarantee(vf, "unsupported eltype"); + + // Unroll factor for the scalar loop below. The value is chosen based on performance analysis. + const size_t unroll_factor = 4; + + switch (eltype) { + case T_BOOLEAN: + BLOCK_COMMENT("arrays_hashcode(unsigned byte) {"); + break; + case T_CHAR: + BLOCK_COMMENT("arrays_hashcode(char) {"); + break; + case T_BYTE: + BLOCK_COMMENT("arrays_hashcode(byte) {"); + break; + case T_SHORT: + BLOCK_COMMENT("arrays_hashcode(short) {"); + break; + case T_INT: + BLOCK_COMMENT("arrays_hashcode(int) {"); + break; + default: + ShouldNotReachHere(); + } + + // large_arrays_hashcode(T_INT) performs worse than the scalar loop below when the Neon loop + // implemented by the stub executes just once. Call the stub only if at least two iterations will + // be executed. + const size_t large_threshold = eltype == T_INT ? vf * 2 : vf; + cmpw(cnt, large_threshold); + br(Assembler::HS, LARGE); + + bind(TAIL); + + // The andr performs cnt % uf where uf = unroll_factor. The subtract shifted by 3 offsets past + // uf - (cnt % uf) pairs of load + madd insns i.e. it only executes cnt % uf load + madd pairs. + // Iteration eats up the remainder, uf elements at a time. + assert(is_power_of_2(unroll_factor), "can't use this value to calculate the jump target PC"); + andr(tmp2, cnt, unroll_factor - 1); + adr(tmp1, BR_BASE); + sub(tmp1, tmp1, tmp2, ext::sxtw, 3); + movw(tmp2, 0x1f); + br(tmp1); + + bind(LOOP); + for (size_t i = 0; i < unroll_factor; ++i) { + load(tmp1, Address(post(ary, type2aelembytes(eltype))), eltype); + maddw(result, result, tmp2, tmp1); + } + bind(BR_BASE); + subsw(cnt, cnt, unroll_factor); + br(Assembler::HS, LOOP); + + b(DONE); + + bind(LARGE); + + RuntimeAddress stub = RuntimeAddress(StubRoutines::aarch64::large_arrays_hashcode(eltype)); + assert(stub.target() != nullptr, "array_hashcode stub has not been generated"); + address tpc = trampoline_call(stub); + if (tpc == nullptr) { + DEBUG_ONLY(reset_labels(TAIL, BR_BASE)); + postcond(pc() == badAddress); + return nullptr; + } + + bind(DONE); + + BLOCK_COMMENT("} // arrays_hashcode"); + + postcond(pc() != badAddress); + return pc(); +} + void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, Register tmpReg, Register tmp2Reg, Register tmp3Reg) { Register oop = objectReg; diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index 43e60ae5a48f8..28cc401a1b2c8 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -35,6 +35,9 @@ enum shift_kind kind = Assembler::LSL, unsigned shift = 0); public: + // jdk.internal.util.ArraysSupport.vectorizedHashCode + address arrays_hashcode(Register ary, Register cnt, Register result, BasicType eltype); + // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. void fast_lock(Register object, Register box, Register tmp, Register tmp2, Register tmp3); void fast_unlock(Register object, Register box, Register tmp, Register tmp2); diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index b3513a586de35..ac88b427459c0 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -53,7 +53,9 @@ #include "runtime/stubRoutines.hpp" #include "utilities/align.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/intpow.hpp" #include "utilities/powerOfTwo.hpp" #ifdef COMPILER2 #include "opto/runtime.hpp" @@ -5311,6 +5313,309 @@ class StubGenerator: public StubCodeGenerator { return entry; } + // result = r0 - return value. Contains initial hashcode value on entry. + // ary = r1 - array address + // cnt = r2 - elements count + // Clobbers: v0-v13, rscratch1, rscratch2 + address generate_large_arrays_hashcode(BasicType eltype) { + const Register result = r0, ary = r1, cnt = r2; + const FloatRegister vdata0 = v3, vdata1 = v2, vdata2 = v1, vdata3 = v0; + const FloatRegister vmul0 = v4, vmul1 = v5, vmul2 = v6, vmul3 = v7; + const FloatRegister vpow = v8; // powers of 31: <31^3, ..., 31^0> + const FloatRegister vpowm = v9; + + assert_different_registers(ary, cnt, result); + assert_different_registers(vdata0, vdata1, vdata2, vdata3, vmul0, vmul1, vmul2, vmul3, vpow, + vpowm); + + Label SMALL_LOOP, LARGE_LOOP_PREHEADER, LARGE_LOOP, TAIL, TAIL_SHORTCUT, BR_BASE; + + unsigned int vf; // vectorization factor + bool multiply_by_halves; + Assembler::SIMD_Arrangement load_arrangement; + switch (eltype) { + case T_BOOLEAN: + case T_BYTE: + load_arrangement = Assembler::T8B; + multiply_by_halves = true; + vf = 8; + break; + case T_CHAR: + case T_SHORT: + load_arrangement = Assembler::T8H; + multiply_by_halves = true; + vf = 8; + break; + case T_INT: + load_arrangement = Assembler::T4S; + multiply_by_halves = false; + vf = 4; + break; + default: + ShouldNotReachHere(); + } + + // Unroll factor + const unsigned uf = 4; + + // Effective vectorization factor + const unsigned evf = vf * uf; + + __ align(CodeEntryAlignment); + + const char *mark_name = ""; + switch (eltype) { + case T_BOOLEAN: + mark_name = "_large_arrays_hashcode_boolean"; + break; + case T_BYTE: + mark_name = "_large_arrays_hashcode_byte"; + break; + case T_CHAR: + mark_name = "_large_arrays_hashcode_char"; + break; + case T_SHORT: + mark_name = "_large_arrays_hashcode_short"; + break; + case T_INT: + mark_name = "_large_arrays_hashcode_int"; + break; + default: + mark_name = "_large_arrays_hashcode_incorrect_type"; + __ should_not_reach_here(); + }; + + StubCodeMark mark(this, "StubRoutines", mark_name); + + address entry = __ pc(); + __ enter(); + + // Put 0-3'th powers of 31 into a single SIMD register together. The register will be used in + // the SMALL and LARGE LOOPS' epilogues. The initialization is hoisted here and the register's + // value shouldn't change throughout both loops. + __ movw(rscratch1, intpow(31U, 3)); + __ mov(vpow, Assembler::S, 0, rscratch1); + __ movw(rscratch1, intpow(31U, 2)); + __ mov(vpow, Assembler::S, 1, rscratch1); + __ movw(rscratch1, intpow(31U, 1)); + __ mov(vpow, Assembler::S, 2, rscratch1); + __ movw(rscratch1, intpow(31U, 0)); + __ mov(vpow, Assembler::S, 3, rscratch1); + + __ mov(vmul0, Assembler::T16B, 0); + __ mov(vmul0, Assembler::S, 3, result); + + __ andr(rscratch2, cnt, (uf - 1) * vf); + __ cbz(rscratch2, LARGE_LOOP_PREHEADER); + + __ movw(rscratch1, intpow(31U, multiply_by_halves ? vf / 2 : vf)); + __ mov(vpowm, Assembler::S, 0, rscratch1); + + // SMALL LOOP + __ bind(SMALL_LOOP); + + __ ld1(vdata0, load_arrangement, Address(__ post(ary, vf * type2aelembytes(eltype)))); + __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 0); + __ subsw(rscratch2, rscratch2, vf); + + if (load_arrangement == Assembler::T8B) { + // Extend 8B to 8H to be able to use vector multiply + // instructions + assert(load_arrangement == Assembler::T8B, "expected to extend 8B to 8H"); + if (is_signed_subword_type(eltype)) { + __ sxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); + } else { + __ uxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); + } + } + + switch (load_arrangement) { + case Assembler::T4S: + __ addv(vmul0, load_arrangement, vmul0, vdata0); + break; + case Assembler::T8B: + case Assembler::T8H: + assert(is_subword_type(eltype), "subword type expected"); + if (is_signed_subword_type(eltype)) { + __ saddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); + } else { + __ uaddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); + } + break; + default: + __ should_not_reach_here(); + } + + // Process the upper half of a vector + if (load_arrangement == Assembler::T8B || load_arrangement == Assembler::T8H) { + __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 0); + if (is_signed_subword_type(eltype)) { + __ saddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); + } else { + __ uaddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); + } + } + + __ br(Assembler::HI, SMALL_LOOP); + + // SMALL LOOP'S EPILOQUE + __ lsr(rscratch2, cnt, exact_log2(evf)); + __ cbnz(rscratch2, LARGE_LOOP_PREHEADER); + + __ mulv(vmul0, Assembler::T4S, vmul0, vpow); + __ addv(vmul0, Assembler::T4S, vmul0); + __ umov(result, vmul0, Assembler::S, 0); + + // TAIL + __ bind(TAIL); + + // The andr performs cnt % vf. The subtract shifted by 3 offsets past vf - 1 - (cnt % vf) pairs + // of load + madd insns i.e. it only executes cnt % vf load + madd pairs. + assert(is_power_of_2(vf), "can't use this value to calculate the jump target PC"); + __ andr(rscratch2, cnt, vf - 1); + __ bind(TAIL_SHORTCUT); + __ adr(rscratch1, BR_BASE); + __ sub(rscratch1, rscratch1, rscratch2, ext::uxtw, 3); + __ movw(rscratch2, 0x1f); + __ br(rscratch1); + + for (size_t i = 0; i < vf - 1; ++i) { + __ load(rscratch1, Address(__ post(ary, type2aelembytes(eltype))), + eltype); + __ maddw(result, result, rscratch2, rscratch1); + } + __ bind(BR_BASE); + + __ leave(); + __ ret(lr); + + // LARGE LOOP + __ bind(LARGE_LOOP_PREHEADER); + + __ lsr(rscratch2, cnt, exact_log2(evf)); + + if (multiply_by_halves) { + // 31^4 - multiplier between lower and upper parts of a register + __ movw(rscratch1, intpow(31U, vf / 2)); + __ mov(vpowm, Assembler::S, 1, rscratch1); + // 31^28 - remainder of the iteraion multiplier, 28 = 32 - 4 + __ movw(rscratch1, intpow(31U, evf - vf / 2)); + __ mov(vpowm, Assembler::S, 0, rscratch1); + } else { + // 31^16 + __ movw(rscratch1, intpow(31U, evf)); + __ mov(vpowm, Assembler::S, 0, rscratch1); + } + + __ mov(vmul3, Assembler::T16B, 0); + __ mov(vmul2, Assembler::T16B, 0); + __ mov(vmul1, Assembler::T16B, 0); + + __ bind(LARGE_LOOP); + + __ mulvs(vmul3, Assembler::T4S, vmul3, vpowm, 0); + __ mulvs(vmul2, Assembler::T4S, vmul2, vpowm, 0); + __ mulvs(vmul1, Assembler::T4S, vmul1, vpowm, 0); + __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 0); + + __ ld1(vdata3, vdata2, vdata1, vdata0, load_arrangement, + Address(__ post(ary, evf * type2aelembytes(eltype)))); + + if (load_arrangement == Assembler::T8B) { + // Extend 8B to 8H to be able to use vector multiply + // instructions + assert(load_arrangement == Assembler::T8B, "expected to extend 8B to 8H"); + if (is_signed_subword_type(eltype)) { + __ sxtl(vdata3, Assembler::T8H, vdata3, load_arrangement); + __ sxtl(vdata2, Assembler::T8H, vdata2, load_arrangement); + __ sxtl(vdata1, Assembler::T8H, vdata1, load_arrangement); + __ sxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); + } else { + __ uxtl(vdata3, Assembler::T8H, vdata3, load_arrangement); + __ uxtl(vdata2, Assembler::T8H, vdata2, load_arrangement); + __ uxtl(vdata1, Assembler::T8H, vdata1, load_arrangement); + __ uxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); + } + } + + switch (load_arrangement) { + case Assembler::T4S: + __ addv(vmul3, load_arrangement, vmul3, vdata3); + __ addv(vmul2, load_arrangement, vmul2, vdata2); + __ addv(vmul1, load_arrangement, vmul1, vdata1); + __ addv(vmul0, load_arrangement, vmul0, vdata0); + break; + case Assembler::T8B: + case Assembler::T8H: + assert(is_subword_type(eltype), "subword type expected"); + if (is_signed_subword_type(eltype)) { + __ saddwv(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T4H); + __ saddwv(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T4H); + __ saddwv(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T4H); + __ saddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); + } else { + __ uaddwv(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T4H); + __ uaddwv(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T4H); + __ uaddwv(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T4H); + __ uaddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); + } + break; + default: + __ should_not_reach_here(); + } + + // Process the upper half of a vector + if (load_arrangement == Assembler::T8B || load_arrangement == Assembler::T8H) { + __ mulvs(vmul3, Assembler::T4S, vmul3, vpowm, 1); + __ mulvs(vmul2, Assembler::T4S, vmul2, vpowm, 1); + __ mulvs(vmul1, Assembler::T4S, vmul1, vpowm, 1); + __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 1); + if (is_signed_subword_type(eltype)) { + __ saddwv2(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T8H); + __ saddwv2(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T8H); + __ saddwv2(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T8H); + __ saddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); + } else { + __ uaddwv2(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T8H); + __ uaddwv2(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T8H); + __ uaddwv2(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T8H); + __ uaddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); + } + } + + __ subsw(rscratch2, rscratch2, 1); + __ br(Assembler::HI, LARGE_LOOP); + + __ mulv(vmul3, Assembler::T4S, vmul3, vpow); + __ addv(vmul3, Assembler::T4S, vmul3); + __ umov(result, vmul3, Assembler::S, 0); + + __ mov(rscratch2, intpow(31U, vf)); + + __ mulv(vmul2, Assembler::T4S, vmul2, vpow); + __ addv(vmul2, Assembler::T4S, vmul2); + __ umov(rscratch1, vmul2, Assembler::S, 0); + __ maddw(result, result, rscratch2, rscratch1); + + __ mulv(vmul1, Assembler::T4S, vmul1, vpow); + __ addv(vmul1, Assembler::T4S, vmul1); + __ umov(rscratch1, vmul1, Assembler::S, 0); + __ maddw(result, result, rscratch2, rscratch1); + + __ mulv(vmul0, Assembler::T4S, vmul0, vpow); + __ addv(vmul0, Assembler::T4S, vmul0); + __ umov(rscratch1, vmul0, Assembler::S, 0); + __ maddw(result, result, rscratch2, rscratch1); + + __ andr(rscratch2, cnt, vf - 1); + __ cbnz(rscratch2, TAIL_SHORTCUT); + + __ leave(); + __ ret(lr); + + return entry; + } + address generate_dsin_dcos(bool isCos) { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", isCos ? "libmDcos" : "libmDsin"); @@ -8257,6 +8562,13 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::aarch64::_large_array_equals = generate_large_array_equals(); } + // arrays_hascode stub for large arrays. + StubRoutines::aarch64::_large_arrays_hashcode_boolean = generate_large_arrays_hashcode(T_BOOLEAN); + StubRoutines::aarch64::_large_arrays_hashcode_byte = generate_large_arrays_hashcode(T_BYTE); + StubRoutines::aarch64::_large_arrays_hashcode_char = generate_large_arrays_hashcode(T_CHAR); + StubRoutines::aarch64::_large_arrays_hashcode_int = generate_large_arrays_hashcode(T_INT); + StubRoutines::aarch64::_large_arrays_hashcode_short = generate_large_arrays_hashcode(T_SHORT); + // byte_array_inflate stub for large arrays. StubRoutines::aarch64::_large_byte_array_inflate = generate_large_byte_array_inflate(); diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index 80875a3b3cdcf..dee615df5a51f 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -48,6 +48,11 @@ address StubRoutines::aarch64::_zero_blocks = nullptr; address StubRoutines::aarch64::_count_positives = nullptr; address StubRoutines::aarch64::_count_positives_long = nullptr; address StubRoutines::aarch64::_large_array_equals = nullptr; +address StubRoutines::aarch64::_large_arrays_hashcode_boolean = nullptr; +address StubRoutines::aarch64::_large_arrays_hashcode_byte = nullptr; +address StubRoutines::aarch64::_large_arrays_hashcode_char = nullptr; +address StubRoutines::aarch64::_large_arrays_hashcode_int = nullptr; +address StubRoutines::aarch64::_large_arrays_hashcode_short = nullptr; address StubRoutines::aarch64::_compare_long_string_LL = nullptr; address StubRoutines::aarch64::_compare_long_string_UU = nullptr; address StubRoutines::aarch64::_compare_long_string_LU = nullptr; diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp index e6438908ce4c6..7d3b72a88363d 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -62,6 +62,11 @@ class aarch64 { static address _zero_blocks; static address _large_array_equals; + static address _large_arrays_hashcode_boolean; + static address _large_arrays_hashcode_byte; + static address _large_arrays_hashcode_char; + static address _large_arrays_hashcode_int; + static address _large_arrays_hashcode_short; static address _compare_long_string_LL; static address _compare_long_string_LU; static address _compare_long_string_UL; @@ -145,6 +150,25 @@ class aarch64 { return _large_array_equals; } + static address large_arrays_hashcode(BasicType eltype) { + switch (eltype) { + case T_BOOLEAN: + return _large_arrays_hashcode_boolean; + case T_BYTE: + return _large_arrays_hashcode_byte; + case T_CHAR: + return _large_arrays_hashcode_char; + case T_SHORT: + return _large_arrays_hashcode_short; + case T_INT: + return _large_arrays_hashcode_int; + default: + ShouldNotReachHere(); + } + + return nullptr; + } + static address compare_long_string_LL() { return _compare_long_string_LL; } diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index d71162ac568ea..81e39113afaab 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -574,6 +574,10 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) { FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true); } + + if (FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) { + FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true); + } #endif _spin_wait = get_spin_wait_desc(); diff --git a/src/hotspot/share/utilities/intpow.hpp b/src/hotspot/share/utilities/intpow.hpp new file mode 100644 index 0000000000000..0b441a55c4c96 --- /dev/null +++ b/src/hotspot/share/utilities/intpow.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, Arm 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. + * + */ + +#ifndef SHARE_UTILITIES_INTPOW_HPP +#define SHARE_UTILITIES_INTPOW_HPP + +#include "metaprogramming/enableIf.hpp" +#include +#include + +// Raise v to the power p mod 2**N, where N is the width of the type T. +template ::value && std::is_unsigned::value)> +static constexpr T intpow(T v, unsigned p) { + if (p == 0) { + return 1; + } + + // We use exponentiation by squaring to calculate the required power. + T a = intpow(v, p / 2); + T b = (p % 2) ? v : 1; + + return a * a * b; +} + +#endif // SHARE_UTILITIES_INTPOW_HPP diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index 7e9d557d11cb7..64f3e787356e0 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -77,11 +77,29 @@ class FloatRegister(Register): def __str__(self): return self.astr("v") + def generate(self): + self.number = random.randint(0, 31) + return self + def nextReg(self): next = FloatRegister() next.number = (self.number + 1) % 32 return next +class LowFloatRegister(Register): + + def __str__(self): + return self.astr("v") + + def generate(self): + self.number = random.randint(0, 15) + return self + + def nextReg(self): + next = FloatRegister() + next.number = (self.number + 1) % 16 + return next + class GeneralRegister(Register): def __str__(self): @@ -1271,6 +1289,75 @@ def astr(self): def aname(self): return self._name +class VectorScalarNEONInstruction(Instruction): + def __init__(self, args): + self._name, self.insname, self.arrangement = args + + def generate(self): + vectorLength = {"8B" : 8, "16B" : 16, "4H" : 4, "8H" : 8, "2S" : 2, "4S" : 4, "1D" : 1, "2D" : 2} [self.arrangement] + self.elemIndex = random.randrange(0, vectorLength) + self.elemSizeSpecifier = self.arrangement[len(self.arrangement) - 1:] + self._firstSIMDreg = LowFloatRegister().generate() + self.numRegs = 3 + return self + + def cstr(self): + buf = Instruction.cstr(self) + str(self._firstSIMDreg) + buf = '%s, __ T%s' % (buf, self.arrangement) + current = self._firstSIMDreg + for cnt in range(1, self.numRegs - 1): + buf = '%s, %s' % (buf, current.nextReg()) + current = current.nextReg() + buf = '%s, %s, %d' % (buf, current.nextReg(), self.elemIndex) + return '%s);' % (buf) + + def astr(self): + buf = '%s\t%s.%s' % (self.insname, self._firstSIMDreg, self.arrangement) + current = self._firstSIMDreg + for cnt in range(1, self.numRegs - 1): + buf = '%s, %s.%s' % (buf, current.nextReg(), self.arrangement) + current = current.nextReg() + buf = '%s, %s.%s[%d]' % (buf, current.nextReg(), self.elemSizeSpecifier, self.elemIndex) + return buf + + def aname(self): + return self._name + +class WideningNEONInstruction(Instruction): + def __init__(self, args): + self._name, self.insname, self.widerArrangement, self.narrowerArrangement = args + + def generate(self): + self._firstSIMDreg = FloatRegister().generate() + return self + + def cstr(self): + buf = Instruction.cstr(self) + str(self._firstSIMDreg) + current = self._firstSIMDreg + for cnt in range(1, self.numWiderRegs): + buf = '%s, %s' % (buf, current.nextReg()) + current = current.nextReg() + buf = '%s, __ T%s' % (buf, self.widerArrangement) + for cnt in range(0, self.numNarrowerRegs): + buf = '%s, %s' % (buf, current.nextReg()) + current = current.nextReg() + buf = '%s, __ T%s' % (buf, self.narrowerArrangement) + return '%s);' % (buf) + + def astr(self): + buf = '%s\t%s.%s' % (self.insname, self._firstSIMDreg, self.widerArrangement) + current = self._firstSIMDreg + for cnt in range(1, self.numWiderRegs): + buf = '%s, %s.%s' % (buf, current.nextReg(), self.widerArrangement) + current = current.nextReg() + for cnt in range(0, self.numNarrowerRegs): + buf = '%s, %s.%s' % (buf, current.nextReg(), self.narrowerArrangement) + current = current.nextReg() + return buf + + def aname(self): + return self._name + class SHA512SIMDOp(Instruction): def generate(self): @@ -1390,6 +1477,10 @@ class TwoRegNEONOp(CommonNEONInstruction): class ThreeRegNEONOp(TwoRegNEONOp): numRegs = 3 +class AddWideNEONOp(WideningNEONInstruction): + numWiderRegs = 2 + numNarrowerRegs = 1 + class NEONFloatCompareWithZero(TwoRegNEONOp): def __init__(self, args): self._name = 'fcm' @@ -1748,6 +1839,17 @@ def generate(kind, names): ["facgt", "facgt", "2D"], ]) +generate(VectorScalarNEONInstruction, + [["fmlavs", "fmla", "2S"], ["mulvs", "mul", "4S"], + ["fmlavs", "fmla", "2D"], + ["fmlsvs", "fmls", "2S"], ["mulvs", "mul", "4S"], + ["fmlsvs", "fmls", "2D"], + ["fmulxvs", "fmulx", "2S"], ["mulvs", "mul", "4S"], + ["fmulxvs", "fmulx", "2D"], + ["mulvs", "mul", "4H"], ["mulvs", "mul", "8H"], + ["mulvs", "mul", "2S"], ["mulvs", "mul", "4S"], + ]) + neonVectorCompareInstructionPrefix = ['cm', 'fcm'] neonIntegerVectorCompareConditions = ['GT', 'GE', 'EQ', 'HI', 'HS'] neonFloatVectorCompareConditions = ['EQ', 'GT', 'GE'] @@ -2081,6 +2183,15 @@ def generate(kind, names): generate(SVEReductionOp, [["andv", 0], ["orv", 0], ["eorv", 0], ["smaxv", 0], ["sminv", 0], ["fminv", 2], ["fmaxv", 2], ["fadda", 2], ["uaddv", 0]]) +generate(AddWideNEONOp, + [["saddwv", "saddw", "8H", "8B"], ["saddwv2", "saddw2", "8H", "16B"], + ["saddwv", "saddw", "4S", "4H"], ["saddwv2", "saddw2", "4S", "8H"], + ["saddwv", "saddw", "2D", "2S"], ["saddwv2", "saddw2", "2D", "4S"], + ["uaddwv", "uaddw", "8H", "8B"], ["uaddwv2", "uaddw2", "8H", "16B"], + ["uaddwv", "uaddw", "4S", "4H"], ["uaddwv2", "uaddw2", "4S", "8H"], + ["uaddwv", "uaddw", "2D", "2S"], ["uaddwv2", "uaddw2", "2D", "4S"], + ]) + print "\n __ bind(forth);" outfile.write("forth:\n") diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index b8260aaf932d1..9805a05c5c150 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -293,9 +293,9 @@ __ ldrshw(r5, Address(r3, 12)); // ldrsh w5, [x3, 12] __ ldrsw(r27, Address(r24, 17)); // ldrsw x27, [x24, 17] __ ldrd(v13, Address(r29, -35)); // ldr d13, [x29, -35] - __ ldrs(v22, Address(r9, -47)); // ldr s22, [x9, -47] + __ ldrs(v23, Address(r9, -47)); // ldr s23, [x9, -47] __ strd(v11, Address(r0, 9)); // str d11, [x0, 9] - __ strs(v20, Address(r0, -127)); // str s20, [x0, -127] + __ strs(v21, Address(r0, -127)); // str s21, [x0, -127] // pre // LoadStoreOp @@ -314,7 +314,7 @@ __ ldrd(v0, Address(__ pre(r14, -54))); // ldr d0, [x14, -54]! __ ldrs(v3, Address(__ pre(r1, 40))); // ldr s3, [x1, 40]! __ strd(v4, Address(__ pre(r14, -94))); // str d4, [x14, -94]! - __ strs(v17, Address(__ pre(r28, -54))); // str s17, [x28, -54]! + __ strs(v18, Address(__ pre(r28, -54))); // str s18, [x28, -54]! // post // LoadStoreOp @@ -331,8 +331,8 @@ __ ldrshw(r3, Address(__ post(r11, -48))); // ldrsh w3, [x11], -48 __ ldrsw(r25, Address(__ post(r23, 22))); // ldrsw x25, [x23], 22 __ ldrd(v0, Address(__ post(r10, -215))); // ldr d0, [x10], -215 - __ ldrs(v17, Address(__ post(r6, 55))); // ldr s17, [x6], 55 - __ strd(v13, Address(__ post(r21, -234))); // str d13, [x21], -234 + __ ldrs(v19, Address(__ post(r6, 55))); // ldr s19, [x6], 55 + __ strd(v14, Address(__ post(r21, -234))); // str d14, [x21], -234 __ strs(v0, Address(__ post(r22, -70))); // str s0, [x22], -70 // base_plus_reg @@ -349,9 +349,9 @@ __ ldrsh(r21, Address(r30, r30, Address::sxtw(1))); // ldrsh x21, [x30, w30, sxtw #1] __ ldrshw(r11, Address(r10, r28, Address::sxtw(1))); // ldrsh w11, [x10, w28, sxtw #1] __ ldrsw(r28, Address(r19, r10, Address::uxtw(0))); // ldrsw x28, [x19, w10, uxtw #0] - __ ldrd(v29, Address(r29, r14, Address::sxtw(0))); // ldr d29, [x29, w14, sxtw #0] + __ ldrd(v30, Address(r29, r14, Address::sxtw(0))); // ldr d30, [x29, w14, sxtw #0] __ ldrs(v8, Address(r5, r5, Address::sxtw(2))); // ldr s8, [x5, w5, sxtw #2] - __ strd(v24, Address(r8, r13, Address::sxtx(0))); // str d24, [x8, x13, sxtx #0] + __ strd(v25, Address(r8, r13, Address::sxtx(0))); // str d25, [x8, x13, sxtx #0] __ strs(v17, Address(r24, r26, Address::lsl(2))); // str s17, [x24, x26, lsl #2] // base_plus_scaled_offset @@ -370,7 +370,7 @@ __ ldrsw(r10, Address(r7, 6372)); // ldrsw x10, [x7, 6372] __ ldrd(v3, Address(r25, 12392)); // ldr d3, [x25, 12392] __ ldrs(v12, Address(r9, 7840)); // ldr s12, [x9, 7840] - __ strd(v23, Address(r1, 12728)); // str d23, [x1, 12728] + __ strd(v24, Address(r1, 12728)); // str d24, [x1, 12728] __ strs(v3, Address(r20, 6924)); // str s3, [x20, 6924] // pcrel @@ -484,63 +484,63 @@ __ umsubl(r13, r10, r7, r5); // umsubl x13, w10, w7, x5 // ThreeRegFloatOp - __ fabds(v29, v15, v3); // fabd s29, s15, s3 - __ fmuls(v11, v12, v15); // fmul s11, s12, s15 - __ fdivs(v30, v30, v17); // fdiv s30, s30, s17 - __ fadds(v19, v20, v15); // fadd s19, s20, s15 - __ fsubs(v15, v9, v21); // fsub s15, s9, s21 - __ fabdd(v2, v9, v27); // fabd d2, d9, d27 - __ fmuld(v7, v29, v30); // fmul d7, d29, d30 - __ fdivd(v17, v1, v2); // fdiv d17, d1, d2 + __ fabds(v30, v15, v3); // fabd s30, s15, s3 + __ fmuls(v12, v12, v16); // fmul s12, s12, s16 + __ fdivs(v31, v31, v18); // fdiv s31, s31, s18 + __ fadds(v19, v21, v16); // fadd s19, s21, s16 + __ fsubs(v15, v10, v21); // fsub s15, s10, s21 + __ fabdd(v2, v10, v28); // fabd d2, d10, d28 + __ fmuld(v7, v30, v31); // fmul d7, d30, d31 + __ fdivd(v18, v1, v2); // fdiv d18, d1, d2 __ faddd(v6, v10, v3); // fadd d6, d10, d3 - __ fsubd(v24, v11, v7); // fsub d24, d11, d7 + __ fsubd(v25, v11, v7); // fsub d25, d11, d7 // FourRegFloatOp - __ fmadds(v1, v11, v0, v3); // fmadd s1, s11, s0, s3 - __ fmsubs(v17, v28, v6, v22); // fmsub s17, s28, s6, s22 - __ fnmadds(v6, v0, v27, v26); // fnmadd s6, s0, s27, s26 - __ fnmadds(v2, v5, v7, v28); // fnmadd s2, s5, s7, s28 - __ fmaddd(v11, v25, v13, v11); // fmadd d11, d25, d13, d11 - __ fmsubd(v23, v19, v8, v17); // fmsub d23, d19, d8, d17 - __ fnmaddd(v21, v25, v20, v19); // fnmadd d21, d25, d20, d19 - __ fnmaddd(v17, v2, v29, v22); // fnmadd d17, d2, d29, d22 + __ fmadds(v1, v12, v0, v3); // fmadd s1, s12, s0, s3 + __ fmsubs(v19, v29, v6, v23); // fmsub s19, s29, s6, s23 + __ fnmadds(v6, v0, v28, v27); // fnmadd s6, s0, s28, s27 + __ fnmadds(v2, v5, v7, v29); // fnmadd s2, s5, s7, s29 + __ fmaddd(v12, v25, v13, v12); // fmadd d12, d25, d13, d12 + __ fmsubd(v24, v19, v8, v18); // fmsub d24, d19, d8, d18 + __ fnmaddd(v22, v26, v21, v20); // fnmadd d22, d26, d21, d20 + __ fnmaddd(v19, v2, v30, v22); // fnmadd d19, d2, d30, d22 // TwoRegFloatOp - __ fmovs(v8, v21); // fmov s8, s21 - __ fabss(v19, v20); // fabs s19, s20 - __ fnegs(v11, v17); // fneg s11, s17 - __ fsqrts(v20, v6); // fsqrt s20, s6 - __ fcvts(v15, v3); // fcvt d15, s3 - __ fcvtsh(v3, v28); // fcvt h3, s28 - __ fcvths(v3, v27); // fcvt s3, h27 - __ fmovd(v14, v14); // fmov d14, d14 - __ fabsd(v10, v12); // fabs d10, d12 - __ fnegd(v11, v17); // fneg d11, d17 - __ fsqrtd(v10, v25); // fsqrt d10, d25 + __ fmovs(v8, v22); // fmov s8, s22 + __ fabss(v19, v21); // fabs s19, s21 + __ fnegs(v12, v18); // fneg s12, s18 + __ fsqrts(v21, v6); // fsqrt s21, s6 + __ fcvts(v16, v3); // fcvt d16, s3 + __ fcvtsh(v3, v29); // fcvt h3, s29 + __ fcvths(v3, v28); // fcvt s3, h28 + __ fmovd(v15, v14); // fmov d15, d14 + __ fabsd(v10, v13); // fabs d10, d13 + __ fnegd(v12, v18); // fneg d12, d18 + __ fsqrtd(v10, v26); // fsqrt d10, d26 __ fcvtd(v7, v7); // fcvt s7, d7 // FloatConvertOp - __ fcvtzsw(r14, v28); // fcvtzs w14, s28 - __ fcvtzs(r0, v22); // fcvtzs x0, s22 + __ fcvtzsw(r14, v29); // fcvtzs w14, s29 + __ fcvtzs(r0, v23); // fcvtzs x0, s23 __ fcvtzdw(r0, v12); // fcvtzs w0, d12 - __ fcvtzd(r23, v13); // fcvtzs x23, d13 + __ fcvtzd(r23, v14); // fcvtzs x23, d14 __ scvtfws(v13, r7); // scvtf s13, w7 - __ scvtfs(v14, r7); // scvtf s14, x7 - __ scvtfwd(v8, r20); // scvtf d8, w20 - __ scvtfd(v17, r28); // scvtf d17, x28 + __ scvtfs(v15, r7); // scvtf s15, x7 + __ scvtfwd(v9, r20); // scvtf d9, w20 + __ scvtfd(v19, r28); // scvtf d19, x28 __ fcvtassw(r30, v16); // fcvtas w30, s16 __ fcvtasd(r2, v9); // fcvtas x2, d9 - __ fcvtmssw(r16, v20); // fcvtms w16, s20 + __ fcvtmssw(r16, v21); // fcvtms w16, s21 __ fcvtmsd(r29, v4); // fcvtms x29, d4 - __ fmovs(r1, v26); // fmov w1, s26 - __ fmovd(r24, v23); // fmov x24, d23 + __ fmovs(r1, v27); // fmov w1, s27 + __ fmovd(r24, v24); // fmov x24, d24 __ fmovs(v14, r21); // fmov s14, w21 - __ fmovd(v12, r5); // fmov d12, x5 + __ fmovd(v13, r5); // fmov d13, x5 // TwoRegFloatOp - __ fcmps(v12, v24); // fcmp s12, s24 - __ fcmpd(v24, v29); // fcmp d24, d29 - __ fcmps(v27, 0.0); // fcmp s27, #0.0 + __ fcmps(v12, v25); // fcmp s12, s25 + __ fcmpd(v25, v30); // fcmp d25, d30 + __ fcmps(v28, 0.0); // fcmp s28, #0.0 __ fcmpd(v21, 0.0); // fcmp d21, #0.0 // LoadStorePairOp @@ -573,250 +573,265 @@ // LdStNEONOp __ ld1(v0, __ T8B, Address(r11)); // ld1 {v0.8B}, [x11] __ ld1(v16, v17, __ T16B, Address(__ post(r26, 32))); // ld1 {v16.16B, v17.16B}, [x26], 32 - __ ld1(v21, v22, v23, __ T1D, Address(__ post(r26, r17))); // ld1 {v21.1D, v22.1D, v23.1D}, [x26], x17 - __ ld1(v26, v27, v28, v29, __ T8H, Address(__ post(r29, 64))); // ld1 {v26.8H, v27.8H, v28.8H, v29.8H}, [x29], 64 - __ ld1r(v21, __ T8B, Address(r6)); // ld1r {v21.8B}, [x6] - __ ld1r(v13, __ T4S, Address(__ post(r29, 4))); // ld1r {v13.4S}, [x29], 4 - __ ld1r(v21, __ T1D, Address(__ post(r12, r16))); // ld1r {v21.1D}, [x12], x16 + __ ld1(v22, v23, v24, __ T1D, Address(__ post(r26, r17))); // ld1 {v22.1D, v23.1D, v24.1D}, [x26], x17 + __ ld1(v27, v28, v29, v30, __ T8H, Address(__ post(r29, 64))); // ld1 {v27.8H, v28.8H, v29.8H, v30.8H}, [x29], 64 + __ ld1r(v22, __ T8B, Address(r6)); // ld1r {v22.8B}, [x6] + __ ld1r(v14, __ T4S, Address(__ post(r29, 4))); // ld1r {v14.4S}, [x29], 4 + __ ld1r(v22, __ T1D, Address(__ post(r12, r16))); // ld1r {v22.1D}, [x12], x16 __ ld2(v1, v2, __ T2D, Address(r0)); // ld2 {v1.2D, v2.2D}, [x0] - __ ld2(v9, v10, __ T4H, Address(__ post(r21, 16))); // ld2 {v9.4H, v10.4H}, [x21], 16 + __ ld2(v10, v11, __ T4H, Address(__ post(r21, 16))); // ld2 {v10.4H, v11.4H}, [x21], 16 __ ld2r(v7, v8, __ T16B, Address(r25)); // ld2r {v7.16B, v8.16B}, [x25] - __ ld2r(v8, v9, __ T2S, Address(__ post(r9, 8))); // ld2r {v8.2S, v9.2S}, [x9], 8 + __ ld2r(v9, v10, __ T2S, Address(__ post(r9, 8))); // ld2r {v9.2S, v10.2S}, [x9], 8 __ ld2r(v9, v10, __ T2D, Address(__ post(r12, r14))); // ld2r {v9.2D, v10.2D}, [x12], x14 __ ld3(v7, v8, v9, __ T4S, Address(__ post(r4, r17))); // ld3 {v7.4S, v8.4S, v9.4S}, [x4], x17 __ ld3(v23, v24, v25, __ T2S, Address(r17)); // ld3 {v23.2S, v24.2S, v25.2S}, [x17] - __ ld3r(v3, v4, v5, __ T8H, Address(r22)); // ld3r {v3.8H, v4.8H, v5.8H}, [x22] - __ ld3r(v12, v13, v14, __ T4S, Address(__ post(r2, 12))); // ld3r {v12.4S, v13.4S, v14.4S}, [x2], 12 - __ ld3r(v15, v16, v17, __ T1D, Address(__ post(r10, r12))); // ld3r {v15.1D, v16.1D, v17.1D}, [x10], x12 + __ ld3r(v4, v5, v6, __ T8H, Address(r22)); // ld3r {v4.8H, v5.8H, v6.8H}, [x22] + __ ld3r(v13, v14, v15, __ T4S, Address(__ post(r2, 12))); // ld3r {v13.4S, v14.4S, v15.4S}, [x2], 12 + __ ld3r(v16, v17, v18, __ T1D, Address(__ post(r10, r12))); // ld3r {v16.1D, v17.1D, v18.1D}, [x10], x12 __ ld4(v4, v5, v6, v7, __ T8H, Address(__ post(r2, 64))); // ld4 {v4.8H, v5.8H, v6.8H, v7.8H}, [x2], 64 __ ld4(v6, v7, v8, v9, __ T8B, Address(__ post(r20, r11))); // ld4 {v6.8B, v7.8B, v8.8B, v9.8B}, [x20], x11 - __ ld4r(v11, v12, v13, v14, __ T8B, Address(r12)); // ld4r {v11.8B, v12.8B, v13.8B, v14.8B}, [x12] - __ ld4r(v15, v16, v17, v18, __ T4H, Address(__ post(r17, 8))); // ld4r {v15.4H, v16.4H, v17.4H, v18.4H}, [x17], 8 + __ ld4r(v12, v13, v14, v15, __ T8B, Address(r12)); // ld4r {v12.8B, v13.8B, v14.8B, v15.8B}, [x12] + __ ld4r(v16, v17, v18, v19, __ T4H, Address(__ post(r17, 8))); // ld4r {v16.4H, v17.4H, v18.4H, v19.4H}, [x17], 8 __ ld4r(v14, v15, v16, v17, __ T2S, Address(__ post(r25, r16))); // ld4r {v14.2S, v15.2S, v16.2S, v17.2S}, [x25], x16 // NEONReduceInstruction __ addv(v20, __ T8B, v21); // addv b20, v21.8B __ addv(v1, __ T16B, v2); // addv b1, v2.16B - __ addv(v22, __ T4H, v23); // addv h22, v23.4H + __ addv(v23, __ T4H, v24); // addv h23, v24.4H __ addv(v30, __ T8H, v31); // addv h30, v31.8H __ addv(v14, __ T4S, v15); // addv s14, v15.4S __ smaxv(v2, __ T8B, v3); // smaxv b2, v3.8B __ smaxv(v6, __ T16B, v7); // smaxv b6, v7.16B __ smaxv(v3, __ T4H, v4); // smaxv h3, v4.4H - __ smaxv(v7, __ T8H, v8); // smaxv h7, v8.8H - __ smaxv(v24, __ T4S, v25); // smaxv s24, v25.4S + __ smaxv(v8, __ T8H, v9); // smaxv h8, v9.8H + __ smaxv(v25, __ T4S, v26); // smaxv s25, v26.4S __ fmaxv(v0, __ T4S, v1); // fmaxv s0, v1.4S __ sminv(v27, __ T8B, v28); // sminv b27, v28.8B - __ uminv(v29, __ T8B, v30); // uminv b29, v30.8B + __ uminv(v30, __ T8B, v31); // uminv b30, v31.8B __ sminv(v5, __ T16B, v6); // sminv b5, v6.16B __ uminv(v5, __ T16B, v6); // uminv b5, v6.16B - __ sminv(v29, __ T4H, v30); // sminv h29, v30.4H + __ sminv(v30, __ T4H, v31); // sminv h30, v31.4H __ uminv(v11, __ T4H, v12); // uminv h11, v12.4H __ sminv(v25, __ T8H, v26); // sminv h25, v26.8H __ uminv(v0, __ T8H, v1); // uminv h0, v1.8H - __ sminv(v30, __ T4S, v31); // sminv s30, v31.4S + __ sminv(v31, __ T4S, v0); // sminv s31, v0.4S __ uminv(v0, __ T4S, v1); // uminv s0, v1.4S - __ fminv(v17, __ T4S, v18); // fminv s17, v18.4S - __ fmaxp(v28, v29, __ S); // fmaxp s28, v29.2S - __ fmaxp(v25, v26, __ D); // fmaxp d25, v26.2D + __ fminv(v19, __ T4S, v20); // fminv s19, v20.4S + __ fmaxp(v29, v30, __ S); // fmaxp s29, v30.2S + __ fmaxp(v26, v27, __ D); // fmaxp d26, v27.2D __ fminp(v9, v10, __ S); // fminp s9, v10.2S - __ fminp(v25, v26, __ D); // fminp d25, v26.2D + __ fminp(v26, v27, __ D); // fminp d26, v27.2D // NEONFloatCompareWithZero __ fcm(Assembler::GT, v12, __ T2S, v13); // fcmgt v12.2S, v13.2S, #0.0 __ fcm(Assembler::GT, v15, __ T4S, v16); // fcmgt v15.4S, v16.4S, #0.0 __ fcm(Assembler::GT, v11, __ T2D, v12); // fcmgt v11.2D, v12.2D, #0.0 - __ fcm(Assembler::GE, v10, __ T2S, v11); // fcmge v10.2S, v11.2S, #0.0 - __ fcm(Assembler::GE, v17, __ T4S, v18); // fcmge v17.4S, v18.4S, #0.0 - __ fcm(Assembler::GE, v24, __ T2D, v25); // fcmge v24.2D, v25.2D, #0.0 - __ fcm(Assembler::EQ, v21, __ T2S, v22); // fcmeq v21.2S, v22.2S, #0.0 - __ fcm(Assembler::EQ, v23, __ T4S, v24); // fcmeq v23.4S, v24.4S, #0.0 + __ fcm(Assembler::GE, v11, __ T2S, v12); // fcmge v11.2S, v12.2S, #0.0 + __ fcm(Assembler::GE, v18, __ T4S, v19); // fcmge v18.4S, v19.4S, #0.0 + __ fcm(Assembler::GE, v25, __ T2D, v26); // fcmge v25.2D, v26.2D, #0.0 + __ fcm(Assembler::EQ, v22, __ T2S, v23); // fcmeq v22.2S, v23.2S, #0.0 + __ fcm(Assembler::EQ, v24, __ T4S, v25); // fcmeq v24.4S, v25.4S, #0.0 __ fcm(Assembler::EQ, v0, __ T2D, v1); // fcmeq v0.2D, v1.2D, #0.0 - __ fcm(Assembler::LT, v16, __ T2S, v17); // fcmlt v16.2S, v17.2S, #0.0 - __ fcm(Assembler::LT, v10, __ T4S, v11); // fcmlt v10.4S, v11.4S, #0.0 + __ fcm(Assembler::LT, v17, __ T2S, v18); // fcmlt v17.2S, v18.2S, #0.0 + __ fcm(Assembler::LT, v11, __ T4S, v12); // fcmlt v11.4S, v12.4S, #0.0 __ fcm(Assembler::LT, v6, __ T2D, v7); // fcmlt v6.2D, v7.2D, #0.0 - __ fcm(Assembler::LE, v28, __ T2S, v29); // fcmle v28.2S, v29.2S, #0.0 + __ fcm(Assembler::LE, v29, __ T2S, v30); // fcmle v29.2S, v30.2S, #0.0 __ fcm(Assembler::LE, v6, __ T4S, v7); // fcmle v6.4S, v7.4S, #0.0 __ fcm(Assembler::LE, v5, __ T2D, v6); // fcmle v5.2D, v6.2D, #0.0 // TwoRegNEONOp __ absr(v5, __ T8B, v6); // abs v5.8B, v6.8B - __ absr(v20, __ T16B, v21); // abs v20.16B, v21.16B - __ absr(v17, __ T4H, v18); // abs v17.4H, v18.4H - __ absr(v15, __ T8H, v16); // abs v15.8H, v16.8H - __ absr(v17, __ T2S, v18); // abs v17.2S, v18.2S - __ absr(v29, __ T4S, v30); // abs v29.4S, v30.4S - __ absr(v26, __ T2D, v27); // abs v26.2D, v27.2D + __ absr(v21, __ T16B, v22); // abs v21.16B, v22.16B + __ absr(v19, __ T4H, v20); // abs v19.4H, v20.4H + __ absr(v16, __ T8H, v17); // abs v16.8H, v17.8H + __ absr(v18, __ T2S, v19); // abs v18.2S, v19.2S + __ absr(v30, __ T4S, v31); // abs v30.4S, v31.4S + __ absr(v27, __ T2D, v28); // abs v27.2D, v28.2D __ fabs(v28, __ T2S, v29); // fabs v28.2S, v29.2S __ fabs(v1, __ T4S, v2); // fabs v1.4S, v2.4S - __ fabs(v27, __ T2D, v28); // fabs v27.2D, v28.2D - __ fneg(v0, __ T2S, v1); // fneg v0.2S, v1.2S + __ fabs(v28, __ T2D, v29); // fabs v28.2D, v29.2D + __ fneg(v1, __ T2S, v2); // fneg v1.2S, v2.2S __ fneg(v20, __ T4S, v21); // fneg v20.4S, v21.4S - __ fneg(v28, __ T2D, v29); // fneg v28.2D, v29.2D - __ fsqrt(v15, __ T2S, v16); // fsqrt v15.2S, v16.2S - __ fsqrt(v12, __ T4S, v13); // fsqrt v12.4S, v13.4S + __ fneg(v29, __ T2D, v30); // fneg v29.2D, v30.2D + __ fsqrt(v16, __ T2S, v17); // fsqrt v16.2S, v17.2S + __ fsqrt(v13, __ T4S, v14); // fsqrt v13.4S, v14.4S __ fsqrt(v10, __ T2D, v11); // fsqrt v10.2D, v11.2D - __ notr(v28, __ T8B, v29); // not v28.8B, v29.8B - __ notr(v28, __ T16B, v29); // not v28.16B, v29.16B + __ notr(v29, __ T8B, v30); // not v29.8B, v30.8B + __ notr(v29, __ T16B, v30); // not v29.16B, v30.16B // ThreeRegNEONOp __ andr(v19, __ T8B, v20, v21); // and v19.8B, v20.8B, v21.8B __ andr(v22, __ T16B, v23, v24); // and v22.16B, v23.16B, v24.16B __ orr(v10, __ T8B, v11, v12); // orr v10.8B, v11.8B, v12.8B __ orr(v4, __ T16B, v5, v6); // orr v4.16B, v5.16B, v6.16B - __ eor(v30, __ T8B, v31, v0); // eor v30.8B, v31.8B, v0.8B - __ eor(v20, __ T16B, v21, v22); // eor v20.16B, v21.16B, v22.16B + __ eor(v31, __ T8B, v0, v1); // eor v31.8B, v0.8B, v1.8B + __ eor(v21, __ T16B, v22, v23); // eor v21.16B, v22.16B, v23.16B __ addv(v8, __ T8B, v9, v10); // add v8.8B, v9.8B, v10.8B - __ addv(v30, __ T16B, v31, v0); // add v30.16B, v31.16B, v0.16B - __ addv(v17, __ T4H, v18, v19); // add v17.4H, v18.4H, v19.4H + __ addv(v31, __ T16B, v0, v1); // add v31.16B, v0.16B, v1.16B + __ addv(v19, __ T4H, v20, v21); // add v19.4H, v20.4H, v21.4H __ addv(v10, __ T8H, v11, v12); // add v10.8H, v11.8H, v12.8H - __ addv(v27, __ T2S, v28, v29); // add v27.2S, v28.2S, v29.2S + __ addv(v28, __ T2S, v29, v30); // add v28.2S, v29.2S, v30.2S __ addv(v2, __ T4S, v3, v4); // add v2.4S, v3.4S, v4.4S - __ addv(v24, __ T2D, v25, v26); // add v24.2D, v25.2D, v26.2D - __ fadd(v4, __ T2S, v5, v6); // fadd v4.2S, v5.2S, v6.2S + __ addv(v25, __ T2D, v26, v27); // add v25.2D, v26.2D, v27.2D + __ fadd(v5, __ T2S, v6, v7); // fadd v5.2S, v6.2S, v7.2S __ fadd(v3, __ T4S, v4, v5); // fadd v3.4S, v4.4S, v5.4S __ fadd(v8, __ T2D, v9, v10); // fadd v8.2D, v9.2D, v10.2D __ subv(v22, __ T8B, v23, v24); // sub v22.8B, v23.8B, v24.8B - __ subv(v17, __ T16B, v18, v19); // sub v17.16B, v18.16B, v19.16B + __ subv(v19, __ T16B, v20, v21); // sub v19.16B, v20.16B, v21.16B __ subv(v13, __ T4H, v14, v15); // sub v13.4H, v14.4H, v15.4H - __ subv(v4, __ T8H, v5, v6); // sub v4.8H, v5.8H, v6.8H - __ subv(v28, __ T2S, v29, v30); // sub v28.2S, v29.2S, v30.2S - __ subv(v23, __ T4S, v24, v25); // sub v23.4S, v24.4S, v25.4S + __ subv(v5, __ T8H, v6, v7); // sub v5.8H, v6.8H, v7.8H + __ subv(v29, __ T2S, v30, v31); // sub v29.2S, v30.2S, v31.2S + __ subv(v24, __ T4S, v25, v26); // sub v24.4S, v25.4S, v26.4S __ subv(v21, __ T2D, v22, v23); // sub v21.2D, v22.2D, v23.2D - __ fsub(v25, __ T2S, v26, v27); // fsub v25.2S, v26.2S, v27.2S + __ fsub(v26, __ T2S, v27, v28); // fsub v26.2S, v27.2S, v28.2S __ fsub(v24, __ T4S, v25, v26); // fsub v24.4S, v25.4S, v26.4S __ fsub(v3, __ T2D, v4, v5); // fsub v3.2D, v4.2D, v5.2D - __ mulv(v23, __ T8B, v24, v25); // mul v23.8B, v24.8B, v25.8B + __ mulv(v24, __ T8B, v25, v26); // mul v24.8B, v25.8B, v26.8B __ mulv(v26, __ T16B, v27, v28); // mul v26.16B, v27.16B, v28.16B __ mulv(v23, __ T4H, v24, v25); // mul v23.4H, v24.4H, v25.4H - __ mulv(v14, __ T8H, v15, v16); // mul v14.8H, v15.8H, v16.8H + __ mulv(v15, __ T8H, v16, v17); // mul v15.8H, v16.8H, v17.8H __ mulv(v21, __ T2S, v22, v23); // mul v21.2S, v22.2S, v23.2S __ mulv(v3, __ T4S, v4, v5); // mul v3.4S, v4.4S, v5.4S - __ fabd(v23, __ T2S, v24, v25); // fabd v23.2S, v24.2S, v25.2S + __ fabd(v24, __ T2S, v25, v26); // fabd v24.2S, v25.2S, v26.2S __ fabd(v8, __ T4S, v9, v10); // fabd v8.4S, v9.4S, v10.4S - __ fabd(v24, __ T2D, v25, v26); // fabd v24.2D, v25.2D, v26.2D - __ faddp(v19, __ T2S, v20, v21); // faddp v19.2S, v20.2S, v21.2S - __ faddp(v15, __ T4S, v16, v17); // faddp v15.4S, v16.4S, v17.4S - __ faddp(v16, __ T2D, v17, v18); // faddp v16.2D, v17.2D, v18.2D + __ fabd(v25, __ T2D, v26, v27); // fabd v25.2D, v26.2D, v27.2D + __ faddp(v20, __ T2S, v21, v22); // faddp v20.2S, v21.2S, v22.2S + __ faddp(v16, __ T4S, v17, v18); // faddp v16.4S, v17.4S, v18.4S + __ faddp(v17, __ T2D, v18, v19); // faddp v17.2D, v18.2D, v19.2D __ fmul(v2, __ T2S, v3, v4); // fmul v2.2S, v3.2S, v4.2S __ fmul(v1, __ T4S, v2, v3); // fmul v1.4S, v2.4S, v3.4S __ fmul(v0, __ T2D, v1, v2); // fmul v0.2D, v1.2D, v2.2D __ mlav(v24, __ T4H, v25, v26); // mla v24.4H, v25.4H, v26.4H __ mlav(v4, __ T8H, v5, v6); // mla v4.8H, v5.8H, v6.8H __ mlav(v3, __ T2S, v4, v5); // mla v3.2S, v4.2S, v5.2S - __ mlav(v11, __ T4S, v12, v13); // mla v11.4S, v12.4S, v13.4S - __ fmla(v30, __ T2S, v31, v0); // fmla v30.2S, v31.2S, v0.2S - __ fmla(v27, __ T4S, v28, v29); // fmla v27.4S, v28.4S, v29.4S - __ fmla(v9, __ T2D, v10, v11); // fmla v9.2D, v10.2D, v11.2D - __ mlsv(v25, __ T4H, v26, v27); // mls v25.4H, v26.4H, v27.4H + __ mlav(v12, __ T4S, v13, v14); // mla v12.4S, v13.4S, v14.4S + __ fmla(v31, __ T2S, v0, v1); // fmla v31.2S, v0.2S, v1.2S + __ fmla(v28, __ T4S, v29, v30); // fmla v28.4S, v29.4S, v30.4S + __ fmla(v10, __ T2D, v11, v12); // fmla v10.2D, v11.2D, v12.2D + __ mlsv(v26, __ T4H, v27, v28); // mls v26.4H, v27.4H, v28.4H __ mlsv(v2, __ T8H, v3, v4); // mls v2.8H, v3.8H, v4.8H __ mlsv(v12, __ T2S, v13, v14); // mls v12.2S, v13.2S, v14.2S - __ mlsv(v17, __ T4S, v18, v19); // mls v17.4S, v18.4S, v19.4S - __ fmls(v30, __ T2S, v31, v0); // fmls v30.2S, v31.2S, v0.2S + __ mlsv(v18, __ T4S, v19, v20); // mls v18.4S, v19.4S, v20.4S + __ fmls(v31, __ T2S, v0, v1); // fmls v31.2S, v0.2S, v1.2S __ fmls(v1, __ T4S, v2, v3); // fmls v1.4S, v2.4S, v3.4S - __ fmls(v12, __ T2D, v13, v14); // fmls v12.2D, v13.2D, v14.2D - __ fdiv(v28, __ T2S, v29, v30); // fdiv v28.2S, v29.2S, v30.2S + __ fmls(v13, __ T2D, v14, v15); // fmls v13.2D, v14.2D, v15.2D + __ fdiv(v29, __ T2S, v30, v31); // fdiv v29.2S, v30.2S, v31.2S __ fdiv(v0, __ T4S, v1, v2); // fdiv v0.4S, v1.4S, v2.4S - __ fdiv(v17, __ T2D, v18, v19); // fdiv v17.2D, v18.2D, v19.2D + __ fdiv(v19, __ T2D, v20, v21); // fdiv v19.2D, v20.2D, v21.2D __ maxv(v12, __ T8B, v13, v14); // smax v12.8B, v13.8B, v14.8B __ maxv(v17, __ T16B, v18, v19); // smax v17.16B, v18.16B, v19.16B - __ maxv(v21, __ T4H, v22, v23); // smax v21.4H, v22.4H, v23.4H - __ maxv(v12, __ T8H, v13, v14); // smax v12.8H, v13.8H, v14.8H - __ maxv(v27, __ T2S, v28, v29); // smax v27.2S, v28.2S, v29.2S - __ maxv(v29, __ T4S, v30, v31); // smax v29.4S, v30.4S, v31.4S - __ smaxp(v30, __ T8B, v31, v0); // smaxp v30.8B, v31.8B, v0.8B + __ maxv(v22, __ T4H, v23, v24); // smax v22.4H, v23.4H, v24.4H + __ maxv(v13, __ T8H, v14, v15); // smax v13.8H, v14.8H, v15.8H + __ maxv(v28, __ T2S, v29, v30); // smax v28.2S, v29.2S, v30.2S + __ maxv(v30, __ T4S, v31, v0); // smax v30.4S, v31.4S, v0.4S + __ smaxp(v31, __ T8B, v0, v1); // smaxp v31.8B, v0.8B, v1.8B __ smaxp(v1, __ T16B, v2, v3); // smaxp v1.16B, v2.16B, v3.16B - __ smaxp(v25, __ T4H, v26, v27); // smaxp v25.4H, v26.4H, v27.4H - __ smaxp(v27, __ T8H, v28, v29); // smaxp v27.8H, v28.8H, v29.8H + __ smaxp(v26, __ T4H, v27, v28); // smaxp v26.4H, v27.4H, v28.4H + __ smaxp(v28, __ T8H, v29, v30); // smaxp v28.8H, v29.8H, v30.8H __ smaxp(v4, __ T2S, v5, v6); // smaxp v4.2S, v5.2S, v6.2S - __ smaxp(v29, __ T4S, v30, v31); // smaxp v29.4S, v30.4S, v31.4S - __ fmax(v3, __ T2S, v4, v5); // fmax v3.2S, v4.2S, v5.2S + __ smaxp(v30, __ T4S, v31, v0); // smaxp v30.4S, v31.4S, v0.4S + __ fmax(v4, __ T2S, v5, v6); // fmax v4.2S, v5.2S, v6.2S __ fmax(v6, __ T4S, v7, v8); // fmax v6.4S, v7.4S, v8.4S - __ fmax(v29, __ T2D, v30, v31); // fmax v29.2D, v30.2D, v31.2D - __ minv(v25, __ T8B, v26, v27); // smin v25.8B, v26.8B, v27.8B - __ minv(v17, __ T16B, v18, v19); // smin v17.16B, v18.16B, v19.16B - __ minv(v8, __ T4H, v9, v10); // smin v8.4H, v9.4H, v10.4H - __ minv(v7, __ T8H, v8, v9); // smin v7.8H, v8.8H, v9.8H + __ fmax(v30, __ T2D, v31, v0); // fmax v30.2D, v31.2D, v0.2D + __ minv(v26, __ T8B, v27, v28); // smin v26.8B, v27.8B, v28.8B + __ minv(v18, __ T16B, v19, v20); // smin v18.16B, v19.16B, v20.16B + __ minv(v9, __ T4H, v10, v11); // smin v9.4H, v10.4H, v11.4H + __ minv(v8, __ T8H, v9, v10); // smin v8.8H, v9.8H, v10.8H __ minv(v12, __ T2S, v13, v14); // smin v12.2S, v13.2S, v14.2S __ minv(v0, __ T4S, v1, v2); // smin v0.4S, v1.4S, v2.4S - __ sminp(v19, __ T8B, v20, v21); // sminp v19.8B, v20.8B, v21.8B + __ sminp(v20, __ T8B, v21, v22); // sminp v20.8B, v21.8B, v22.8B __ sminp(v1, __ T16B, v2, v3); // sminp v1.16B, v2.16B, v3.16B - __ sminp(v23, __ T4H, v24, v25); // sminp v23.4H, v24.4H, v25.4H + __ sminp(v24, __ T4H, v25, v26); // sminp v24.4H, v25.4H, v26.4H __ sminp(v2, __ T8H, v3, v4); // sminp v2.8H, v3.8H, v4.8H __ sminp(v0, __ T2S, v1, v2); // sminp v0.2S, v1.2S, v2.2S - __ sminp(v8, __ T4S, v9, v10); // sminp v8.4S, v9.4S, v10.4S - __ fmin(v23, __ T2S, v24, v25); // fmin v23.2S, v24.2S, v25.2S - __ fmin(v25, __ T4S, v26, v27); // fmin v25.4S, v26.4S, v27.4S - __ fmin(v15, __ T2D, v16, v17); // fmin v15.2D, v16.2D, v17.2D - __ facgt(v29, __ T2S, v30, v31); // facgt v29.2S, v30.2S, v31.2S + __ sminp(v9, __ T4S, v10, v11); // sminp v9.4S, v10.4S, v11.4S + __ fmin(v24, __ T2S, v25, v26); // fmin v24.2S, v25.2S, v26.2S + __ fmin(v26, __ T4S, v27, v28); // fmin v26.4S, v27.4S, v28.4S + __ fmin(v16, __ T2D, v17, v18); // fmin v16.2D, v17.2D, v18.2D + __ facgt(v30, __ T2S, v31, v0); // facgt v30.2S, v31.2S, v0.2S __ facgt(v3, __ T4S, v4, v5); // facgt v3.4S, v4.4S, v5.4S __ facgt(v10, __ T2D, v11, v12); // facgt v10.2D, v11.2D, v12.2D +// VectorScalarNEONInstruction + __ fmlavs(v5, __ T2S, v6, v7, 1); // fmla v5.2S, v6.2S, v7.S[1] + __ mulvs(v9, __ T4S, v10, v11, 0); // mul v9.4S, v10.4S, v11.S[0] + __ fmlavs(v5, __ T2D, v6, v7, 0); // fmla v5.2D, v6.2D, v7.D[0] + __ fmlsvs(v5, __ T2S, v6, v7, 0); // fmls v5.2S, v6.2S, v7.S[0] + __ mulvs(v8, __ T4S, v9, v10, 1); // mul v8.4S, v9.4S, v10.S[1] + __ fmlsvs(v5, __ T2D, v6, v7, 0); // fmls v5.2D, v6.2D, v7.D[0] + __ fmulxvs(v6, __ T2S, v7, v8, 0); // fmulx v6.2S, v7.2S, v8.S[0] + __ mulvs(v6, __ T4S, v7, v8, 1); // mul v6.4S, v7.4S, v8.S[1] + __ fmulxvs(v3, __ T2D, v4, v5, 0); // fmulx v3.2D, v4.2D, v5.D[0] + __ mulvs(v13, __ T4H, v14, v15, 2); // mul v13.4H, v14.4H, v15.H[2] + __ mulvs(v2, __ T8H, v3, v4, 4); // mul v2.8H, v3.8H, v4.H[4] + __ mulvs(v2, __ T2S, v3, v4, 0); // mul v2.2S, v3.2S, v4.S[0] + __ mulvs(v9, __ T4S, v10, v11, 1); // mul v9.4S, v10.4S, v11.S[1] + // NEONVectorCompare - __ cm(Assembler::GT, v22, __ T8B, v23, v24); // cmgt v22.8B, v23.8B, v24.8B - __ cm(Assembler::GT, v10, __ T16B, v11, v12); // cmgt v10.16B, v11.16B, v12.16B - __ cm(Assembler::GT, v4, __ T4H, v5, v6); // cmgt v4.4H, v5.4H, v6.4H - __ cm(Assembler::GT, v17, __ T8H, v18, v19); // cmgt v17.8H, v18.8H, v19.8H - __ cm(Assembler::GT, v1, __ T2S, v2, v3); // cmgt v1.2S, v2.2S, v3.2S - __ cm(Assembler::GT, v11, __ T4S, v12, v13); // cmgt v11.4S, v12.4S, v13.4S - __ cm(Assembler::GT, v7, __ T2D, v8, v9); // cmgt v7.2D, v8.2D, v9.2D - __ cm(Assembler::GE, v10, __ T8B, v11, v12); // cmge v10.8B, v11.8B, v12.8B - __ cm(Assembler::GE, v15, __ T16B, v16, v17); // cmge v15.16B, v16.16B, v17.16B - __ cm(Assembler::GE, v16, __ T4H, v17, v18); // cmge v16.4H, v17.4H, v18.4H - __ cm(Assembler::GE, v2, __ T8H, v3, v4); // cmge v2.8H, v3.8H, v4.8H - __ cm(Assembler::GE, v9, __ T2S, v10, v11); // cmge v9.2S, v10.2S, v11.2S - __ cm(Assembler::GE, v11, __ T4S, v12, v13); // cmge v11.4S, v12.4S, v13.4S - __ cm(Assembler::GE, v12, __ T2D, v13, v14); // cmge v12.2D, v13.2D, v14.2D - __ cm(Assembler::EQ, v14, __ T8B, v15, v16); // cmeq v14.8B, v15.8B, v16.8B - __ cm(Assembler::EQ, v13, __ T16B, v14, v15); // cmeq v13.16B, v14.16B, v15.16B - __ cm(Assembler::EQ, v2, __ T4H, v3, v4); // cmeq v2.4H, v3.4H, v4.4H - __ cm(Assembler::EQ, v6, __ T8H, v7, v8); // cmeq v6.8H, v7.8H, v8.8H - __ cm(Assembler::EQ, v19, __ T2S, v20, v21); // cmeq v19.2S, v20.2S, v21.2S - __ cm(Assembler::EQ, v25, __ T4S, v26, v27); // cmeq v25.4S, v26.4S, v27.4S - __ cm(Assembler::EQ, v15, __ T2D, v16, v17); // cmeq v15.2D, v16.2D, v17.2D - __ cm(Assembler::HI, v4, __ T8B, v5, v6); // cmhi v4.8B, v5.8B, v6.8B - __ cm(Assembler::HI, v2, __ T16B, v3, v4); // cmhi v2.16B, v3.16B, v4.16B - __ cm(Assembler::HI, v4, __ T4H, v5, v6); // cmhi v4.4H, v5.4H, v6.4H - __ cm(Assembler::HI, v11, __ T8H, v12, v13); // cmhi v11.8H, v12.8H, v13.8H - __ cm(Assembler::HI, v17, __ T2S, v18, v19); // cmhi v17.2S, v18.2S, v19.2S - __ cm(Assembler::HI, v20, __ T4S, v21, v22); // cmhi v20.4S, v21.4S, v22.4S - __ cm(Assembler::HI, v16, __ T2D, v17, v18); // cmhi v16.2D, v17.2D, v18.2D - __ cm(Assembler::HS, v17, __ T8B, v18, v19); // cmhs v17.8B, v18.8B, v19.8B - __ cm(Assembler::HS, v10, __ T16B, v11, v12); // cmhs v10.16B, v11.16B, v12.16B - __ cm(Assembler::HS, v20, __ T4H, v21, v22); // cmhs v20.4H, v21.4H, v22.4H - __ cm(Assembler::HS, v22, __ T8H, v23, v24); // cmhs v22.8H, v23.8H, v24.8H - __ cm(Assembler::HS, v12, __ T2S, v13, v14); // cmhs v12.2S, v13.2S, v14.2S - __ cm(Assembler::HS, v25, __ T4S, v26, v27); // cmhs v25.4S, v26.4S, v27.4S - __ cm(Assembler::HS, v23, __ T2D, v24, v25); // cmhs v23.2D, v24.2D, v25.2D - __ fcm(Assembler::EQ, v28, __ T2S, v29, v30); // fcmeq v28.2S, v29.2S, v30.2S - __ fcm(Assembler::EQ, v14, __ T4S, v15, v16); // fcmeq v14.4S, v15.4S, v16.4S - __ fcm(Assembler::EQ, v10, __ T2D, v11, v12); // fcmeq v10.2D, v11.2D, v12.2D - __ fcm(Assembler::GT, v24, __ T2S, v25, v26); // fcmgt v24.2S, v25.2S, v26.2S - __ fcm(Assembler::GT, v1, __ T4S, v2, v3); // fcmgt v1.4S, v2.4S, v3.4S - __ fcm(Assembler::GT, v11, __ T2D, v12, v13); // fcmgt v11.2D, v12.2D, v13.2D - __ fcm(Assembler::GE, v30, __ T2S, v31, v0); // fcmge v30.2S, v31.2S, v0.2S - __ fcm(Assembler::GE, v10, __ T4S, v11, v12); // fcmge v10.4S, v11.4S, v12.4S - __ fcm(Assembler::GE, v15, __ T2D, v16, v17); // fcmge v15.2D, v16.2D, v17.2D + __ cm(Assembler::GT, v21, __ T8B, v22, v23); // cmgt v21.8B, v22.8B, v23.8B + __ cm(Assembler::GT, v16, __ T16B, v17, v18); // cmgt v16.16B, v17.16B, v18.16B + __ cm(Assembler::GT, v18, __ T4H, v19, v20); // cmgt v18.4H, v19.4H, v20.4H + __ cm(Assembler::GT, v11, __ T8H, v12, v13); // cmgt v11.8H, v12.8H, v13.8H + __ cm(Assembler::GT, v21, __ T2S, v22, v23); // cmgt v21.2S, v22.2S, v23.2S + __ cm(Assembler::GT, v23, __ T4S, v24, v25); // cmgt v23.4S, v24.4S, v25.4S + __ cm(Assembler::GT, v12, __ T2D, v13, v14); // cmgt v12.2D, v13.2D, v14.2D + __ cm(Assembler::GE, v26, __ T8B, v27, v28); // cmge v26.8B, v27.8B, v28.8B + __ cm(Assembler::GE, v23, __ T16B, v24, v25); // cmge v23.16B, v24.16B, v25.16B + __ cm(Assembler::GE, v28, __ T4H, v29, v30); // cmge v28.4H, v29.4H, v30.4H + __ cm(Assembler::GE, v14, __ T8H, v15, v16); // cmge v14.8H, v15.8H, v16.8H + __ cm(Assembler::GE, v11, __ T2S, v12, v13); // cmge v11.2S, v12.2S, v13.2S + __ cm(Assembler::GE, v24, __ T4S, v25, v26); // cmge v24.4S, v25.4S, v26.4S + __ cm(Assembler::GE, v1, __ T2D, v2, v3); // cmge v1.2D, v2.2D, v3.2D + __ cm(Assembler::EQ, v12, __ T8B, v13, v14); // cmeq v12.8B, v13.8B, v14.8B + __ cm(Assembler::EQ, v31, __ T16B, v0, v1); // cmeq v31.16B, v0.16B, v1.16B + __ cm(Assembler::EQ, v10, __ T4H, v11, v12); // cmeq v10.4H, v11.4H, v12.4H + __ cm(Assembler::EQ, v16, __ T8H, v17, v18); // cmeq v16.8H, v17.8H, v18.8H + __ cm(Assembler::EQ, v7, __ T2S, v8, v9); // cmeq v7.2S, v8.2S, v9.2S + __ cm(Assembler::EQ, v2, __ T4S, v3, v4); // cmeq v2.4S, v3.4S, v4.4S + __ cm(Assembler::EQ, v3, __ T2D, v4, v5); // cmeq v3.2D, v4.2D, v5.2D + __ cm(Assembler::HI, v13, __ T8B, v14, v15); // cmhi v13.8B, v14.8B, v15.8B + __ cm(Assembler::HI, v19, __ T16B, v20, v21); // cmhi v19.16B, v20.16B, v21.16B + __ cm(Assembler::HI, v17, __ T4H, v18, v19); // cmhi v17.4H, v18.4H, v19.4H + __ cm(Assembler::HI, v16, __ T8H, v17, v18); // cmhi v16.8H, v17.8H, v18.8H + __ cm(Assembler::HI, v3, __ T2S, v4, v5); // cmhi v3.2S, v4.2S, v5.2S + __ cm(Assembler::HI, v1, __ T4S, v2, v3); // cmhi v1.4S, v2.4S, v3.4S + __ cm(Assembler::HI, v11, __ T2D, v12, v13); // cmhi v11.2D, v12.2D, v13.2D + __ cm(Assembler::HS, v30, __ T8B, v31, v0); // cmhs v30.8B, v31.8B, v0.8B + __ cm(Assembler::HS, v5, __ T16B, v6, v7); // cmhs v5.16B, v6.16B, v7.16B + __ cm(Assembler::HS, v8, __ T4H, v9, v10); // cmhs v8.4H, v9.4H, v10.4H + __ cm(Assembler::HS, v15, __ T8H, v16, v17); // cmhs v15.8H, v16.8H, v17.8H + __ cm(Assembler::HS, v29, __ T2S, v30, v31); // cmhs v29.2S, v30.2S, v31.2S + __ cm(Assembler::HS, v30, __ T4S, v31, v0); // cmhs v30.4S, v31.4S, v0.4S + __ cm(Assembler::HS, v0, __ T2D, v1, v2); // cmhs v0.2D, v1.2D, v2.2D + __ fcm(Assembler::EQ, v20, __ T2S, v21, v22); // fcmeq v20.2S, v21.2S, v22.2S + __ fcm(Assembler::EQ, v7, __ T4S, v8, v9); // fcmeq v7.4S, v8.4S, v9.4S + __ fcm(Assembler::EQ, v20, __ T2D, v21, v22); // fcmeq v20.2D, v21.2D, v22.2D + __ fcm(Assembler::GT, v23, __ T2S, v24, v25); // fcmgt v23.2S, v24.2S, v25.2S + __ fcm(Assembler::GT, v28, __ T4S, v29, v30); // fcmgt v28.4S, v29.4S, v30.4S + __ fcm(Assembler::GT, v21, __ T2D, v22, v23); // fcmgt v21.2D, v22.2D, v23.2D + __ fcm(Assembler::GE, v27, __ T2S, v28, v29); // fcmge v27.2S, v28.2S, v29.2S + __ fcm(Assembler::GE, v25, __ T4S, v26, v27); // fcmge v25.4S, v26.4S, v27.4S + __ fcm(Assembler::GE, v5, __ T2D, v6, v7); // fcmge v5.2D, v6.2D, v7.2D // SVEComparisonWithZero - __ sve_fcm(Assembler::EQ, p3, __ S, p3, z2, 0.0); // fcmeq p3.s, p3/z, z2.s, #0.0 - __ sve_fcm(Assembler::GT, p9, __ D, p0, z16, 0.0); // fcmgt p9.d, p0/z, z16.d, #0.0 - __ sve_fcm(Assembler::GE, p0, __ D, p1, z11, 0.0); // fcmge p0.d, p1/z, z11.d, #0.0 - __ sve_fcm(Assembler::LT, p4, __ D, p7, z14, 0.0); // fcmlt p4.d, p7/z, z14.d, #0.0 - __ sve_fcm(Assembler::LE, p0, __ S, p5, z20, 0.0); // fcmle p0.s, p5/z, z20.s, #0.0 - __ sve_fcm(Assembler::NE, p11, __ D, p6, z27, 0.0); // fcmne p11.d, p6/z, z27.d, #0.0 + __ sve_fcm(Assembler::EQ, p0, __ D, p7, z23, 0.0); // fcmeq p0.d, p7/z, z23.d, #0.0 + __ sve_fcm(Assembler::GT, p2, __ S, p7, z12, 0.0); // fcmgt p2.s, p7/z, z12.s, #0.0 + __ sve_fcm(Assembler::GE, p7, __ D, p7, z29, 0.0); // fcmge p7.d, p7/z, z29.d, #0.0 + __ sve_fcm(Assembler::LT, p9, __ S, p3, z31, 0.0); // fcmlt p9.s, p3/z, z31.s, #0.0 + __ sve_fcm(Assembler::LE, p9, __ D, p6, z31, 0.0); // fcmle p9.d, p6/z, z31.d, #0.0 + __ sve_fcm(Assembler::NE, p10, __ S, p2, z16, 0.0); // fcmne p10.s, p2/z, z16.s, #0.0 // SVEComparisonWithImm - __ sve_cmp(Assembler::EQ, p12, __ B, p5, z4, 0); // cmpeq p12.b, p5/z, z4.b, #0 - __ sve_cmp(Assembler::GT, p15, __ H, p2, z5, 12); // cmpgt p15.h, p2/z, z5.h, #12 - __ sve_cmp(Assembler::GE, p7, __ S, p7, z28, 3); // cmpge p7.s, p7/z, z28.s, #3 - __ sve_cmp(Assembler::LT, p15, __ H, p4, z5, 15); // cmplt p15.h, p4/z, z5.h, #15 - __ sve_cmp(Assembler::LE, p9, __ S, p4, z26, -4); // cmple p9.s, p4/z, z26.s, #-4 - __ sve_cmp(Assembler::NE, p5, __ B, p7, z9, 1); // cmpne p5.b, p7/z, z9.b, #1 - __ sve_cmp(Assembler::HS, p13, __ D, p1, z27, 43); // cmphs p13.d, p1/z, z27.d, #43 - __ sve_cmp(Assembler::HI, p10, __ B, p6, z9, 70); // cmphi p10.b, p6/z, z9.b, #70 - __ sve_cmp(Assembler::LS, p8, __ B, p7, z22, 61); // cmpls p8.b, p7/z, z22.b, #61 - __ sve_cmp(Assembler::LO, p11, __ S, p5, z17, 11); // cmplo p11.s, p5/z, z17.s, #11 + __ sve_cmp(Assembler::EQ, p4, __ D, p4, z6, 11); // cmpeq p4.d, p4/z, z6.d, #11 + __ sve_cmp(Assembler::GT, p14, __ B, p2, z30, 4); // cmpgt p14.b, p2/z, z30.b, #4 + __ sve_cmp(Assembler::GE, p5, __ D, p4, z4, 1); // cmpge p5.d, p4/z, z4.d, #1 + __ sve_cmp(Assembler::LT, p11, __ D, p3, z3, 6); // cmplt p11.d, p3/z, z3.d, #6 + __ sve_cmp(Assembler::LE, p9, __ S, p0, z19, -1); // cmple p9.s, p0/z, z19.s, #-1 + __ sve_cmp(Assembler::NE, p3, __ S, p2, z12, -3); // cmpne p3.s, p2/z, z12.s, #-3 + __ sve_cmp(Assembler::HS, p11, __ D, p4, z1, 20); // cmphs p11.d, p4/z, z1.d, #20 + __ sve_cmp(Assembler::HI, p8, __ S, p5, z2, 53); // cmphi p8.s, p5/z, z2.s, #53 + __ sve_cmp(Assembler::LS, p5, __ D, p6, z21, 49); // cmpls p5.d, p6/z, z21.d, #49 + __ sve_cmp(Assembler::LO, p13, __ B, p7, z3, 97); // cmplo p13.b, p7/z, z3.b, #97 // SpecialCases __ ccmn(zr, zr, 3u, Assembler::LE); // ccmn xzr, xzr, #3, LE @@ -1071,215 +1086,229 @@ __ fmovd(v0, -1.0625); // fmov d0, #-1.0625 // LSEOp - __ swp(Assembler::xword, r15, r6, r12); // swp x15, x6, [x12] - __ ldadd(Assembler::xword, r16, r11, r13); // ldadd x16, x11, [x13] - __ ldbic(Assembler::xword, r23, r1, r30); // ldclr x23, x1, [x30] - __ ldeor(Assembler::xword, r19, r5, r17); // ldeor x19, x5, [x17] - __ ldorr(Assembler::xword, r2, r16, r22); // ldset x2, x16, [x22] - __ ldsmin(Assembler::xword, r13, r10, r21); // ldsmin x13, x10, [x21] - __ ldsmax(Assembler::xword, r29, r27, r12); // ldsmax x29, x27, [x12] - __ ldumin(Assembler::xword, r27, r3, r1); // ldumin x27, x3, [x1] - __ ldumax(Assembler::xword, zr, r24, r19); // ldumax xzr, x24, [x19] + __ swp(Assembler::xword, r19, r17, r9); // swp x19, x17, [x9] + __ ldadd(Assembler::xword, r28, r27, r15); // ldadd x28, x27, [x15] + __ ldbic(Assembler::xword, r7, r21, r23); // ldclr x7, x21, [x23] + __ ldeor(Assembler::xword, zr, r25, r2); // ldeor xzr, x25, [x2] + __ ldorr(Assembler::xword, zr, r27, r15); // ldset xzr, x27, [x15] + __ ldsmin(Assembler::xword, r10, r23, r19); // ldsmin x10, x23, [x19] + __ ldsmax(Assembler::xword, r3, r16, r0); // ldsmax x3, x16, [x0] + __ ldumin(Assembler::xword, r25, r26, r23); // ldumin x25, x26, [x23] + __ ldumax(Assembler::xword, r2, r16, r12); // ldumax x2, x16, [x12] // LSEOp - __ swpa(Assembler::xword, r17, r9, r28); // swpa x17, x9, [x28] - __ ldadda(Assembler::xword, r27, r15, r7); // ldadda x27, x15, [x7] - __ ldbica(Assembler::xword, r21, r23, sp); // ldclra x21, x23, [sp] - __ ldeora(Assembler::xword, r25, r2, sp); // ldeora x25, x2, [sp] - __ ldorra(Assembler::xword, r27, r16, r10); // ldseta x27, x16, [x10] - __ ldsmina(Assembler::xword, r23, r19, r3); // ldsmina x23, x19, [x3] - __ ldsmaxa(Assembler::xword, r16, r0, r25); // ldsmaxa x16, x0, [x25] - __ ldumina(Assembler::xword, r26, r23, r2); // ldumina x26, x23, [x2] - __ ldumaxa(Assembler::xword, r16, r12, r4); // ldumaxa x16, x12, [x4] + __ swpa(Assembler::xword, r4, r28, r30); // swpa x4, x28, [x30] + __ ldadda(Assembler::xword, r29, r16, r27); // ldadda x29, x16, [x27] + __ ldbica(Assembler::xword, r6, r9, r29); // ldclra x6, x9, [x29] + __ ldeora(Assembler::xword, r16, r7, r4); // ldeora x16, x7, [x4] + __ ldorra(Assembler::xword, r7, r15, r9); // ldseta x7, x15, [x9] + __ ldsmina(Assembler::xword, r23, r8, r2); // ldsmina x23, x8, [x2] + __ ldsmaxa(Assembler::xword, r28, r21, sp); // ldsmaxa x28, x21, [sp] + __ ldumina(Assembler::xword, r5, r27, r0); // ldumina x5, x27, [x0] + __ ldumaxa(Assembler::xword, r17, r15, r4); // ldumaxa x17, x15, [x4] // LSEOp - __ swpal(Assembler::xword, r28, r30, r29); // swpal x28, x30, [x29] - __ ldaddal(Assembler::xword, r16, r27, r6); // ldaddal x16, x27, [x6] - __ ldbical(Assembler::xword, r9, r29, r15); // ldclral x9, x29, [x15] - __ ldeoral(Assembler::xword, r7, r4, r7); // ldeoral x7, x4, [x7] - __ ldorral(Assembler::xword, r15, r9, r23); // ldsetal x15, x9, [x23] - __ ldsminal(Assembler::xword, r8, r2, r28); // ldsminal x8, x2, [x28] - __ ldsmaxal(Assembler::xword, r21, zr, r5); // ldsmaxal x21, xzr, [x5] - __ lduminal(Assembler::xword, r27, r0, r17); // lduminal x27, x0, [x17] - __ ldumaxal(Assembler::xword, r15, r4, r26); // ldumaxal x15, x4, [x26] + __ swpal(Assembler::xword, r26, r8, r28); // swpal x26, x8, [x28] + __ ldaddal(Assembler::xword, r22, r27, r27); // ldaddal x22, x27, [x27] + __ ldbical(Assembler::xword, r25, r23, r0); // ldclral x25, x23, [x0] + __ ldeoral(Assembler::xword, r4, r6, r15); // ldeoral x4, x6, [x15] + __ ldorral(Assembler::xword, r0, r4, r15); // ldsetal x0, x4, [x15] + __ ldsminal(Assembler::xword, r1, r10, r7); // ldsminal x1, x10, [x7] + __ ldsmaxal(Assembler::xword, r5, r10, r28); // ldsmaxal x5, x10, [x28] + __ lduminal(Assembler::xword, r7, r20, r23); // lduminal x7, x20, [x23] + __ ldumaxal(Assembler::xword, r21, r6, r11); // ldumaxal x21, x6, [x11] // LSEOp - __ swpl(Assembler::xword, r8, r28, r22); // swpl x8, x28, [x22] - __ ldaddl(Assembler::xword, r27, r27, r25); // ldaddl x27, x27, [x25] - __ ldbicl(Assembler::xword, r23, r0, r4); // ldclrl x23, x0, [x4] - __ ldeorl(Assembler::xword, r6, r16, r0); // ldeorl x6, x16, [x0] - __ ldorrl(Assembler::xword, r4, r15, r1); // ldsetl x4, x15, [x1] - __ ldsminl(Assembler::xword, r10, r7, r5); // ldsminl x10, x7, [x5] - __ ldsmaxl(Assembler::xword, r10, r28, r7); // ldsmaxl x10, x28, [x7] - __ lduminl(Assembler::xword, r20, r23, r21); // lduminl x20, x23, [x21] - __ ldumaxl(Assembler::xword, r6, r11, r8); // ldumaxl x6, x11, [x8] + __ swpl(Assembler::xword, r8, r17, sp); // swpl x8, x17, [sp] + __ ldaddl(Assembler::xword, r6, r17, r2); // ldaddl x6, x17, [x2] + __ ldbicl(Assembler::xword, r12, r30, r29); // ldclrl x12, x30, [x29] + __ ldeorl(Assembler::xword, r3, r27, r22); // ldeorl x3, x27, [x22] + __ ldorrl(Assembler::xword, r29, r14, r13); // ldsetl x29, x14, [x13] + __ ldsminl(Assembler::xword, r28, r17, r24); // ldsminl x28, x17, [x24] + __ ldsmaxl(Assembler::xword, r5, r2, r14); // ldsmaxl x5, x2, [x14] + __ lduminl(Assembler::xword, r10, r16, r11); // lduminl x10, x16, [x11] + __ ldumaxl(Assembler::xword, r27, r23, r12); // ldumaxl x27, x23, [x12] // LSEOp - __ swp(Assembler::word, r17, zr, r6); // swp w17, wzr, [x6] - __ ldadd(Assembler::word, r17, r2, r12); // ldadd w17, w2, [x12] - __ ldbic(Assembler::word, r30, r29, r3); // ldclr w30, w29, [x3] - __ ldeor(Assembler::word, r27, r22, r29); // ldeor w27, w22, [x29] - __ ldorr(Assembler::word, r14, r13, r28); // ldset w14, w13, [x28] - __ ldsmin(Assembler::word, r17, r24, r5); // ldsmin w17, w24, [x5] - __ ldsmax(Assembler::word, r2, r14, r10); // ldsmax w2, w14, [x10] - __ ldumin(Assembler::word, r16, r11, r27); // ldumin w16, w11, [x27] - __ ldumax(Assembler::word, r23, r12, r4); // ldumax w23, w12, [x4] + __ swp(Assembler::word, r4, r22, r17); // swp w4, w22, [x17] + __ ldadd(Assembler::word, r4, r1, r19); // ldadd w4, w1, [x19] + __ ldbic(Assembler::word, r16, r16, r13); // ldclr w16, w16, [x13] + __ ldeor(Assembler::word, r14, r12, r2); // ldeor w14, w12, [x2] + __ ldorr(Assembler::word, r17, r3, r21); // ldset w17, w3, [x21] + __ ldsmin(Assembler::word, r23, r5, r6); // ldsmin w23, w5, [x6] + __ ldsmax(Assembler::word, r7, r19, r13); // ldsmax w7, w19, [x13] + __ ldumin(Assembler::word, r28, r17, r16); // ldumin w28, w17, [x16] + __ ldumax(Assembler::word, r6, r2, r29); // ldumax w6, w2, [x29] // LSEOp - __ swpa(Assembler::word, r22, r17, r4); // swpa w22, w17, [x4] - __ ldadda(Assembler::word, r1, r19, r16); // ldadda w1, w19, [x16] - __ ldbica(Assembler::word, r16, r13, r14); // ldclra w16, w13, [x14] - __ ldeora(Assembler::word, r12, r2, r17); // ldeora w12, w2, [x17] - __ ldorra(Assembler::word, r3, r21, r23); // ldseta w3, w21, [x23] - __ ldsmina(Assembler::word, r5, r6, r7); // ldsmina w5, w6, [x7] - __ ldsmaxa(Assembler::word, r19, r13, r28); // ldsmaxa w19, w13, [x28] - __ ldumina(Assembler::word, r17, r16, r6); // ldumina w17, w16, [x6] - __ ldumaxa(Assembler::word, r2, r29, r3); // ldumaxa w2, w29, [x3] + __ swpa(Assembler::word, r3, r4, r6); // swpa w3, w4, [x6] + __ ldadda(Assembler::word, r16, r20, r13); // ldadda w16, w20, [x13] + __ ldbica(Assembler::word, r12, r20, r8); // ldclra w12, w20, [x8] + __ ldeora(Assembler::word, r25, r20, r19); // ldeora w25, w20, [x19] + __ ldorra(Assembler::word, r0, r11, r24); // ldseta w0, w11, [x24] + __ ldsmina(Assembler::word, r6, r20, sp); // ldsmina w6, w20, [sp] + __ ldsmaxa(Assembler::word, r14, r16, r6); // ldsmaxa w14, w16, [x6] + __ ldumina(Assembler::word, r0, r7, r15); // ldumina w0, w7, [x15] + __ ldumaxa(Assembler::word, r19, r26, r9); // ldumaxa w19, w26, [x9] // LSEOp - __ swpal(Assembler::word, r4, r6, r15); // swpal w4, w6, [x15] - __ ldaddal(Assembler::word, r20, r13, r12); // ldaddal w20, w13, [x12] - __ ldbical(Assembler::word, r20, r8, r25); // ldclral w20, w8, [x25] - __ ldeoral(Assembler::word, r20, r19, r0); // ldeoral w20, w19, [x0] - __ ldorral(Assembler::word, r11, r24, r6); // ldsetal w11, w24, [x6] - __ ldsminal(Assembler::word, r20, zr, r14); // ldsminal w20, wzr, [x14] - __ ldsmaxal(Assembler::word, r16, r6, r0); // ldsmaxal w16, w6, [x0] - __ lduminal(Assembler::word, r7, r15, r19); // lduminal w7, w15, [x19] - __ ldumaxal(Assembler::word, r26, r9, r10); // ldumaxal w26, w9, [x10] + __ swpal(Assembler::word, r10, r23, r21); // swpal w10, w23, [x21] + __ ldaddal(Assembler::word, r22, r28, r2); // ldaddal w22, w28, [x2] + __ ldbical(Assembler::word, r3, r15, r19); // ldclral w3, w15, [x19] + __ ldeoral(Assembler::word, r20, r7, r4); // ldeoral w20, w7, [x4] + __ ldorral(Assembler::word, r29, r7, r0); // ldsetal w29, w7, [x0] + __ ldsminal(Assembler::word, r9, r16, r20); // ldsminal w9, w16, [x20] + __ ldsmaxal(Assembler::word, r23, r4, r16); // ldsmaxal w23, w4, [x16] + __ lduminal(Assembler::word, r10, r23, r11); // lduminal w10, w23, [x11] + __ ldumaxal(Assembler::word, r25, r6, sp); // ldumaxal w25, w6, [sp] // LSEOp - __ swpl(Assembler::word, r23, r21, r22); // swpl w23, w21, [x22] - __ ldaddl(Assembler::word, r28, r2, r3); // ldaddl w28, w2, [x3] - __ ldbicl(Assembler::word, r15, r19, r20); // ldclrl w15, w19, [x20] - __ ldeorl(Assembler::word, r7, r4, r29); // ldeorl w7, w4, [x29] - __ ldorrl(Assembler::word, r7, r0, r9); // ldsetl w7, w0, [x9] - __ ldsminl(Assembler::word, r16, r20, r23); // ldsminl w16, w20, [x23] - __ ldsmaxl(Assembler::word, r4, r16, r10); // ldsmaxl w4, w16, [x10] - __ lduminl(Assembler::word, r23, r11, r25); // lduminl w23, w11, [x25] - __ ldumaxl(Assembler::word, r6, zr, r16); // ldumaxl w6, wzr, [x16] + __ swpl(Assembler::word, r16, r13, r23); // swpl w16, w13, [x23] + __ ldaddl(Assembler::word, r12, r1, r14); // ldaddl w12, w1, [x14] + __ ldbicl(Assembler::word, r9, r21, r16); // ldclrl w9, w21, [x16] + __ ldeorl(Assembler::word, r26, r15, r4); // ldeorl w26, w15, [x4] + __ ldorrl(Assembler::word, r4, r16, r8); // ldsetl w4, w16, [x8] + __ ldsminl(Assembler::word, r6, r30, r4); // ldsminl w6, w30, [x4] + __ ldsmaxl(Assembler::word, r29, r17, r29); // ldsmaxl w29, w17, [x29] + __ lduminl(Assembler::word, r26, r9, r15); // lduminl w26, w9, [x15] + __ ldumaxl(Assembler::word, r2, r11, r29); // ldumaxl w2, w11, [x29] // SHA3SIMDOp - __ bcax(v13, __ T16B, v22, v11, v1); // bcax v13.16B, v22.16B, v11.16B, v1.16B - __ eor3(v13, __ T16B, v8, v20, v16); // eor3 v13.16B, v8.16B, v20.16B, v16.16B - __ rax1(v25, __ T2D, v15, v4); // rax1 v25.2D, v15.2D, v4.2D - __ xar(v4, __ T2D, v17, v8, 13); // xar v4.2D, v17.2D, v8.2D, #13 + __ bcax(v3, __ T16B, v7, v1, v27); // bcax v3.16B, v7.16B, v1.16B, v27.16B + __ eor3(v21, __ T16B, v18, v14, v8); // eor3 v21.16B, v18.16B, v14.16B, v8.16B + __ rax1(v18, __ T2D, v22, v25); // rax1 v18.2D, v22.2D, v25.2D + __ xar(v5, __ T2D, v20, v21, 37); // xar v5.2D, v20.2D, v21.2D, #37 // SHA512SIMDOp - __ sha512h(v29, __ T2D, v4, v28); // sha512h q29, q4, v28.2D - __ sha512h2(v16, __ T2D, v29, v26); // sha512h2 q16, q29, v26.2D - __ sha512su0(v9, __ T2D, v14); // sha512su0 v9.2D, v14.2D - __ sha512su1(v2, __ T2D, v11, v28); // sha512su1 v2.2D, v11.2D, v28.2D + __ sha512h(v23, __ T2D, v16, v30); // sha512h q23, q16, v30.2D + __ sha512h2(v20, __ T2D, v20, v0); // sha512h2 q20, q20, v0.2D + __ sha512su0(v4, __ T2D, v19); // sha512su0 v4.2D, v19.2D + __ sha512su1(v24, __ T2D, v4, v20); // sha512su1 v24.2D, v4.2D, v20.2D // SVEBinaryImmOp - __ sve_add(z3, __ B, 10u); // add z3.b, z3.b, #0xa - __ sve_sub(z26, __ S, 150u); // sub z26.s, z26.s, #0x96 - __ sve_and(z14, __ H, 57343u); // and z14.h, z14.h, #0xdfff - __ sve_eor(z24, __ B, 191u); // eor z24.b, z24.b, #0xbf - __ sve_orr(z17, __ S, 4294966791u); // orr z17.s, z17.s, #0xfffffe07 + __ sve_add(z4, __ D, 210u); // add z4.d, z4.d, #0xd2 + __ sve_sub(z19, __ B, 71u); // sub z19.b, z19.b, #0x47 + __ sve_and(z8, __ H, 49663u); // and z8.h, z8.h, #0xc1ff + __ sve_eor(z31, __ S, 4294967231u); // eor z31.s, z31.s, #0xffffffbf + __ sve_orr(z1, __ H, 16368u); // orr z1.h, z1.h, #0x3ff0 // SVEBinaryImmOp - __ sve_add(z20, __ S, 3u); // add z20.s, z20.s, #0x3 - __ sve_sub(z4, __ S, 196u); // sub z4.s, z4.s, #0xc4 - __ sve_and(z4, __ S, 4286578691u); // and z4.s, z4.s, #0xff800003 - __ sve_eor(z25, __ S, 33553408u); // eor z25.s, z25.s, #0x1fffc00 - __ sve_orr(z8, __ H, 49663u); // orr z8.h, z8.h, #0xc1ff + __ sve_add(z0, __ H, 61u); // add z0.h, z0.h, #0x3d + __ sve_sub(z24, __ S, 36u); // sub z24.s, z24.s, #0x24 + __ sve_and(z27, __ B, 243u); // and z27.b, z27.b, #0xf3 + __ sve_eor(z24, __ H, 65534u); // eor z24.h, z24.h, #0xfffe + __ sve_orr(z22, __ S, 4294967293u); // orr z22.s, z22.s, #0xfffffffd // SVEBinaryImmOp - __ sve_add(z30, __ S, 36u); // add z30.s, z30.s, #0x24 - __ sve_sub(z30, __ B, 85u); // sub z30.b, z30.b, #0x55 - __ sve_and(z19, __ H, 4032u); // and z19.h, z19.h, #0xfc0 - __ sve_eor(z7, __ D, 274877904896u); // eor z7.d, z7.d, #0x3ffffff800 - __ sve_orr(z27, __ B, 243u); // orr z27.b, z27.b, #0xf3 + __ sve_add(z29, __ H, 113u); // add z29.h, z29.h, #0x71 + __ sve_sub(z20, __ B, 165u); // sub z20.b, z20.b, #0xa5 + __ sve_and(z28, __ H, 32256u); // and z28.h, z28.h, #0x7e00 + __ sve_eor(z12, __ S, 4287102855u); // eor z12.s, z12.s, #0xff87ff87 + __ sve_orr(z9, __ S, 3825205247u); // orr z9.s, z9.s, #0xe3ffffff // SVEBinaryImmOp - __ sve_add(z23, __ H, 132u); // add z23.h, z23.h, #0x84 - __ sve_sub(z30, __ S, 183u); // sub z30.s, z30.s, #0xb7 - __ sve_and(z20, __ D, 4503599627354112u); // and z20.d, z20.d, #0xfffffffffc000 - __ sve_eor(z13, __ S, 4042322160u); // eor z13.s, z13.s, #0xf0f0f0f0 - __ sve_orr(z28, __ H, 32256u); // orr z28.h, z28.h, #0x7e00 + __ sve_add(z18, __ S, 41u); // add z18.s, z18.s, #0x29 + __ sve_sub(z0, __ B, 98u); // sub z0.b, z0.b, #0x62 + __ sve_and(z8, __ H, 32768u); // and z8.h, z8.h, #0x8000 + __ sve_eor(z4, __ H, 508u); // eor z4.h, z4.h, #0x1fc + __ sve_orr(z0, __ H, 64512u); // orr z0.h, z0.h, #0xfc00 // SVEBinaryImmOp - __ sve_add(z11, __ S, 13u); // add z11.s, z11.s, #0xd - __ sve_sub(z24, __ H, 159u); // sub z24.h, z24.h, #0x9f - __ sve_and(z13, __ S, 2151677951u); // and z13.s, z13.s, #0x803fffff - __ sve_eor(z4, __ B, 124u); // eor z4.b, z4.b, #0x7c - __ sve_orr(z7, __ H, 32768u); // orr z7.h, z7.h, #0x8000 + __ sve_add(z3, __ B, 79u); // add z3.b, z3.b, #0x4f + __ sve_sub(z19, __ D, 84u); // sub z19.d, z19.d, #0x54 + __ sve_and(z24, __ B, 62u); // and z24.b, z24.b, #0x3e + __ sve_eor(z24, __ D, 18428729675200069887u); // eor z24.d, z24.d, #0xffc00000000000ff + __ sve_orr(z11, __ D, 17296056810822168583u); // orr z11.d, z11.d, #0xf007f007f007f007 // SVEBinaryImmOp - __ sve_add(z4, __ H, 243u); // add z4.h, z4.h, #0xf3 - __ sve_sub(z5, __ B, 86u); // sub z5.b, z5.b, #0x56 - __ sve_and(z21, __ D, 8064u); // and z21.d, z21.d, #0x1f80 - __ sve_eor(z9, __ S, 130023424u); // eor z9.s, z9.s, #0x7c00000 - __ sve_orr(z24, __ B, 62u); // orr z24.b, z24.b, #0x3e + __ sve_add(z31, __ S, 115u); // add z31.s, z31.s, #0x73 + __ sve_sub(z3, __ D, 134u); // sub z3.d, z3.d, #0x86 + __ sve_and(z22, __ S, 4042322160u); // and z22.s, z22.s, #0xf0f0f0f0 + __ sve_eor(z3, __ B, 225u); // eor z3.b, z3.b, #0xe1 + __ sve_orr(z9, __ S, 4164941887u); // orr z9.s, z9.s, #0xf83ff83f // SVEVectorOp - __ sve_add(z23, __ S, z28, z13); // add z23.s, z28.s, z13.s - __ sve_sub(z10, __ S, z26, z12); // sub z10.s, z26.s, z12.s - __ sve_fadd(z30, __ S, z17, z14); // fadd z30.s, z17.s, z14.s - __ sve_fmul(z29, __ D, z16, z21); // fmul z29.d, z16.d, z21.d - __ sve_fsub(z7, __ S, z19, z2); // fsub z7.s, z19.s, z2.s - __ sve_abs(z26, __ S, p4, z9); // abs z26.s, p4/m, z9.s - __ sve_add(z17, __ B, p5, z0); // add z17.b, p5/m, z17.b, z0.b - __ sve_and(z2, __ B, p6, z14); // and z2.b, p6/m, z2.b, z14.b - __ sve_asr(z11, __ S, p5, z14); // asr z11.s, p5/m, z11.s, z14.s - __ sve_bic(z29, __ B, p3, z3); // bic z29.b, p3/m, z29.b, z3.b - __ sve_clz(z22, __ D, p2, z3); // clz z22.d, p2/m, z3.d - __ sve_cnt(z27, __ S, p0, z19); // cnt z27.s, p0/m, z19.s - __ sve_eor(z7, __ H, p6, z21); // eor z7.h, p6/m, z7.h, z21.h - __ sve_lsl(z5, __ B, p2, z25); // lsl z5.b, p2/m, z5.b, z25.b - __ sve_lsr(z21, __ B, p4, z17); // lsr z21.b, p4/m, z21.b, z17.b - __ sve_mul(z3, __ H, p2, z19); // mul z3.h, p2/m, z3.h, z19.h - __ sve_neg(z7, __ S, p3, z14); // neg z7.s, p3/m, z14.s - __ sve_not(z17, __ D, p2, z13); // not z17.d, p2/m, z13.d - __ sve_orr(z17, __ H, p7, z17); // orr z17.h, p7/m, z17.h, z17.h - __ sve_rbit(z15, __ S, p3, z26); // rbit z15.s, p3/m, z26.s - __ sve_revb(z27, __ H, p5, z7); // revb z27.h, p5/m, z7.h - __ sve_smax(z5, __ H, p7, z27); // smax z5.h, p7/m, z5.h, z27.h - __ sve_smin(z0, __ S, p3, z24); // smin z0.s, p3/m, z0.s, z24.s - __ sve_sub(z20, __ S, p0, z3); // sub z20.s, p0/m, z20.s, z3.s - __ sve_fabs(z25, __ D, p1, z25); // fabs z25.d, p1/m, z25.d - __ sve_fadd(z17, __ S, p4, z1); // fadd z17.s, p4/m, z17.s, z1.s - __ sve_fdiv(z14, __ S, p7, z13); // fdiv z14.s, p7/m, z14.s, z13.s - __ sve_fmax(z17, __ D, p0, z30); // fmax z17.d, p0/m, z17.d, z30.d - __ sve_fmin(z22, __ S, p5, z29); // fmin z22.s, p5/m, z22.s, z29.s - __ sve_fmul(z8, __ S, p0, z0); // fmul z8.s, p0/m, z8.s, z0.s - __ sve_fneg(z23, __ D, p5, z0); // fneg z23.d, p5/m, z0.d - __ sve_frintm(z25, __ S, p6, z23); // frintm z25.s, p6/m, z23.s - __ sve_frintn(z21, __ S, p5, z1); // frintn z21.s, p5/m, z1.s - __ sve_frintp(z10, __ D, p5, z11); // frintp z10.d, p5/m, z11.d - __ sve_fsqrt(z23, __ D, p6, z8); // fsqrt z23.d, p6/m, z8.d - __ sve_fsub(z17, __ D, p5, z19); // fsub z17.d, p5/m, z17.d, z19.d - __ sve_fmad(z4, __ D, p5, z13, z30); // fmad z4.d, p5/m, z13.d, z30.d - __ sve_fmla(z30, __ D, p7, z25, z17); // fmla z30.d, p7/m, z25.d, z17.d - __ sve_fmls(z14, __ D, p2, z12, z28); // fmls z14.d, p2/m, z12.d, z28.d - __ sve_fmsb(z5, __ S, p0, z13, z13); // fmsb z5.s, p0/m, z13.s, z13.s - __ sve_fnmad(z7, __ S, p2, z11, z19); // fnmad z7.s, p2/m, z11.s, z19.s - __ sve_fnmsb(z25, __ D, p3, z2, z3); // fnmsb z25.d, p3/m, z2.d, z3.d - __ sve_fnmla(z0, __ D, p5, z5, z20); // fnmla z0.d, p5/m, z5.d, z20.d - __ sve_fnmls(z28, __ S, p3, z13, z8); // fnmls z28.s, p3/m, z13.s, z8.s - __ sve_mla(z29, __ B, p0, z14, z27); // mla z29.b, p0/m, z14.b, z27.b - __ sve_mls(z3, __ H, p6, z8, z24); // mls z3.h, p6/m, z8.h, z24.h - __ sve_and(z1, z25, z10); // and z1.d, z25.d, z10.d - __ sve_eor(z1, z20, z25); // eor z1.d, z20.d, z25.d - __ sve_orr(z28, z19, z16); // orr z28.d, z19.d, z16.d - __ sve_bic(z27, z13, z1); // bic z27.d, z13.d, z1.d - __ sve_uzp1(z11, __ B, z9, z1); // uzp1 z11.b, z9.b, z1.b - __ sve_uzp2(z1, __ H, z27, z26); // uzp2 z1.h, z27.h, z26.h - __ sve_fabd(z2, __ D, p1, z29); // fabd z2.d, p1/m, z2.d, z29.d - __ sve_bext(z24, __ D, z2, z2); // bext z24.d, z2.d, z2.d - __ sve_bdep(z3, __ H, z25, z28); // bdep z3.h, z25.h, z28.h - __ sve_eor3(z3, z22, z13); // eor3 z3.d, z3.d, z22.d, z13.d + __ sve_add(z0, __ D, z4, z2); // add z0.d, z4.d, z2.d + __ sve_sub(z14, __ S, z6, z11); // sub z14.s, z6.s, z11.s + __ sve_fadd(z14, __ S, z17, z30); // fadd z14.s, z17.s, z30.s + __ sve_fmul(z3, __ S, z3, z23); // fmul z3.s, z3.s, z23.s + __ sve_fsub(z3, __ S, z24, z28); // fsub z3.s, z24.s, z28.s + __ sve_abs(z19, __ D, p5, z7); // abs z19.d, p5/m, z7.d + __ sve_add(z21, __ H, p3, z5); // add z21.h, p3/m, z21.h, z5.h + __ sve_and(z26, __ S, p1, z22); // and z26.s, p1/m, z26.s, z22.s + __ sve_asr(z17, __ H, p0, z3); // asr z17.h, p0/m, z17.h, z3.h + __ sve_bic(z20, __ H, p3, z8); // bic z20.h, p3/m, z20.h, z8.h + __ sve_clz(z14, __ H, p4, z17); // clz z14.h, p4/m, z17.h + __ sve_cnt(z13, __ D, p6, z18); // cnt z13.d, p6/m, z18.d + __ sve_eor(z19, __ H, p2, z16); // eor z19.h, p2/m, z19.h, z16.h + __ sve_lsl(z27, __ S, p5, z28); // lsl z27.s, p5/m, z27.s, z28.s + __ sve_lsr(z8, __ D, p2, z5); // lsr z8.d, p2/m, z8.d, z5.d + __ sve_mul(z28, __ H, p2, z0); // mul z28.h, p2/m, z28.h, z0.h + __ sve_neg(z25, __ B, p5, z21); // neg z25.b, p5/m, z21.b + __ sve_not(z3, __ B, p5, z26); // not z3.b, p5/m, z26.b + __ sve_orr(z26, __ S, p7, z19); // orr z26.s, p7/m, z26.s, z19.s + __ sve_rbit(z1, __ D, p3, z14); // rbit z1.d, p3/m, z14.d + __ sve_revb(z14, __ H, p0, z18); // revb z14.h, p0/m, z18.h + __ sve_smax(z31, __ S, p5, z23); // smax z31.s, p5/m, z31.s, z23.s + __ sve_smin(z30, __ B, p3, z8); // smin z30.b, p3/m, z30.b, z8.b + __ sve_sub(z0, __ S, p3, z23); // sub z0.s, p3/m, z0.s, z23.s + __ sve_fabs(z0, __ D, p4, z26); // fabs z0.d, p4/m, z26.d + __ sve_fadd(z24, __ D, p3, z22); // fadd z24.d, p3/m, z24.d, z22.d + __ sve_fdiv(z2, __ D, p0, z11); // fdiv z2.d, p0/m, z2.d, z11.d + __ sve_fmax(z12, __ D, p5, z24); // fmax z12.d, p5/m, z12.d, z24.d + __ sve_fmin(z9, __ D, p7, z17); // fmin z9.d, p7/m, z9.d, z17.d + __ sve_fmul(z20, __ D, p5, z4); // fmul z20.d, p5/m, z20.d, z4.d + __ sve_fneg(z13, __ D, p7, z22); // fneg z13.d, p7/m, z22.d + __ sve_frintm(z31, __ D, p6, z18); // frintm z31.d, p6/m, z18.d + __ sve_frintn(z15, __ D, p2, z13); // frintn z15.d, p2/m, z13.d + __ sve_frintp(z20, __ S, p1, z1); // frintp z20.s, p1/m, z1.s + __ sve_fsqrt(z14, __ S, p0, z7); // fsqrt z14.s, p0/m, z7.s + __ sve_fsub(z12, __ D, p4, z4); // fsub z12.d, p4/m, z12.d, z4.d + __ sve_fmad(z15, __ S, p0, z3, z30); // fmad z15.s, p0/m, z3.s, z30.s + __ sve_fmla(z20, __ D, p1, z20, z31); // fmla z20.d, p1/m, z20.d, z31.d + __ sve_fmls(z13, __ D, p3, z9, z14); // fmls z13.d, p3/m, z9.d, z14.d + __ sve_fmsb(z1, __ S, p3, z28, z3); // fmsb z1.s, p3/m, z28.s, z3.s + __ sve_fnmad(z26, __ S, p2, z25, z9); // fnmad z26.s, p2/m, z25.s, z9.s + __ sve_fnmsb(z26, __ D, p2, z14, z1); // fnmsb z26.d, p2/m, z14.d, z1.d + __ sve_fnmla(z26, __ D, p1, z29, z20); // fnmla z26.d, p1/m, z29.d, z20.d + __ sve_fnmls(z6, __ D, p7, z13, z1); // fnmls z6.d, p7/m, z13.d, z1.d + __ sve_mla(z11, __ B, p2, z1, z1); // mla z11.b, p2/m, z1.b, z1.b + __ sve_mls(z27, __ B, p6, z15, z2); // mls z27.b, p6/m, z15.b, z2.b + __ sve_and(z30, z17, z25); // and z30.d, z17.d, z25.d + __ sve_eor(z2, z24, z3); // eor z2.d, z24.d, z3.d + __ sve_orr(z29, z13, z3); // orr z29.d, z13.d, z3.d + __ sve_bic(z14, z16, z28); // bic z14.d, z16.d, z28.d + __ sve_uzp1(z4, __ S, z11, z27); // uzp1 z4.s, z11.s, z27.s + __ sve_uzp2(z2, __ D, z16, z1); // uzp2 z2.d, z16.d, z1.d + __ sve_fabd(z7, __ D, p5, z31); // fabd z7.d, p5/m, z7.d, z31.d + __ sve_bext(z16, __ S, z10, z22); // bext z16.s, z10.s, z22.s + __ sve_bdep(z29, __ B, z7, z22); // bdep z29.b, z7.b, z22.b + __ sve_eor3(z12, z24, z11); // eor3 z12.d, z12.d, z24.d, z11.d // SVEReductionOp - __ sve_andv(v27, __ H, p4, z4); // andv h27, p4, z4.h - __ sve_orv(v26, __ S, p4, z2); // orv s26, p4, z2.s - __ sve_eorv(v1, __ S, p7, z7); // eorv s1, p7, z7.s - __ sve_smaxv(v30, __ H, p7, z16); // smaxv h30, p7, z16.h - __ sve_sminv(v21, __ B, p4, z28); // sminv b21, p4, z28.b - __ sve_fminv(v21, __ D, p1, z12); // fminv d21, p1, z12.d - __ sve_fmaxv(v11, __ S, p2, z10); // fmaxv s11, p2, z10.s - __ sve_fadda(v0, __ D, p1, z22); // fadda d0, p1, d0, z22.d - __ sve_uaddv(v20, __ H, p1, z3); // uaddv d20, p1, z3.h + __ sve_andv(v11, __ B, p2, z0); // andv b11, p2, z0.b + __ sve_orv(v23, __ B, p5, z20); // orv b23, p5, z20.b + __ sve_eorv(v3, __ B, p3, z15); // eorv b3, p3, z15.b + __ sve_smaxv(v30, __ B, p6, z27); // smaxv b30, p6, z27.b + __ sve_sminv(v21, __ D, p6, z10); // sminv d21, p6, z10.d + __ sve_fminv(v3, __ S, p6, z4); // fminv s3, p6, z4.s + __ sve_fmaxv(v6, __ S, p0, z21); // fmaxv s6, p0, z21.s + __ sve_fadda(v25, __ D, p6, z30); // fadda d25, p6, d25, z30.d + __ sve_uaddv(v31, __ H, p4, z1); // uaddv d31, p4, z1.h + +// AddWideNEONOp + __ saddwv(v12, v13, __ T8H, v14, __ T8B); // saddw v12.8H, v13.8H, v14.8B + __ saddwv2(v30, v31, __ T8H, v0, __ T16B); // saddw2 v30.8H, v31.8H, v0.16B + __ saddwv(v13, v14, __ T4S, v15, __ T4H); // saddw v13.4S, v14.4S, v15.4H + __ saddwv2(v8, v9, __ T4S, v10, __ T8H); // saddw2 v8.4S, v9.4S, v10.8H + __ saddwv(v25, v26, __ T2D, v27, __ T2S); // saddw v25.2D, v26.2D, v27.2S + __ saddwv2(v29, v30, __ T2D, v31, __ T4S); // saddw2 v29.2D, v30.2D, v31.4S + __ uaddwv(v1, v2, __ T8H, v3, __ T8B); // uaddw v1.8H, v2.8H, v3.8B + __ uaddwv2(v31, v0, __ T8H, v1, __ T16B); // uaddw2 v31.8H, v0.8H, v1.16B + __ uaddwv(v23, v24, __ T4S, v25, __ T4H); // uaddw v23.4S, v24.4S, v25.4H + __ uaddwv2(v31, v0, __ T4S, v1, __ T8H); // uaddw2 v31.4S, v0.4S, v1.8H + __ uaddwv(v20, v21, __ T2D, v22, __ T2S); // uaddw v20.2D, v21.2D, v22.2S + __ uaddwv2(v0, v1, __ T2D, v2, __ T4S); // uaddw2 v0.2D, v1.2D, v2.4S __ bind(forth); @@ -1298,30 +1327,30 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x14000428, 0x94000000, - 0x97ffffd4, 0x94000425, 0x3400000a, 0x34fffa2a, - 0x3400844a, 0x35000008, 0x35fff9c8, 0x350083e8, - 0xb400000b, 0xb4fff96b, 0xb400838b, 0xb500001d, - 0xb5fff91d, 0xb500833d, 0x10000013, 0x10fff8b3, - 0x100082d3, 0x90000013, 0x36300016, 0x3637f836, - 0x36308256, 0x3758000c, 0x375ff7cc, 0x375881ec, + 0x14000000, 0x17ffffd7, 0x14000441, 0x94000000, + 0x97ffffd4, 0x9400043e, 0x3400000a, 0x34fffa2a, + 0x3400876a, 0x35000008, 0x35fff9c8, 0x35008708, + 0xb400000b, 0xb4fff96b, 0xb40086ab, 0xb500001d, + 0xb5fff91d, 0xb500865d, 0x10000013, 0x10fff8b3, + 0x100085f3, 0x90000013, 0x36300016, 0x3637f836, + 0x36308576, 0x3758000c, 0x375ff7cc, 0x3758850c, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x54007fc0, 0x54000001, 0x54fff541, 0x54007f61, - 0x54000002, 0x54fff4e2, 0x54007f02, 0x54000002, - 0x54fff482, 0x54007ea2, 0x54000003, 0x54fff423, - 0x54007e43, 0x54000003, 0x54fff3c3, 0x54007de3, - 0x54000004, 0x54fff364, 0x54007d84, 0x54000005, - 0x54fff305, 0x54007d25, 0x54000006, 0x54fff2a6, - 0x54007cc6, 0x54000007, 0x54fff247, 0x54007c67, - 0x54000008, 0x54fff1e8, 0x54007c08, 0x54000009, - 0x54fff189, 0x54007ba9, 0x5400000a, 0x54fff12a, - 0x54007b4a, 0x5400000b, 0x54fff0cb, 0x54007aeb, - 0x5400000c, 0x54fff06c, 0x54007a8c, 0x5400000d, - 0x54fff00d, 0x54007a2d, 0x5400000e, 0x54ffefae, - 0x540079ce, 0x5400000f, 0x54ffef4f, 0x5400796f, + 0x540082e0, 0x54000001, 0x54fff541, 0x54008281, + 0x54000002, 0x54fff4e2, 0x54008222, 0x54000002, + 0x54fff482, 0x540081c2, 0x54000003, 0x54fff423, + 0x54008163, 0x54000003, 0x54fff3c3, 0x54008103, + 0x54000004, 0x54fff364, 0x540080a4, 0x54000005, + 0x54fff305, 0x54008045, 0x54000006, 0x54fff2a6, + 0x54007fe6, 0x54000007, 0x54fff247, 0x54007f87, + 0x54000008, 0x54fff1e8, 0x54007f28, 0x54000009, + 0x54fff189, 0x54007ec9, 0x5400000a, 0x54fff12a, + 0x54007e6a, 0x5400000b, 0x54fff0cb, 0x54007e0b, + 0x5400000c, 0x54fff06c, 0x54007dac, 0x5400000d, + 0x54fff00d, 0x54007d4d, 0x5400000e, 0x54ffefae, + 0x54007cee, 0x5400000f, 0x54ffef4f, 0x54007c8f, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, @@ -1346,23 +1375,23 @@ 0xb81b1022, 0x381ea354, 0x79002fd7, 0xf85cf39a, 0xb8580309, 0x385e218c, 0x784051e1, 0x389e11d8, 0x789fa1f8, 0x79c01865, 0xb881131b, 0xfc5dd3ad, - 0xbc5d1136, 0xfc00900b, 0xbc181014, 0xf818ec7d, + 0xbc5d1137, 0xfc00900b, 0xbc181015, 0xf818ec7d, 0xb81b8c91, 0x381efc40, 0x78007c3d, 0xf857beb0, 0xb8413dd4, 0x385fddd6, 0x78409e2f, 0x389eddea, 0x789e7d94, 0x78de3d55, 0xb8805c13, 0xfc5cadc0, - 0xbc428c23, 0xfc1a2dc4, 0xbc1caf91, 0xf81475f6, + 0xbc428c23, 0xfc1a2dc4, 0xbc1caf92, 0xf81475f6, 0xb81f95d1, 0x381e757e, 0x78014561, 0xf8402436, 0xb85896e2, 0x385f4763, 0x785db4f0, 0x3880374f, 0x789e25e7, 0x78dd0563, 0xb88166f9, 0xfc529540, - 0xbc4374d1, 0xfc1166ad, 0xbc1ba6c0, 0xf820ea7b, + 0xbc4374d3, 0xfc1166ae, 0xbc1ba6c0, 0xf820ea7b, 0xb82d68c8, 0x38367a04, 0x782f4b59, 0xf878c8a4, 0xb8674a24, 0x386b78f1, 0x78776bc0, 0x38a15aca, - 0x78bedbd5, 0x78fcd94b, 0xb8aa4a7c, 0xfc6ecbbd, - 0xbc65d8a8, 0xfc2de918, 0xbc3a7b11, 0xf91f1193, + 0x78bedbd5, 0x78fcd94b, 0xb8aa4a7c, 0xfc6ecbbe, + 0xbc65d8a8, 0xfc2de919, 0xbc3a7b11, 0xf91f1193, 0xb91ed5f7, 0x391ec9bd, 0x79182ceb, 0xf95d4b0a, 0xb9581010, 0x395fc034, 0x795fb221, 0x399d8731, 0x799efb3b, 0x79dd1a2e, 0xb998e4ea, 0xfd583723, - 0xbd5ea12c, 0xfd18dc37, 0xbd1b0e83, 0x58ffdaa2, + 0xbd5ea12c, 0xfd18dc38, 0xbd1b0e83, 0x58ffdaa2, 0x1800001d, 0xf885d1c0, 0xd8ffda40, 0xf8a77820, 0xf9980220, 0x1a030301, 0x3a140311, 0x5a0d000b, 0x7a07015c, 0x9a1001e4, 0xba140182, 0xda0d01bd, @@ -1383,187 +1412,193 @@ 0x9ad521f7, 0x9adb263c, 0x9ac0286a, 0x9ac92f27, 0x9bdd7de6, 0x9b427d4f, 0x1b0b2cf1, 0x1b1ddcf7, 0x9b0b2f6e, 0x9b0cbf04, 0x9b2b728e, 0x9b2cdd6d, - 0x9bae275e, 0x9ba7954d, 0x7ea3d5fd, 0x1e2f098b, - 0x1e311bde, 0x1e2f2a93, 0x1e35392f, 0x7efbd522, - 0x1e7e0ba7, 0x1e621831, 0x1e632946, 0x1e673978, - 0x1f000d61, 0x1f06db91, 0x1f3b6806, 0x1f2770a2, - 0x1f4d2f2b, 0x1f48c677, 0x1f744f35, 0x1f7d5851, - 0x1e2042a8, 0x1e20c293, 0x1e21422b, 0x1e21c0d4, - 0x1e22c06f, 0x1e23c383, 0x1ee24363, 0x1e6041ce, - 0x1e60c18a, 0x1e61422b, 0x1e61c32a, 0x1e6240e7, - 0x1e38038e, 0x9e3802c0, 0x1e780180, 0x9e7801b7, - 0x1e2200ed, 0x9e2200ee, 0x1e620288, 0x9e620391, - 0x1e24021e, 0x9e640122, 0x1e300290, 0x9e70009d, - 0x1e260341, 0x9e6602f8, 0x1e2702ae, 0x9e6700ac, - 0x1e382180, 0x1e7d2300, 0x1e202368, 0x1e6022a8, + 0x9bae275e, 0x9ba7954d, 0x7ea3d5fe, 0x1e30098c, + 0x1e321bff, 0x1e302ab3, 0x1e35394f, 0x7efcd542, + 0x1e7f0bc7, 0x1e621832, 0x1e632946, 0x1e673979, + 0x1f000d81, 0x1f06dfb3, 0x1f3c6c06, 0x1f2774a2, + 0x1f4d332c, 0x1f48ca78, 0x1f755356, 0x1f7e5853, + 0x1e2042c8, 0x1e20c2b3, 0x1e21424c, 0x1e21c0d5, + 0x1e22c070, 0x1e23c3a3, 0x1ee24383, 0x1e6041cf, + 0x1e60c1aa, 0x1e61424c, 0x1e61c34a, 0x1e6240e7, + 0x1e3803ae, 0x9e3802e0, 0x1e780180, 0x9e7801d7, + 0x1e2200ed, 0x9e2200ef, 0x1e620289, 0x9e620393, + 0x1e24021e, 0x9e640122, 0x1e3002b0, 0x9e70009d, + 0x1e260361, 0x9e660318, 0x1e2702ae, 0x9e6700ad, + 0x1e392180, 0x1e7e2320, 0x1e202388, 0x1e6022a8, 0x293a1796, 0x29426e73, 0x697c68fc, 0xa93d0486, 0xa97b5eba, 0x29b47934, 0x29c2534d, 0x69f62dbd, 0xa9bd54bb, 0xa9c503c6, 0x28a63e13, 0x28e25d2c, 0x68c469e0, 0xa8b34748, 0xa8f51c59, 0x28264433, 0x285036c0, 0xa8005f7d, 0xa872290b, 0x0c407160, - 0x4cdfa350, 0x0cd16f55, 0x4cdf27ba, 0x0d40c0d5, - 0x4ddfcbad, 0x0dd0cd95, 0x4c408c01, 0x0cdf86a9, - 0x4d60c327, 0x0dffc928, 0x4deecd89, 0x4cd14887, - 0x0c404a37, 0x4d40e6c3, 0x4ddfe84c, 0x0dcced4f, - 0x4cdf0444, 0x0ccb0286, 0x0d60e18b, 0x0dffe62f, - 0x0df0eb2e, 0x0e31bab4, 0x4e31b841, 0x0e71baf6, + 0x4cdfa350, 0x0cd16f56, 0x4cdf27bb, 0x0d40c0d6, + 0x4ddfcbae, 0x0dd0cd96, 0x4c408c01, 0x0cdf86aa, + 0x4d60c327, 0x0dffc929, 0x4deecd89, 0x4cd14887, + 0x0c404a37, 0x4d40e6c4, 0x4ddfe84d, 0x0dcced50, + 0x4cdf0444, 0x0ccb0286, 0x0d60e18c, 0x0dffe630, + 0x0df0eb2e, 0x0e31bab4, 0x4e31b841, 0x0e71bb17, 0x4e71bbfe, 0x4eb1b9ee, 0x0e30a862, 0x4e30a8e6, - 0x0e70a883, 0x4e70a907, 0x4eb0ab38, 0x6e30f820, - 0x0e31ab9b, 0x2e31abdd, 0x4e31a8c5, 0x6e31a8c5, - 0x0e71abdd, 0x2e71a98b, 0x4e71ab59, 0x6e71a820, - 0x4eb1abfe, 0x6eb1a820, 0x6eb0fa51, 0x7e30fbbc, - 0x7e70fb59, 0x7eb0f949, 0x7ef0fb59, 0x0ea0c9ac, - 0x4ea0ca0f, 0x4ee0c98b, 0x2ea0c96a, 0x6ea0ca51, - 0x6ee0cb38, 0x0ea0dad5, 0x4ea0db17, 0x4ee0d820, - 0x0ea0ea30, 0x4ea0e96a, 0x4ee0e8e6, 0x2ea0dbbc, - 0x6ea0d8e6, 0x6ee0d8c5, 0x0e20b8c5, 0x4e20bab4, - 0x0e60ba51, 0x4e60ba0f, 0x0ea0ba51, 0x4ea0bbdd, - 0x4ee0bb7a, 0x0ea0fbbc, 0x4ea0f841, 0x4ee0fb9b, - 0x2ea0f820, 0x6ea0fab4, 0x6ee0fbbc, 0x2ea1fa0f, - 0x6ea1f9ac, 0x6ee1f96a, 0x2e205bbc, 0x6e205bbc, + 0x0e70a883, 0x4e70a928, 0x4eb0ab59, 0x6e30f820, + 0x0e31ab9b, 0x2e31abfe, 0x4e31a8c5, 0x6e31a8c5, + 0x0e71abfe, 0x2e71a98b, 0x4e71ab59, 0x6e71a820, + 0x4eb1a81f, 0x6eb1a820, 0x6eb0fa93, 0x7e30fbdd, + 0x7e70fb7a, 0x7eb0f949, 0x7ef0fb7a, 0x0ea0c9ac, + 0x4ea0ca0f, 0x4ee0c98b, 0x2ea0c98b, 0x6ea0ca72, + 0x6ee0cb59, 0x0ea0daf6, 0x4ea0db38, 0x4ee0d820, + 0x0ea0ea51, 0x4ea0e98b, 0x4ee0e8e6, 0x2ea0dbdd, + 0x6ea0d8e6, 0x6ee0d8c5, 0x0e20b8c5, 0x4e20bad5, + 0x0e60ba93, 0x4e60ba30, 0x0ea0ba72, 0x4ea0bbfe, + 0x4ee0bb9b, 0x0ea0fbbc, 0x4ea0f841, 0x4ee0fbbc, + 0x2ea0f841, 0x6ea0fab4, 0x6ee0fbdd, 0x2ea1fa30, + 0x6ea1f9cd, 0x6ee1f96a, 0x2e205bdd, 0x6e205bdd, 0x0e351e93, 0x4e381ef6, 0x0eac1d6a, 0x4ea61ca4, - 0x2e201ffe, 0x6e361eb4, 0x0e2a8528, 0x4e2087fe, - 0x0e738651, 0x4e6c856a, 0x0ebd879b, 0x4ea48462, - 0x4efa8738, 0x0e26d4a4, 0x4e25d483, 0x4e6ad528, - 0x2e3886f6, 0x6e338651, 0x2e6f85cd, 0x6e6684a4, - 0x2ebe87bc, 0x6eb98717, 0x6ef786d5, 0x0ebbd759, - 0x4ebad738, 0x4ee5d483, 0x0e399f17, 0x4e3c9f7a, - 0x0e799f17, 0x4e709dee, 0x0eb79ed5, 0x4ea59c83, - 0x2eb9d717, 0x6eaad528, 0x6efad738, 0x2e35d693, - 0x6e31d60f, 0x6e72d630, 0x2e24dc62, 0x6e23dc41, + 0x2e211c1f, 0x6e371ed5, 0x0e2a8528, 0x4e21841f, + 0x0e758693, 0x4e6c856a, 0x0ebe87bc, 0x4ea48462, + 0x4efb8759, 0x0e27d4c5, 0x4e25d483, 0x4e6ad528, + 0x2e3886f6, 0x6e358693, 0x2e6f85cd, 0x6e6784c5, + 0x2ebf87dd, 0x6eba8738, 0x6ef786d5, 0x0ebcd77a, + 0x4ebad738, 0x4ee5d483, 0x0e3a9f38, 0x4e3c9f7a, + 0x0e799f17, 0x4e719e0f, 0x0eb79ed5, 0x4ea59c83, + 0x2ebad738, 0x6eaad528, 0x6efbd759, 0x2e36d6b4, + 0x6e32d630, 0x6e73d651, 0x2e24dc62, 0x6e23dc41, 0x6e62dc20, 0x0e7a9738, 0x4e6694a4, 0x0ea59483, - 0x4ead958b, 0x0e20cffe, 0x4e3dcf9b, 0x4e6bcd49, - 0x2e7b9759, 0x6e649462, 0x2eae95ac, 0x6eb39651, - 0x0ea0cffe, 0x4ea3cc41, 0x4eeecdac, 0x2e3effbc, - 0x6e22fc20, 0x6e73fe51, 0x0e2e65ac, 0x4e336651, - 0x0e7766d5, 0x4e6e65ac, 0x0ebd679b, 0x4ebf67dd, - 0x0e20a7fe, 0x4e23a441, 0x0e7ba759, 0x4e7da79b, - 0x0ea6a4a4, 0x4ebfa7dd, 0x0e25f483, 0x4e28f4e6, - 0x4e7ff7dd, 0x0e3b6f59, 0x4e336e51, 0x0e6a6d28, - 0x4e696d07, 0x0eae6dac, 0x4ea26c20, 0x0e35ae93, - 0x4e23ac41, 0x0e79af17, 0x4e64ac62, 0x0ea2ac20, - 0x4eaaad28, 0x0eb9f717, 0x4ebbf759, 0x4ef1f60f, - 0x2ebfefdd, 0x6ea5ec83, 0x6eeced6a, 0x0e3836f6, - 0x4e2c356a, 0x0e6634a4, 0x4e733651, 0x0ea33441, - 0x4ead358b, 0x4ee93507, 0x0e2c3d6a, 0x4e313e0f, - 0x0e723e30, 0x4e643c62, 0x0eab3d49, 0x4ead3d8b, - 0x4eee3dac, 0x2e308dee, 0x6e2f8dcd, 0x2e648c62, - 0x6e688ce6, 0x2eb58e93, 0x6ebb8f59, 0x6ef18e0f, - 0x2e2634a4, 0x6e243462, 0x2e6634a4, 0x6e6d358b, - 0x2eb33651, 0x6eb636b4, 0x6ef23630, 0x2e333e51, - 0x6e2c3d6a, 0x2e763eb4, 0x6e783ef6, 0x2eae3dac, - 0x6ebb3f59, 0x6ef93f17, 0x0e3ee7bc, 0x4e30e5ee, - 0x4e6ce56a, 0x2ebae738, 0x6ea3e441, 0x6eede58b, - 0x2e20e7fe, 0x6e2ce56a, 0x6e71e60f, 0x65922c43, - 0x65d02219, 0x65d02560, 0x65d13dc4, 0x65913690, - 0x65d33b6b, 0x2500948c, 0x254c08bf, 0x25831f87, - 0x254f30af, 0x259c3359, 0x25019d35, 0x24eac76d, - 0x2431993a, 0x242f7ed8, 0x24a2f62b, 0xba5fd3e3, - 0x3a5f03e5, 0xfa411be4, 0x7a42cbe2, 0x93df03ff, - 0xc820ffff, 0x8822fc7f, 0xc8247cbf, 0x88267fff, - 0x4e010fe0, 0x5e040420, 0x4e081fe1, 0x4e0c1fe1, - 0x4e0a1fe1, 0x4e071fe1, 0x4e042c20, 0x4e062c20, - 0x4e052c20, 0x4e083c20, 0x0e0c3c20, 0x0e0a3c20, - 0x0e073c20, 0x9eae0020, 0x0f03f409, 0x6f03f40e, - 0x4cc0ac3f, 0x0ea1b820, 0x4e21c862, 0x4e61b8a4, - 0x05a08020, 0x05104fe0, 0x05505001, 0x05906fe2, - 0x05d03005, 0x05101fea, 0x05901feb, 0x04b0e3e0, - 0x0470e7e1, 0x042f9c20, 0x043f9c35, 0x047f9c20, - 0x04ff9c20, 0x04299420, 0x04319160, 0x0461943e, - 0x04a19020, 0x04038100, 0x040381a0, 0x040387e1, - 0x04438be2, 0x04c38fe3, 0x040181e0, 0x04018100, - 0x04018621, 0x04418b22, 0x04418822, 0x04818c23, - 0x040081e0, 0x04008120, 0x04008761, 0x04008621, - 0x04408822, 0x04808c23, 0x042053ff, 0x047f5401, - 0x25208028, 0x2538cfe0, 0x2578d001, 0x25b8efe2, - 0x25f8f007, 0x2538dfea, 0x25b8dfeb, 0xa400a3e0, - 0xa420a7e0, 0xa4484be0, 0xa467afe0, 0xa4a8a7ea, - 0xa547a814, 0xa4084ffe, 0xa55c53e0, 0xa5e1540b, - 0xe400fbf6, 0xe408ffff, 0xe420e7e0, 0xe4484be0, - 0xe460efe0, 0xe547e400, 0xe4014be0, 0xe4a84fe0, - 0xe5f15000, 0x858043e0, 0x85a043ff, 0xe59f5d08, - 0x0420e3e9, 0x0460e3ea, 0x04a0e3eb, 0x04e0e3ec, - 0x25104042, 0x25104871, 0x25904861, 0x25904c92, - 0x05344020, 0x05744041, 0x05b44062, 0x05f44083, - 0x252c8840, 0x253c1420, 0x25681572, 0x25a21ce3, - 0x25ea1e34, 0x253c0421, 0x25680572, 0x25a20ce3, - 0x25ea0e34, 0x0522c020, 0x05e6c0a4, 0x2401a001, - 0x2443a051, 0x24858881, 0x24c78cd1, 0x24850891, - 0x24c70cc1, 0x250f9001, 0x25508051, 0x25802491, - 0x25df28c1, 0x25850c81, 0x251e10d1, 0x65816001, - 0x65c36051, 0x65854891, 0x65c74cc1, 0x05733820, - 0x05b238a4, 0x05f138e6, 0x0570396a, 0x65d0a001, - 0x65d6a443, 0x65d4a826, 0x6594ac26, 0x6554ac26, - 0x6556ac26, 0x6552ac26, 0x65cbac85, 0x65caac01, - 0x6589ac85, 0x6588ac01, 0x65c9ac85, 0x65c8ac01, - 0x65dea833, 0x659ca509, 0x65d8a801, 0x65dcac01, - 0x655cb241, 0x0520a1e0, 0x0521a601, 0x052281e0, - 0x05238601, 0x04a14026, 0x042244a6, 0x046344a6, - 0x04a444a6, 0x04e544a7, 0x0568aca7, 0x05b23230, - 0x853040af, 0xc5b040af, 0xe57080af, 0xe5b080af, - 0x25034440, 0x254054c4, 0x25034640, 0x25415a05, - 0x25834440, 0x25c54489, 0x250b5d3a, 0x2550dc20, - 0x2518e3e1, 0x2518e021, 0x2518e0a1, 0x2518e121, - 0x2518e1a1, 0x2558e3e2, 0x2558e042, 0x2558e0c2, - 0x2558e142, 0x2598e3e3, 0x2598e063, 0x2598e0e3, - 0x2598e163, 0x25d8e3e4, 0x25d8e084, 0x25d8e104, - 0x25d8e184, 0x2518e407, 0x05214800, 0x05614800, - 0x05a14800, 0x05e14800, 0x05214c00, 0x05614c00, - 0x05a14c00, 0x05e14c00, 0x05304001, 0x05314001, - 0x05a18610, 0x05e18610, 0x05271e11, 0x6545e891, - 0x6585e891, 0x65c5e891, 0x6545c891, 0x6585c891, - 0x65c5c891, 0x45b0c210, 0x45f1c231, 0x1e601000, - 0x1e603000, 0x1e621000, 0x1e623000, 0x1e641000, - 0x1e643000, 0x1e661000, 0x1e663000, 0x1e681000, - 0x1e683000, 0x1e6a1000, 0x1e6a3000, 0x1e6c1000, - 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, 0x1e701000, - 0x1e703000, 0x1e721000, 0x1e723000, 0x1e741000, - 0x1e743000, 0x1e761000, 0x1e763000, 0x1e781000, - 0x1e783000, 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, - 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, 0xf82f8186, - 0xf83001ab, 0xf83713c1, 0xf8332225, 0xf82232d0, - 0xf82d52aa, 0xf83d419b, 0xf83b7023, 0xf83f6278, - 0xf8b18389, 0xf8bb00ef, 0xf8b513f7, 0xf8b923e2, - 0xf8bb3150, 0xf8b75073, 0xf8b04320, 0xf8ba7057, - 0xf8b0608c, 0xf8fc83be, 0xf8f000db, 0xf8e911fd, - 0xf8e720e4, 0xf8ef32e9, 0xf8e85382, 0xf8f540bf, - 0xf8fb7220, 0xf8ef6344, 0xf86882dc, 0xf87b033b, - 0xf8771080, 0xf8662010, 0xf864302f, 0xf86a50a7, - 0xf86a40fc, 0xf87472b7, 0xf866610b, 0xb83180df, - 0xb8310182, 0xb83e107d, 0xb83b23b6, 0xb82e338d, - 0xb83150b8, 0xb822414e, 0xb830736b, 0xb837608c, - 0xb8b68091, 0xb8a10213, 0xb8b011cd, 0xb8ac2222, - 0xb8a332f5, 0xb8a550e6, 0xb8b3438d, 0xb8b170d0, - 0xb8a2607d, 0xb8e481e6, 0xb8f4018d, 0xb8f41328, - 0xb8f42013, 0xb8eb30d8, 0xb8f451df, 0xb8f04006, - 0xb8e7726f, 0xb8fa6149, 0xb87782d5, 0xb87c0062, - 0xb86f1293, 0xb86723a4, 0xb8673120, 0xb87052f4, - 0xb8644150, 0xb877732b, 0xb866621f, 0xce2b06cd, - 0xce14410d, 0xce648df9, 0xce883624, 0xce7c809d, - 0xce7a87b0, 0xcec081c9, 0xce7c8962, 0x2520c143, - 0x25a1d2da, 0x058015ce, 0x05400ed8, 0x0500bb31, - 0x25a0c074, 0x25a1d884, 0x05804944, 0x0540b1d9, - 0x05001548, 0x25a0c49e, 0x2521cabe, 0x058054b3, - 0x0543ab47, 0x050026bb, 0x2560d097, 0x25a1d6fe, - 0x058394b4, 0x0540266d, 0x05003cbc, 0x25a0c1ab, - 0x2561d3f8, 0x05800acd, 0x05403684, 0x05000c07, - 0x2560de64, 0x2521cac5, 0x0583c8b5, 0x05405089, - 0x05003e98, 0x04ad0397, 0x04ac074a, 0x658e023e, - 0x65d50a1d, 0x65820667, 0x0496b13a, 0x04001411, - 0x041a19c2, 0x049095cb, 0x041b0c7d, 0x04d9a876, - 0x049aa27b, 0x04591aa7, 0x04138b25, 0x04119235, - 0x04500a63, 0x0497adc7, 0x04dea9b1, 0x04581e31, - 0x05a78f4f, 0x056494fb, 0x04481f65, 0x048a0f00, - 0x04810074, 0x04dca739, 0x65809031, 0x658d9dae, - 0x65c683d1, 0x658797b6, 0x65828008, 0x04ddb417, - 0x6582baf9, 0x6580b435, 0x65c1b56a, 0x65cdb917, - 0x65c19671, 0x65fe95a4, 0x65f11f3e, 0x65fc298e, - 0x65ada1a5, 0x65b3c967, 0x65e3ec59, 0x65f454a0, - 0x65a86dbc, 0x041b41dd, 0x04587903, 0x042a3321, - 0x04b93281, 0x0470327c, 0x04e131bb, 0x0521692b, - 0x057a6f61, 0x65c887a2, 0x45c2b058, 0x455cb723, - 0x043639a3, 0x045a309b, 0x0498305a, 0x04993ce1, - 0x04483e1e, 0x040a3395, 0x65c72595, 0x6586294b, - 0x65d826c0, 0x04412474, + 0x4eae95ac, 0x0e21cc1f, 0x4e3ecfbc, 0x4e6ccd6a, + 0x2e7c977a, 0x6e649462, 0x2eae95ac, 0x6eb49672, + 0x0ea1cc1f, 0x4ea3cc41, 0x4eefcdcd, 0x2e3fffdd, + 0x6e22fc20, 0x6e75fe93, 0x0e2e65ac, 0x4e336651, + 0x0e7866f6, 0x4e6f65cd, 0x0ebe67bc, 0x4ea067fe, + 0x0e21a41f, 0x4e23a441, 0x0e7ca77a, 0x4e7ea7bc, + 0x0ea6a4a4, 0x4ea0a7fe, 0x0e26f4a4, 0x4e28f4e6, + 0x4e60f7fe, 0x0e3c6f7a, 0x4e346e72, 0x0e6b6d49, + 0x4e6a6d28, 0x0eae6dac, 0x4ea26c20, 0x0e36aeb4, + 0x4e23ac41, 0x0e7aaf38, 0x4e64ac62, 0x0ea2ac20, + 0x4eabad49, 0x0ebaf738, 0x4ebcf77a, 0x4ef2f630, + 0x2ea0effe, 0x6ea5ec83, 0x6eeced6a, 0x0fa710c5, + 0x4f8b8149, 0x4fc710c5, 0x0f8750c5, 0x4faa8128, + 0x4fc750c5, 0x2f8890e6, 0x4fa880e6, 0x6fc59083, + 0x0f6f81cd, 0x4f448862, 0x0f848062, 0x4fab8149, + 0x0e3736d5, 0x4e323630, 0x0e743672, 0x4e6d358b, + 0x0eb736d5, 0x4eb93717, 0x4eee35ac, 0x0e3c3f7a, + 0x4e393f17, 0x0e7e3fbc, 0x4e703dee, 0x0ead3d8b, + 0x4eba3f38, 0x4ee33c41, 0x2e2e8dac, 0x6e218c1f, + 0x2e6c8d6a, 0x6e728e30, 0x2ea98d07, 0x6ea48c62, + 0x6ee58c83, 0x2e2f35cd, 0x6e353693, 0x2e733651, + 0x6e723630, 0x2ea53483, 0x6ea33441, 0x6eed358b, + 0x2e203ffe, 0x6e273cc5, 0x2e6a3d28, 0x6e713e0f, + 0x2ebf3fdd, 0x6ea03ffe, 0x6ee23c20, 0x0e36e6b4, + 0x4e29e507, 0x4e76e6b4, 0x2eb9e717, 0x6ebee7bc, + 0x6ef7e6d5, 0x2e3de79b, 0x6e3be759, 0x6e67e4c5, + 0x65d23ee0, 0x65903d92, 0x65d03fa7, 0x65912fe9, + 0x65d13bf9, 0x65932a0a, 0x25cb90c4, 0x25040bde, + 0x25c11085, 0x25c62c6b, 0x259f2279, 0x259d8993, + 0x24e5102b, 0x24ad5458, 0x24ec7ab5, 0x24387c6d, + 0xba5fd3e3, 0x3a5f03e5, 0xfa411be4, 0x7a42cbe2, + 0x93df03ff, 0xc820ffff, 0x8822fc7f, 0xc8247cbf, + 0x88267fff, 0x4e010fe0, 0x5e040420, 0x4e081fe1, + 0x4e0c1fe1, 0x4e0a1fe1, 0x4e071fe1, 0x4e042c20, + 0x4e062c20, 0x4e052c20, 0x4e083c20, 0x0e0c3c20, + 0x0e0a3c20, 0x0e073c20, 0x9eae0020, 0x0f03f409, + 0x6f03f40e, 0x4cc0ac3f, 0x0ea1b820, 0x4e21c862, + 0x4e61b8a4, 0x05a08020, 0x05104fe0, 0x05505001, + 0x05906fe2, 0x05d03005, 0x05101fea, 0x05901feb, + 0x04b0e3e0, 0x0470e7e1, 0x042f9c20, 0x043f9c35, + 0x047f9c20, 0x04ff9c20, 0x04299420, 0x04319160, + 0x0461943e, 0x04a19020, 0x04038100, 0x040381a0, + 0x040387e1, 0x04438be2, 0x04c38fe3, 0x040181e0, + 0x04018100, 0x04018621, 0x04418b22, 0x04418822, + 0x04818c23, 0x040081e0, 0x04008120, 0x04008761, + 0x04008621, 0x04408822, 0x04808c23, 0x042053ff, + 0x047f5401, 0x25208028, 0x2538cfe0, 0x2578d001, + 0x25b8efe2, 0x25f8f007, 0x2538dfea, 0x25b8dfeb, + 0xa400a3e0, 0xa420a7e0, 0xa4484be0, 0xa467afe0, + 0xa4a8a7ea, 0xa547a814, 0xa4084ffe, 0xa55c53e0, + 0xa5e1540b, 0xe400fbf6, 0xe408ffff, 0xe420e7e0, + 0xe4484be0, 0xe460efe0, 0xe547e400, 0xe4014be0, + 0xe4a84fe0, 0xe5f15000, 0x858043e0, 0x85a043ff, + 0xe59f5d08, 0x0420e3e9, 0x0460e3ea, 0x04a0e3eb, + 0x04e0e3ec, 0x25104042, 0x25104871, 0x25904861, + 0x25904c92, 0x05344020, 0x05744041, 0x05b44062, + 0x05f44083, 0x252c8840, 0x253c1420, 0x25681572, + 0x25a21ce3, 0x25ea1e34, 0x253c0421, 0x25680572, + 0x25a20ce3, 0x25ea0e34, 0x0522c020, 0x05e6c0a4, + 0x2401a001, 0x2443a051, 0x24858881, 0x24c78cd1, + 0x24850891, 0x24c70cc1, 0x250f9001, 0x25508051, + 0x25802491, 0x25df28c1, 0x25850c81, 0x251e10d1, + 0x65816001, 0x65c36051, 0x65854891, 0x65c74cc1, + 0x05733820, 0x05b238a4, 0x05f138e6, 0x0570396a, + 0x65d0a001, 0x65d6a443, 0x65d4a826, 0x6594ac26, + 0x6554ac26, 0x6556ac26, 0x6552ac26, 0x65cbac85, + 0x65caac01, 0x6589ac85, 0x6588ac01, 0x65c9ac85, + 0x65c8ac01, 0x65dea833, 0x659ca509, 0x65d8a801, + 0x65dcac01, 0x655cb241, 0x0520a1e0, 0x0521a601, + 0x052281e0, 0x05238601, 0x04a14026, 0x042244a6, + 0x046344a6, 0x04a444a6, 0x04e544a7, 0x0568aca7, + 0x05b23230, 0x853040af, 0xc5b040af, 0xe57080af, + 0xe5b080af, 0x25034440, 0x254054c4, 0x25034640, + 0x25415a05, 0x25834440, 0x25c54489, 0x250b5d3a, + 0x2550dc20, 0x2518e3e1, 0x2518e021, 0x2518e0a1, + 0x2518e121, 0x2518e1a1, 0x2558e3e2, 0x2558e042, + 0x2558e0c2, 0x2558e142, 0x2598e3e3, 0x2598e063, + 0x2598e0e3, 0x2598e163, 0x25d8e3e4, 0x25d8e084, + 0x25d8e104, 0x25d8e184, 0x2518e407, 0x05214800, + 0x05614800, 0x05a14800, 0x05e14800, 0x05214c00, + 0x05614c00, 0x05a14c00, 0x05e14c00, 0x05304001, + 0x05314001, 0x05a18610, 0x05e18610, 0x05271e11, + 0x6545e891, 0x6585e891, 0x65c5e891, 0x6545c891, + 0x6585c891, 0x65c5c891, 0x45b0c210, 0x45f1c231, + 0x1e601000, 0x1e603000, 0x1e621000, 0x1e623000, + 0x1e641000, 0x1e643000, 0x1e661000, 0x1e663000, + 0x1e681000, 0x1e683000, 0x1e6a1000, 0x1e6a3000, + 0x1e6c1000, 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, + 0x1e701000, 0x1e703000, 0x1e721000, 0x1e723000, + 0x1e741000, 0x1e743000, 0x1e761000, 0x1e763000, + 0x1e781000, 0x1e783000, 0x1e7a1000, 0x1e7a3000, + 0x1e7c1000, 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, + 0xf8338131, 0xf83c01fb, 0xf82712f5, 0xf83f2059, + 0xf83f31fb, 0xf82a5277, 0xf8234010, 0xf83972fa, + 0xf8226190, 0xf8a483dc, 0xf8bd0370, 0xf8a613a9, + 0xf8b02087, 0xf8a7312f, 0xf8b75048, 0xf8bc43f5, + 0xf8a5701b, 0xf8b1608f, 0xf8fa8388, 0xf8f6037b, + 0xf8f91017, 0xf8e421e6, 0xf8e031e4, 0xf8e150ea, + 0xf8e5438a, 0xf8e772f4, 0xf8f56166, 0xf86883f1, + 0xf8660051, 0xf86c13be, 0xf86322db, 0xf87d31ae, + 0xf87c5311, 0xf86541c2, 0xf86a7170, 0xf87b6197, + 0xb8248236, 0xb8240261, 0xb83011b0, 0xb82e204c, + 0xb83132a3, 0xb83750c5, 0xb82741b3, 0xb83c7211, + 0xb82663a2, 0xb8a380c4, 0xb8b001b4, 0xb8ac1114, + 0xb8b92274, 0xb8a0330b, 0xb8a653f4, 0xb8ae40d0, + 0xb8a071e7, 0xb8b3613a, 0xb8ea82b7, 0xb8f6005c, + 0xb8e3126f, 0xb8f42087, 0xb8fd3007, 0xb8e95290, + 0xb8f74204, 0xb8ea7177, 0xb8f963e6, 0xb87082ed, + 0xb86c01c1, 0xb8691215, 0xb87a208f, 0xb8643110, + 0xb866509e, 0xb87d43b1, 0xb87a71e9, 0xb86263ab, + 0xce216ce3, 0xce0e2255, 0xce798ed2, 0xce959685, + 0xce7e8217, 0xce608694, 0xcec08264, 0xce748898, + 0x25e0da44, 0x2521c8f3, 0x05801548, 0x0540cbdf, + 0x05006521, 0x2560c7a0, 0x25a1c498, 0x058026bb, + 0x05407dd8, 0x0500f3d6, 0x2560ce3d, 0x2521d4b4, + 0x05803cbc, 0x05404d6c, 0x05001b89, 0x25a0c532, + 0x2521cc40, 0x05800c08, 0x054074c4, 0x050034a0, + 0x2520c9e3, 0x25e1ca93, 0x05803e98, 0x05425238, + 0x050024cb, 0x25a0ce7f, 0x25e1d0c3, 0x05802676, + 0x05401e63, 0x05002d49, 0x04e20080, 0x04ab04ce, + 0x659e022e, 0x65970863, 0x659c0703, 0x04d6b4f3, + 0x04400cb5, 0x049a06da, 0x04508071, 0x045b0d14, + 0x0459b22e, 0x04daba4d, 0x04590a13, 0x0493979b, + 0x04d188a8, 0x0450081c, 0x0417b6b9, 0x041eb743, + 0x04981e7a, 0x05e78dc1, 0x0564824e, 0x048816ff, + 0x040a0d1e, 0x04810ee0, 0x04dcb340, 0x65c08ed8, + 0x65cd8162, 0x65c6970c, 0x65c79e29, 0x65c29494, + 0x04ddbecd, 0x65c2ba5f, 0x65c0a9af, 0x6581a434, + 0x658da0ee, 0x65c1908c, 0x65be806f, 0x65ff0694, + 0x65ee2d2d, 0x65a3af81, 0x65a9cb3a, 0x65e1e9da, + 0x65f447ba, 0x65e17da6, 0x0401482b, 0x040279fb, + 0x0439323e, 0x04a33302, 0x046331bd, 0x04fc320e, + 0x05bb6964, 0x05e16e02, 0x65c897e7, 0x4596b150, + 0x4516b4fd, 0x0438396c, 0x041a280b, 0x04183697, + 0x04192de3, 0x04083b7e, 0x04ca3955, 0x65873883, + 0x658622a6, 0x65d83bd9, 0x0441303f, 0x0e2e11ac, + 0x4e2013fe, 0x0e6f11cd, 0x4e6a1128, 0x0ebb1359, + 0x4ebf13dd, 0x2e231041, 0x6e21101f, 0x2e791317, + 0x6e61101f, 0x2eb612b4, 0x6ea21020, }; // END Generated code -- do not edit From 1cf26a5179e619f17909426fdb26a3fb3b748483 Mon Sep 17 00:00:00 2001 From: Oli Gillespie Date: Mon, 30 Sep 2024 10:53:20 +0000 Subject: [PATCH 057/188] 8341013: Optimize x86/aarch64 MD5 intrinsics by reducing data dependency Reviewed-by: mli, ascarpino --- src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp | 10 +++++----- src/hotspot/cpu/x86/macroAssembler_x86_md5.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index ac88b427459c0..3dbde1ae8242b 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -3419,15 +3419,15 @@ class StubGenerator: public StubCodeGenerator { Register rscratch3 = r10; Register rscratch4 = r11; - __ andw(rscratch3, r2, r4); - __ bicw(rscratch4, r3, r4); reg_cache.extract_u32(rscratch1, k); __ movw(rscratch2, t); - __ orrw(rscratch3, rscratch3, rscratch4); __ addw(rscratch4, r1, rscratch2); __ addw(rscratch4, rscratch4, rscratch1); - __ addw(rscratch3, rscratch3, rscratch4); - __ rorw(rscratch2, rscratch3, 32 - s); + __ bicw(rscratch2, r3, r4); + __ andw(rscratch3, r2, r4); + __ addw(rscratch2, rscratch2, rscratch4); + __ addw(rscratch2, rscratch2, rscratch3); + __ rorw(rscratch2, rscratch2, 32 - s); __ addw(r1, rscratch2, r2); } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86_md5.cpp b/src/hotspot/cpu/x86/macroAssembler_x86_md5.cpp index 439c17b10d37a..09d379a4296d4 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86_md5.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86_md5.cpp @@ -81,8 +81,8 @@ void MacroAssembler::fast_md5(Register buf, Address state, Address ofs, Address notl(rsi); \ andl(rdi, r2); \ andl(rsi, r3); \ - orl(rsi, rdi); \ addl(r1, rsi); \ + addl(r1, rdi); \ roll(r1, s); \ addl(r1, r2); From 58b6fc5baa0931fa6f2aa37bf0bb125497cf6cc9 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 30 Sep 2024 10:56:52 +0000 Subject: [PATCH 058/188] 8341197: [BACKOUT] 8322770: Implement C2 VectorizedHashCode on AArch64 Reviewed-by: shade, jpai --- src/hotspot/cpu/aarch64/aarch64.ad | 78 -- src/hotspot/cpu/aarch64/assembler_aarch64.hpp | 68 +- .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 91 -- .../cpu/aarch64/c2_MacroAssembler_aarch64.hpp | 3 - .../cpu/aarch64/stubGenerator_aarch64.cpp | 312 ----- .../cpu/aarch64/stubRoutines_aarch64.cpp | 7 +- .../cpu/aarch64/stubRoutines_aarch64.hpp | 26 +- .../cpu/aarch64/vm_version_aarch64.cpp | 4 - src/hotspot/share/utilities/intpow.hpp | 46 - test/hotspot/gtest/aarch64/aarch64-asmtest.py | 111 -- test/hotspot/gtest/aarch64/asmtest.out.h | 1189 ++++++++--------- 11 files changed, 580 insertions(+), 1355 deletions(-) delete mode 100644 src/hotspot/share/utilities/intpow.hpp diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 0a93c27c2686b..39eae43a287e7 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -4931,60 +4931,6 @@ operand vRegD_V7() interface(REG_INTER); %} -operand vRegD_V12() -%{ - constraint(ALLOC_IN_RC(v12_reg)); - match(RegD); - op_cost(0); - format %{ %} - interface(REG_INTER); -%} - -operand vRegD_V13() -%{ - constraint(ALLOC_IN_RC(v13_reg)); - match(RegD); - op_cost(0); - format %{ %} - interface(REG_INTER); -%} - -operand vRegD_V14() -%{ - constraint(ALLOC_IN_RC(v14_reg)); - match(RegD); - op_cost(0); - format %{ %} - interface(REG_INTER); -%} - -operand vRegD_V15() -%{ - constraint(ALLOC_IN_RC(v15_reg)); - match(RegD); - op_cost(0); - format %{ %} - interface(REG_INTER); -%} - -operand vRegD_V16() -%{ - constraint(ALLOC_IN_RC(v16_reg)); - match(RegD); - op_cost(0); - format %{ %} - interface(REG_INTER); -%} - -operand vRegD_V17() -%{ - constraint(ALLOC_IN_RC(v17_reg)); - match(RegD); - op_cost(0); - format %{ %} - interface(REG_INTER); -%} - operand pReg() %{ constraint(ALLOC_IN_RC(pr_reg)); @@ -16605,30 +16551,6 @@ instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, ins_pipe(pipe_class_memory); %} -instruct arrays_hashcode(iRegP_R1 ary, iRegI_R2 cnt, iRegI_R0 result, immI basic_type, - vRegD_V0 vtmp0, vRegD_V1 vtmp1, vRegD_V2 vtmp2, vRegD_V3 vtmp3, - vRegD_V4 vtmp4, vRegD_V5 vtmp5, vRegD_V6 vtmp6, vRegD_V7 vtmp7, - vRegD_V12 vtmp8, vRegD_V13 vtmp9, vRegD_V14 vtmp10, - vRegD_V15 vtmp11, vRegD_V16 vtmp12, vRegD_V17 vtmp13, - rFlagsReg cr) -%{ - match(Set result (VectorizedHashCode (Binary ary cnt) (Binary result basic_type))); - effect(TEMP vtmp0, TEMP vtmp1, TEMP vtmp2, TEMP vtmp3, TEMP vtmp4, TEMP vtmp5, TEMP vtmp6, - TEMP vtmp7, TEMP vtmp8, TEMP vtmp9, TEMP vtmp10, TEMP vtmp11, TEMP vtmp12, TEMP vtmp13, - USE_KILL ary, USE_KILL cnt, USE basic_type, KILL cr); - - format %{ "Array HashCode array[] $ary,$cnt,$result,$basic_type -> $result // KILL all" %} - ins_encode %{ - address tpc = __ arrays_hashcode($ary$$Register, $cnt$$Register, $result$$Register, - (BasicType)$basic_type$$constant); - if (tpc == nullptr) { - ciEnv::current()->record_failure("CodeCache is full"); - return; - } - %} - ins_pipe(pipe_class_memory); -%} - instruct count_positives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg cr) %{ match(Set result (CountPositives ary1 len)); diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index a5e0e2665af92..28a0cc2c7d940 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2024, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -287,11 +287,6 @@ class Instruction_aarch64 { f(r->raw_encoding(), lsb + 4, lsb); } - //<0-15>reg: As `rf(FloatRegister)`, but only the lower 16 FloatRegisters are allowed. - void lrf(FloatRegister r, int lsb) { - f(r->raw_encoding(), lsb + 3, lsb); - } - void prf(PRegister r, int lsb) { f(r->raw_encoding(), lsb + 3, lsb); } @@ -770,7 +765,6 @@ class Assembler : public AbstractAssembler { #define f current_insn.f #define sf current_insn.sf #define rf current_insn.rf -#define lrf current_insn.lrf #define srf current_insn.srf #define zrf current_insn.zrf #define prf current_insn.prf @@ -1596,16 +1590,6 @@ class Assembler : public AbstractAssembler { #undef INSN - // Load/store a register, but with a BasicType parameter. Loaded signed integer values are - // extended to 64 bits. - void load(Register Rt, const Address &adr, BasicType bt) { - int op = (is_signed_subword_type(bt) || bt == T_INT) ? 0b10 : 0b01; - ld_st2(Rt, adr, exact_log2(type2aelembytes(bt)), op); - } - void store(Register Rt, const Address &adr, BasicType bt) { - ld_st2(Rt, adr, exact_log2(type2aelembytes(bt)), 0b00); - } - /* SIMD extensions * * We just use FloatRegister in the following. They are exactly the same @@ -2603,7 +2587,6 @@ template INSN(addpv, 0, 0b101111, true); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S, T2D INSN(smullv, 0, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(umullv, 1, 0b110000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S - INSN(smlalv, 0, 0b100000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(umlalv, 1, 0b100000, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(maxv, 0, 0b011001, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S INSN(minv, 0, 0b011011, false); // accepted arrangements: T8B, T16B, T4H, T8H, T2S, T4S @@ -2877,28 +2860,6 @@ template // FMULX - Vector - Scalar INSN(fmulxvs, 1, 0b1001); -#undef INSN - -#define INSN(NAME, op1, op2) \ - void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, int index) { \ - starti; \ - assert(T == T4H || T == T8H || T == T2S || T == T4S, "invalid arrangement"); \ - assert(index >= 0 && \ - ((T == T2S && index <= 1) || (T != T2S && index <= 3) || (T == T8H && index <= 7)), \ - "invalid index"); \ - assert((T != T4H && T != T8H) || Vm->encoding() < 16, "invalid source SIMD&FP register"); \ - f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01111, 28, 24); \ - if (T == T4H || T == T8H) { \ - f(0b01, 23, 22), f(index & 0b11, 21, 20), lrf(Vm, 16), f(index >> 2 & 1, 11); \ - } else { \ - f(0b10, 23, 22), f(index & 1, 21), rf(Vm, 16), f(index >> 1, 11); \ - } \ - f(op2, 15, 12), f(0, 10), rf(Vn, 5), rf(Vd, 0); \ - } - - // MUL - Vector - Scalar - INSN(mulvs, 0, 0b1000); - #undef INSN // Floating-point Reciprocal Estimate @@ -3062,33 +3023,6 @@ template umov(Xd, Vn, T, index); } - protected: - void _xaddwv(bool is_unsigned, FloatRegister Vd, FloatRegister Vn, SIMD_Arrangement Ta, - FloatRegister Vm, SIMD_Arrangement Tb) { - starti; - assert((Tb >> 1) + 1 == (Ta >> 1), "Incompatible arrangement"); - f(0, 31), f((int)Tb & 1, 30), f(is_unsigned ? 1 : 0, 29), f(0b01110, 28, 24); - f((int)(Ta >> 1) - 1, 23, 22), f(1, 21), rf(Vm, 16), f(0b000100, 15, 10), rf(Vn, 5), rf(Vd, 0); - } - - public: -#define INSN(NAME, assertion, is_unsigned) \ - void NAME(FloatRegister Vd, FloatRegister Vn, SIMD_Arrangement Ta, FloatRegister Vm, \ - SIMD_Arrangement Tb) { \ - assert((assertion), "invalid arrangement"); \ - _xaddwv(is_unsigned, Vd, Vn, Ta, Vm, Tb); \ - } - -public: - - INSN(uaddwv, Tb == T8B || Tb == T4H || Tb == T2S, /*is_unsigned*/true) - INSN(uaddwv2, Tb == T16B || Tb == T8H || Tb == T4S, /*is_unsigned*/true) - INSN(saddwv, Tb == T8B || Tb == T4H || Tb == T2S, /*is_unsigned*/false) - INSN(saddwv2, Tb == T16B || Tb == T8H || Tb == T4S, /*is_unsigned*/false) - -#undef INSN - - private: void _pmull(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, FloatRegister Vm, SIMD_Arrangement Tb) { starti; diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index ab2bd7d782c04..b4c12ecd4a849 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -33,7 +33,6 @@ #include "opto/subnode.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/powerOfTwo.hpp" #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ @@ -47,96 +46,6 @@ typedef void (MacroAssembler::* chr_insn)(Register Rt, const Address &adr); -// jdk.internal.util.ArraysSupport.vectorizedHashCode -address C2_MacroAssembler::arrays_hashcode(Register ary, Register cnt, Register result, - BasicType eltype) { - assert_different_registers(ary, cnt, result, rscratch1, rscratch2); - - Register tmp1 = rscratch1, tmp2 = rscratch2; - - Label TAIL, STUB_SWITCH, STUB_SWITCH_OUT, LOOP, BR_BASE, LARGE, DONE; - - // Vectorization factor. Number of array elements loaded to one SIMD&FP registers by the stubs. We - // use 8H load arrangements for chars and shorts and 8B for booleans and bytes. It's possible to - // use 4H for chars and shorts instead, but using 8H gives better performance. - const size_t vf = eltype == T_BOOLEAN || eltype == T_BYTE ? 8 - : eltype == T_CHAR || eltype == T_SHORT ? 8 - : eltype == T_INT ? 4 - : 0; - guarantee(vf, "unsupported eltype"); - - // Unroll factor for the scalar loop below. The value is chosen based on performance analysis. - const size_t unroll_factor = 4; - - switch (eltype) { - case T_BOOLEAN: - BLOCK_COMMENT("arrays_hashcode(unsigned byte) {"); - break; - case T_CHAR: - BLOCK_COMMENT("arrays_hashcode(char) {"); - break; - case T_BYTE: - BLOCK_COMMENT("arrays_hashcode(byte) {"); - break; - case T_SHORT: - BLOCK_COMMENT("arrays_hashcode(short) {"); - break; - case T_INT: - BLOCK_COMMENT("arrays_hashcode(int) {"); - break; - default: - ShouldNotReachHere(); - } - - // large_arrays_hashcode(T_INT) performs worse than the scalar loop below when the Neon loop - // implemented by the stub executes just once. Call the stub only if at least two iterations will - // be executed. - const size_t large_threshold = eltype == T_INT ? vf * 2 : vf; - cmpw(cnt, large_threshold); - br(Assembler::HS, LARGE); - - bind(TAIL); - - // The andr performs cnt % uf where uf = unroll_factor. The subtract shifted by 3 offsets past - // uf - (cnt % uf) pairs of load + madd insns i.e. it only executes cnt % uf load + madd pairs. - // Iteration eats up the remainder, uf elements at a time. - assert(is_power_of_2(unroll_factor), "can't use this value to calculate the jump target PC"); - andr(tmp2, cnt, unroll_factor - 1); - adr(tmp1, BR_BASE); - sub(tmp1, tmp1, tmp2, ext::sxtw, 3); - movw(tmp2, 0x1f); - br(tmp1); - - bind(LOOP); - for (size_t i = 0; i < unroll_factor; ++i) { - load(tmp1, Address(post(ary, type2aelembytes(eltype))), eltype); - maddw(result, result, tmp2, tmp1); - } - bind(BR_BASE); - subsw(cnt, cnt, unroll_factor); - br(Assembler::HS, LOOP); - - b(DONE); - - bind(LARGE); - - RuntimeAddress stub = RuntimeAddress(StubRoutines::aarch64::large_arrays_hashcode(eltype)); - assert(stub.target() != nullptr, "array_hashcode stub has not been generated"); - address tpc = trampoline_call(stub); - if (tpc == nullptr) { - DEBUG_ONLY(reset_labels(TAIL, BR_BASE)); - postcond(pc() == badAddress); - return nullptr; - } - - bind(DONE); - - BLOCK_COMMENT("} // arrays_hashcode"); - - postcond(pc() != badAddress); - return pc(); -} - void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, Register tmpReg, Register tmp2Reg, Register tmp3Reg) { Register oop = objectReg; diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp index 28cc401a1b2c8..43e60ae5a48f8 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.hpp @@ -35,9 +35,6 @@ enum shift_kind kind = Assembler::LSL, unsigned shift = 0); public: - // jdk.internal.util.ArraysSupport.vectorizedHashCode - address arrays_hashcode(Register ary, Register cnt, Register result, BasicType eltype); - // Code used by cmpFastLock and cmpFastUnlock mach instructions in .ad file. void fast_lock(Register object, Register box, Register tmp, Register tmp2, Register tmp3); void fast_unlock(Register object, Register box, Register tmp, Register tmp2); diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 3dbde1ae8242b..eb235f8472c1d 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -53,9 +53,7 @@ #include "runtime/stubRoutines.hpp" #include "utilities/align.hpp" #include "utilities/checkedCast.hpp" -#include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/intpow.hpp" #include "utilities/powerOfTwo.hpp" #ifdef COMPILER2 #include "opto/runtime.hpp" @@ -5313,309 +5311,6 @@ class StubGenerator: public StubCodeGenerator { return entry; } - // result = r0 - return value. Contains initial hashcode value on entry. - // ary = r1 - array address - // cnt = r2 - elements count - // Clobbers: v0-v13, rscratch1, rscratch2 - address generate_large_arrays_hashcode(BasicType eltype) { - const Register result = r0, ary = r1, cnt = r2; - const FloatRegister vdata0 = v3, vdata1 = v2, vdata2 = v1, vdata3 = v0; - const FloatRegister vmul0 = v4, vmul1 = v5, vmul2 = v6, vmul3 = v7; - const FloatRegister vpow = v8; // powers of 31: <31^3, ..., 31^0> - const FloatRegister vpowm = v9; - - assert_different_registers(ary, cnt, result); - assert_different_registers(vdata0, vdata1, vdata2, vdata3, vmul0, vmul1, vmul2, vmul3, vpow, - vpowm); - - Label SMALL_LOOP, LARGE_LOOP_PREHEADER, LARGE_LOOP, TAIL, TAIL_SHORTCUT, BR_BASE; - - unsigned int vf; // vectorization factor - bool multiply_by_halves; - Assembler::SIMD_Arrangement load_arrangement; - switch (eltype) { - case T_BOOLEAN: - case T_BYTE: - load_arrangement = Assembler::T8B; - multiply_by_halves = true; - vf = 8; - break; - case T_CHAR: - case T_SHORT: - load_arrangement = Assembler::T8H; - multiply_by_halves = true; - vf = 8; - break; - case T_INT: - load_arrangement = Assembler::T4S; - multiply_by_halves = false; - vf = 4; - break; - default: - ShouldNotReachHere(); - } - - // Unroll factor - const unsigned uf = 4; - - // Effective vectorization factor - const unsigned evf = vf * uf; - - __ align(CodeEntryAlignment); - - const char *mark_name = ""; - switch (eltype) { - case T_BOOLEAN: - mark_name = "_large_arrays_hashcode_boolean"; - break; - case T_BYTE: - mark_name = "_large_arrays_hashcode_byte"; - break; - case T_CHAR: - mark_name = "_large_arrays_hashcode_char"; - break; - case T_SHORT: - mark_name = "_large_arrays_hashcode_short"; - break; - case T_INT: - mark_name = "_large_arrays_hashcode_int"; - break; - default: - mark_name = "_large_arrays_hashcode_incorrect_type"; - __ should_not_reach_here(); - }; - - StubCodeMark mark(this, "StubRoutines", mark_name); - - address entry = __ pc(); - __ enter(); - - // Put 0-3'th powers of 31 into a single SIMD register together. The register will be used in - // the SMALL and LARGE LOOPS' epilogues. The initialization is hoisted here and the register's - // value shouldn't change throughout both loops. - __ movw(rscratch1, intpow(31U, 3)); - __ mov(vpow, Assembler::S, 0, rscratch1); - __ movw(rscratch1, intpow(31U, 2)); - __ mov(vpow, Assembler::S, 1, rscratch1); - __ movw(rscratch1, intpow(31U, 1)); - __ mov(vpow, Assembler::S, 2, rscratch1); - __ movw(rscratch1, intpow(31U, 0)); - __ mov(vpow, Assembler::S, 3, rscratch1); - - __ mov(vmul0, Assembler::T16B, 0); - __ mov(vmul0, Assembler::S, 3, result); - - __ andr(rscratch2, cnt, (uf - 1) * vf); - __ cbz(rscratch2, LARGE_LOOP_PREHEADER); - - __ movw(rscratch1, intpow(31U, multiply_by_halves ? vf / 2 : vf)); - __ mov(vpowm, Assembler::S, 0, rscratch1); - - // SMALL LOOP - __ bind(SMALL_LOOP); - - __ ld1(vdata0, load_arrangement, Address(__ post(ary, vf * type2aelembytes(eltype)))); - __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 0); - __ subsw(rscratch2, rscratch2, vf); - - if (load_arrangement == Assembler::T8B) { - // Extend 8B to 8H to be able to use vector multiply - // instructions - assert(load_arrangement == Assembler::T8B, "expected to extend 8B to 8H"); - if (is_signed_subword_type(eltype)) { - __ sxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); - } else { - __ uxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); - } - } - - switch (load_arrangement) { - case Assembler::T4S: - __ addv(vmul0, load_arrangement, vmul0, vdata0); - break; - case Assembler::T8B: - case Assembler::T8H: - assert(is_subword_type(eltype), "subword type expected"); - if (is_signed_subword_type(eltype)) { - __ saddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); - } else { - __ uaddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); - } - break; - default: - __ should_not_reach_here(); - } - - // Process the upper half of a vector - if (load_arrangement == Assembler::T8B || load_arrangement == Assembler::T8H) { - __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 0); - if (is_signed_subword_type(eltype)) { - __ saddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); - } else { - __ uaddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); - } - } - - __ br(Assembler::HI, SMALL_LOOP); - - // SMALL LOOP'S EPILOQUE - __ lsr(rscratch2, cnt, exact_log2(evf)); - __ cbnz(rscratch2, LARGE_LOOP_PREHEADER); - - __ mulv(vmul0, Assembler::T4S, vmul0, vpow); - __ addv(vmul0, Assembler::T4S, vmul0); - __ umov(result, vmul0, Assembler::S, 0); - - // TAIL - __ bind(TAIL); - - // The andr performs cnt % vf. The subtract shifted by 3 offsets past vf - 1 - (cnt % vf) pairs - // of load + madd insns i.e. it only executes cnt % vf load + madd pairs. - assert(is_power_of_2(vf), "can't use this value to calculate the jump target PC"); - __ andr(rscratch2, cnt, vf - 1); - __ bind(TAIL_SHORTCUT); - __ adr(rscratch1, BR_BASE); - __ sub(rscratch1, rscratch1, rscratch2, ext::uxtw, 3); - __ movw(rscratch2, 0x1f); - __ br(rscratch1); - - for (size_t i = 0; i < vf - 1; ++i) { - __ load(rscratch1, Address(__ post(ary, type2aelembytes(eltype))), - eltype); - __ maddw(result, result, rscratch2, rscratch1); - } - __ bind(BR_BASE); - - __ leave(); - __ ret(lr); - - // LARGE LOOP - __ bind(LARGE_LOOP_PREHEADER); - - __ lsr(rscratch2, cnt, exact_log2(evf)); - - if (multiply_by_halves) { - // 31^4 - multiplier between lower and upper parts of a register - __ movw(rscratch1, intpow(31U, vf / 2)); - __ mov(vpowm, Assembler::S, 1, rscratch1); - // 31^28 - remainder of the iteraion multiplier, 28 = 32 - 4 - __ movw(rscratch1, intpow(31U, evf - vf / 2)); - __ mov(vpowm, Assembler::S, 0, rscratch1); - } else { - // 31^16 - __ movw(rscratch1, intpow(31U, evf)); - __ mov(vpowm, Assembler::S, 0, rscratch1); - } - - __ mov(vmul3, Assembler::T16B, 0); - __ mov(vmul2, Assembler::T16B, 0); - __ mov(vmul1, Assembler::T16B, 0); - - __ bind(LARGE_LOOP); - - __ mulvs(vmul3, Assembler::T4S, vmul3, vpowm, 0); - __ mulvs(vmul2, Assembler::T4S, vmul2, vpowm, 0); - __ mulvs(vmul1, Assembler::T4S, vmul1, vpowm, 0); - __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 0); - - __ ld1(vdata3, vdata2, vdata1, vdata0, load_arrangement, - Address(__ post(ary, evf * type2aelembytes(eltype)))); - - if (load_arrangement == Assembler::T8B) { - // Extend 8B to 8H to be able to use vector multiply - // instructions - assert(load_arrangement == Assembler::T8B, "expected to extend 8B to 8H"); - if (is_signed_subword_type(eltype)) { - __ sxtl(vdata3, Assembler::T8H, vdata3, load_arrangement); - __ sxtl(vdata2, Assembler::T8H, vdata2, load_arrangement); - __ sxtl(vdata1, Assembler::T8H, vdata1, load_arrangement); - __ sxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); - } else { - __ uxtl(vdata3, Assembler::T8H, vdata3, load_arrangement); - __ uxtl(vdata2, Assembler::T8H, vdata2, load_arrangement); - __ uxtl(vdata1, Assembler::T8H, vdata1, load_arrangement); - __ uxtl(vdata0, Assembler::T8H, vdata0, load_arrangement); - } - } - - switch (load_arrangement) { - case Assembler::T4S: - __ addv(vmul3, load_arrangement, vmul3, vdata3); - __ addv(vmul2, load_arrangement, vmul2, vdata2); - __ addv(vmul1, load_arrangement, vmul1, vdata1); - __ addv(vmul0, load_arrangement, vmul0, vdata0); - break; - case Assembler::T8B: - case Assembler::T8H: - assert(is_subword_type(eltype), "subword type expected"); - if (is_signed_subword_type(eltype)) { - __ saddwv(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T4H); - __ saddwv(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T4H); - __ saddwv(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T4H); - __ saddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); - } else { - __ uaddwv(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T4H); - __ uaddwv(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T4H); - __ uaddwv(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T4H); - __ uaddwv(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T4H); - } - break; - default: - __ should_not_reach_here(); - } - - // Process the upper half of a vector - if (load_arrangement == Assembler::T8B || load_arrangement == Assembler::T8H) { - __ mulvs(vmul3, Assembler::T4S, vmul3, vpowm, 1); - __ mulvs(vmul2, Assembler::T4S, vmul2, vpowm, 1); - __ mulvs(vmul1, Assembler::T4S, vmul1, vpowm, 1); - __ mulvs(vmul0, Assembler::T4S, vmul0, vpowm, 1); - if (is_signed_subword_type(eltype)) { - __ saddwv2(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T8H); - __ saddwv2(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T8H); - __ saddwv2(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T8H); - __ saddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); - } else { - __ uaddwv2(vmul3, vmul3, Assembler::T4S, vdata3, Assembler::T8H); - __ uaddwv2(vmul2, vmul2, Assembler::T4S, vdata2, Assembler::T8H); - __ uaddwv2(vmul1, vmul1, Assembler::T4S, vdata1, Assembler::T8H); - __ uaddwv2(vmul0, vmul0, Assembler::T4S, vdata0, Assembler::T8H); - } - } - - __ subsw(rscratch2, rscratch2, 1); - __ br(Assembler::HI, LARGE_LOOP); - - __ mulv(vmul3, Assembler::T4S, vmul3, vpow); - __ addv(vmul3, Assembler::T4S, vmul3); - __ umov(result, vmul3, Assembler::S, 0); - - __ mov(rscratch2, intpow(31U, vf)); - - __ mulv(vmul2, Assembler::T4S, vmul2, vpow); - __ addv(vmul2, Assembler::T4S, vmul2); - __ umov(rscratch1, vmul2, Assembler::S, 0); - __ maddw(result, result, rscratch2, rscratch1); - - __ mulv(vmul1, Assembler::T4S, vmul1, vpow); - __ addv(vmul1, Assembler::T4S, vmul1); - __ umov(rscratch1, vmul1, Assembler::S, 0); - __ maddw(result, result, rscratch2, rscratch1); - - __ mulv(vmul0, Assembler::T4S, vmul0, vpow); - __ addv(vmul0, Assembler::T4S, vmul0); - __ umov(rscratch1, vmul0, Assembler::S, 0); - __ maddw(result, result, rscratch2, rscratch1); - - __ andr(rscratch2, cnt, vf - 1); - __ cbnz(rscratch2, TAIL_SHORTCUT); - - __ leave(); - __ ret(lr); - - return entry; - } - address generate_dsin_dcos(bool isCos) { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", isCos ? "libmDcos" : "libmDsin"); @@ -8562,13 +8257,6 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::aarch64::_large_array_equals = generate_large_array_equals(); } - // arrays_hascode stub for large arrays. - StubRoutines::aarch64::_large_arrays_hashcode_boolean = generate_large_arrays_hashcode(T_BOOLEAN); - StubRoutines::aarch64::_large_arrays_hashcode_byte = generate_large_arrays_hashcode(T_BYTE); - StubRoutines::aarch64::_large_arrays_hashcode_char = generate_large_arrays_hashcode(T_CHAR); - StubRoutines::aarch64::_large_arrays_hashcode_int = generate_large_arrays_hashcode(T_INT); - StubRoutines::aarch64::_large_arrays_hashcode_short = generate_large_arrays_hashcode(T_SHORT); - // byte_array_inflate stub for large arrays. StubRoutines::aarch64::_large_byte_array_inflate = generate_large_byte_array_inflate(); diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index dee615df5a51f..80875a3b3cdcf 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -48,11 +48,6 @@ address StubRoutines::aarch64::_zero_blocks = nullptr; address StubRoutines::aarch64::_count_positives = nullptr; address StubRoutines::aarch64::_count_positives_long = nullptr; address StubRoutines::aarch64::_large_array_equals = nullptr; -address StubRoutines::aarch64::_large_arrays_hashcode_boolean = nullptr; -address StubRoutines::aarch64::_large_arrays_hashcode_byte = nullptr; -address StubRoutines::aarch64::_large_arrays_hashcode_char = nullptr; -address StubRoutines::aarch64::_large_arrays_hashcode_int = nullptr; -address StubRoutines::aarch64::_large_arrays_hashcode_short = nullptr; address StubRoutines::aarch64::_compare_long_string_LL = nullptr; address StubRoutines::aarch64::_compare_long_string_UU = nullptr; address StubRoutines::aarch64::_compare_long_string_LU = nullptr; diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp index 7d3b72a88363d..e6438908ce4c6 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -62,11 +62,6 @@ class aarch64 { static address _zero_blocks; static address _large_array_equals; - static address _large_arrays_hashcode_boolean; - static address _large_arrays_hashcode_byte; - static address _large_arrays_hashcode_char; - static address _large_arrays_hashcode_int; - static address _large_arrays_hashcode_short; static address _compare_long_string_LL; static address _compare_long_string_LU; static address _compare_long_string_UL; @@ -150,25 +145,6 @@ class aarch64 { return _large_array_equals; } - static address large_arrays_hashcode(BasicType eltype) { - switch (eltype) { - case T_BOOLEAN: - return _large_arrays_hashcode_boolean; - case T_BYTE: - return _large_arrays_hashcode_byte; - case T_CHAR: - return _large_arrays_hashcode_char; - case T_SHORT: - return _large_arrays_hashcode_short; - case T_INT: - return _large_arrays_hashcode_int; - default: - ShouldNotReachHere(); - } - - return nullptr; - } - static address compare_long_string_LL() { return _compare_long_string_LL; } diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 81e39113afaab..d71162ac568ea 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -574,10 +574,6 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(UsePoly1305Intrinsics)) { FLAG_SET_DEFAULT(UsePoly1305Intrinsics, true); } - - if (FLAG_IS_DEFAULT(UseVectorizedHashCodeIntrinsic)) { - FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, true); - } #endif _spin_wait = get_spin_wait_desc(); diff --git a/src/hotspot/share/utilities/intpow.hpp b/src/hotspot/share/utilities/intpow.hpp deleted file mode 100644 index 0b441a55c4c96..0000000000000 --- a/src/hotspot/share/utilities/intpow.hpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2024, Arm 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. - * - */ - -#ifndef SHARE_UTILITIES_INTPOW_HPP -#define SHARE_UTILITIES_INTPOW_HPP - -#include "metaprogramming/enableIf.hpp" -#include -#include - -// Raise v to the power p mod 2**N, where N is the width of the type T. -template ::value && std::is_unsigned::value)> -static constexpr T intpow(T v, unsigned p) { - if (p == 0) { - return 1; - } - - // We use exponentiation by squaring to calculate the required power. - T a = intpow(v, p / 2); - T b = (p % 2) ? v : 1; - - return a * a * b; -} - -#endif // SHARE_UTILITIES_INTPOW_HPP diff --git a/test/hotspot/gtest/aarch64/aarch64-asmtest.py b/test/hotspot/gtest/aarch64/aarch64-asmtest.py index 64f3e787356e0..7e9d557d11cb7 100644 --- a/test/hotspot/gtest/aarch64/aarch64-asmtest.py +++ b/test/hotspot/gtest/aarch64/aarch64-asmtest.py @@ -77,29 +77,11 @@ class FloatRegister(Register): def __str__(self): return self.astr("v") - def generate(self): - self.number = random.randint(0, 31) - return self - def nextReg(self): next = FloatRegister() next.number = (self.number + 1) % 32 return next -class LowFloatRegister(Register): - - def __str__(self): - return self.astr("v") - - def generate(self): - self.number = random.randint(0, 15) - return self - - def nextReg(self): - next = FloatRegister() - next.number = (self.number + 1) % 16 - return next - class GeneralRegister(Register): def __str__(self): @@ -1289,75 +1271,6 @@ def astr(self): def aname(self): return self._name -class VectorScalarNEONInstruction(Instruction): - def __init__(self, args): - self._name, self.insname, self.arrangement = args - - def generate(self): - vectorLength = {"8B" : 8, "16B" : 16, "4H" : 4, "8H" : 8, "2S" : 2, "4S" : 4, "1D" : 1, "2D" : 2} [self.arrangement] - self.elemIndex = random.randrange(0, vectorLength) - self.elemSizeSpecifier = self.arrangement[len(self.arrangement) - 1:] - self._firstSIMDreg = LowFloatRegister().generate() - self.numRegs = 3 - return self - - def cstr(self): - buf = Instruction.cstr(self) + str(self._firstSIMDreg) - buf = '%s, __ T%s' % (buf, self.arrangement) - current = self._firstSIMDreg - for cnt in range(1, self.numRegs - 1): - buf = '%s, %s' % (buf, current.nextReg()) - current = current.nextReg() - buf = '%s, %s, %d' % (buf, current.nextReg(), self.elemIndex) - return '%s);' % (buf) - - def astr(self): - buf = '%s\t%s.%s' % (self.insname, self._firstSIMDreg, self.arrangement) - current = self._firstSIMDreg - for cnt in range(1, self.numRegs - 1): - buf = '%s, %s.%s' % (buf, current.nextReg(), self.arrangement) - current = current.nextReg() - buf = '%s, %s.%s[%d]' % (buf, current.nextReg(), self.elemSizeSpecifier, self.elemIndex) - return buf - - def aname(self): - return self._name - -class WideningNEONInstruction(Instruction): - def __init__(self, args): - self._name, self.insname, self.widerArrangement, self.narrowerArrangement = args - - def generate(self): - self._firstSIMDreg = FloatRegister().generate() - return self - - def cstr(self): - buf = Instruction.cstr(self) + str(self._firstSIMDreg) - current = self._firstSIMDreg - for cnt in range(1, self.numWiderRegs): - buf = '%s, %s' % (buf, current.nextReg()) - current = current.nextReg() - buf = '%s, __ T%s' % (buf, self.widerArrangement) - for cnt in range(0, self.numNarrowerRegs): - buf = '%s, %s' % (buf, current.nextReg()) - current = current.nextReg() - buf = '%s, __ T%s' % (buf, self.narrowerArrangement) - return '%s);' % (buf) - - def astr(self): - buf = '%s\t%s.%s' % (self.insname, self._firstSIMDreg, self.widerArrangement) - current = self._firstSIMDreg - for cnt in range(1, self.numWiderRegs): - buf = '%s, %s.%s' % (buf, current.nextReg(), self.widerArrangement) - current = current.nextReg() - for cnt in range(0, self.numNarrowerRegs): - buf = '%s, %s.%s' % (buf, current.nextReg(), self.narrowerArrangement) - current = current.nextReg() - return buf - - def aname(self): - return self._name - class SHA512SIMDOp(Instruction): def generate(self): @@ -1477,10 +1390,6 @@ class TwoRegNEONOp(CommonNEONInstruction): class ThreeRegNEONOp(TwoRegNEONOp): numRegs = 3 -class AddWideNEONOp(WideningNEONInstruction): - numWiderRegs = 2 - numNarrowerRegs = 1 - class NEONFloatCompareWithZero(TwoRegNEONOp): def __init__(self, args): self._name = 'fcm' @@ -1839,17 +1748,6 @@ def generate(kind, names): ["facgt", "facgt", "2D"], ]) -generate(VectorScalarNEONInstruction, - [["fmlavs", "fmla", "2S"], ["mulvs", "mul", "4S"], - ["fmlavs", "fmla", "2D"], - ["fmlsvs", "fmls", "2S"], ["mulvs", "mul", "4S"], - ["fmlsvs", "fmls", "2D"], - ["fmulxvs", "fmulx", "2S"], ["mulvs", "mul", "4S"], - ["fmulxvs", "fmulx", "2D"], - ["mulvs", "mul", "4H"], ["mulvs", "mul", "8H"], - ["mulvs", "mul", "2S"], ["mulvs", "mul", "4S"], - ]) - neonVectorCompareInstructionPrefix = ['cm', 'fcm'] neonIntegerVectorCompareConditions = ['GT', 'GE', 'EQ', 'HI', 'HS'] neonFloatVectorCompareConditions = ['EQ', 'GT', 'GE'] @@ -2183,15 +2081,6 @@ def generate(kind, names): generate(SVEReductionOp, [["andv", 0], ["orv", 0], ["eorv", 0], ["smaxv", 0], ["sminv", 0], ["fminv", 2], ["fmaxv", 2], ["fadda", 2], ["uaddv", 0]]) -generate(AddWideNEONOp, - [["saddwv", "saddw", "8H", "8B"], ["saddwv2", "saddw2", "8H", "16B"], - ["saddwv", "saddw", "4S", "4H"], ["saddwv2", "saddw2", "4S", "8H"], - ["saddwv", "saddw", "2D", "2S"], ["saddwv2", "saddw2", "2D", "4S"], - ["uaddwv", "uaddw", "8H", "8B"], ["uaddwv2", "uaddw2", "8H", "16B"], - ["uaddwv", "uaddw", "4S", "4H"], ["uaddwv2", "uaddw2", "4S", "8H"], - ["uaddwv", "uaddw", "2D", "2S"], ["uaddwv2", "uaddw2", "2D", "4S"], - ]) - print "\n __ bind(forth);" outfile.write("forth:\n") diff --git a/test/hotspot/gtest/aarch64/asmtest.out.h b/test/hotspot/gtest/aarch64/asmtest.out.h index 9805a05c5c150..b8260aaf932d1 100644 --- a/test/hotspot/gtest/aarch64/asmtest.out.h +++ b/test/hotspot/gtest/aarch64/asmtest.out.h @@ -293,9 +293,9 @@ __ ldrshw(r5, Address(r3, 12)); // ldrsh w5, [x3, 12] __ ldrsw(r27, Address(r24, 17)); // ldrsw x27, [x24, 17] __ ldrd(v13, Address(r29, -35)); // ldr d13, [x29, -35] - __ ldrs(v23, Address(r9, -47)); // ldr s23, [x9, -47] + __ ldrs(v22, Address(r9, -47)); // ldr s22, [x9, -47] __ strd(v11, Address(r0, 9)); // str d11, [x0, 9] - __ strs(v21, Address(r0, -127)); // str s21, [x0, -127] + __ strs(v20, Address(r0, -127)); // str s20, [x0, -127] // pre // LoadStoreOp @@ -314,7 +314,7 @@ __ ldrd(v0, Address(__ pre(r14, -54))); // ldr d0, [x14, -54]! __ ldrs(v3, Address(__ pre(r1, 40))); // ldr s3, [x1, 40]! __ strd(v4, Address(__ pre(r14, -94))); // str d4, [x14, -94]! - __ strs(v18, Address(__ pre(r28, -54))); // str s18, [x28, -54]! + __ strs(v17, Address(__ pre(r28, -54))); // str s17, [x28, -54]! // post // LoadStoreOp @@ -331,8 +331,8 @@ __ ldrshw(r3, Address(__ post(r11, -48))); // ldrsh w3, [x11], -48 __ ldrsw(r25, Address(__ post(r23, 22))); // ldrsw x25, [x23], 22 __ ldrd(v0, Address(__ post(r10, -215))); // ldr d0, [x10], -215 - __ ldrs(v19, Address(__ post(r6, 55))); // ldr s19, [x6], 55 - __ strd(v14, Address(__ post(r21, -234))); // str d14, [x21], -234 + __ ldrs(v17, Address(__ post(r6, 55))); // ldr s17, [x6], 55 + __ strd(v13, Address(__ post(r21, -234))); // str d13, [x21], -234 __ strs(v0, Address(__ post(r22, -70))); // str s0, [x22], -70 // base_plus_reg @@ -349,9 +349,9 @@ __ ldrsh(r21, Address(r30, r30, Address::sxtw(1))); // ldrsh x21, [x30, w30, sxtw #1] __ ldrshw(r11, Address(r10, r28, Address::sxtw(1))); // ldrsh w11, [x10, w28, sxtw #1] __ ldrsw(r28, Address(r19, r10, Address::uxtw(0))); // ldrsw x28, [x19, w10, uxtw #0] - __ ldrd(v30, Address(r29, r14, Address::sxtw(0))); // ldr d30, [x29, w14, sxtw #0] + __ ldrd(v29, Address(r29, r14, Address::sxtw(0))); // ldr d29, [x29, w14, sxtw #0] __ ldrs(v8, Address(r5, r5, Address::sxtw(2))); // ldr s8, [x5, w5, sxtw #2] - __ strd(v25, Address(r8, r13, Address::sxtx(0))); // str d25, [x8, x13, sxtx #0] + __ strd(v24, Address(r8, r13, Address::sxtx(0))); // str d24, [x8, x13, sxtx #0] __ strs(v17, Address(r24, r26, Address::lsl(2))); // str s17, [x24, x26, lsl #2] // base_plus_scaled_offset @@ -370,7 +370,7 @@ __ ldrsw(r10, Address(r7, 6372)); // ldrsw x10, [x7, 6372] __ ldrd(v3, Address(r25, 12392)); // ldr d3, [x25, 12392] __ ldrs(v12, Address(r9, 7840)); // ldr s12, [x9, 7840] - __ strd(v24, Address(r1, 12728)); // str d24, [x1, 12728] + __ strd(v23, Address(r1, 12728)); // str d23, [x1, 12728] __ strs(v3, Address(r20, 6924)); // str s3, [x20, 6924] // pcrel @@ -484,63 +484,63 @@ __ umsubl(r13, r10, r7, r5); // umsubl x13, w10, w7, x5 // ThreeRegFloatOp - __ fabds(v30, v15, v3); // fabd s30, s15, s3 - __ fmuls(v12, v12, v16); // fmul s12, s12, s16 - __ fdivs(v31, v31, v18); // fdiv s31, s31, s18 - __ fadds(v19, v21, v16); // fadd s19, s21, s16 - __ fsubs(v15, v10, v21); // fsub s15, s10, s21 - __ fabdd(v2, v10, v28); // fabd d2, d10, d28 - __ fmuld(v7, v30, v31); // fmul d7, d30, d31 - __ fdivd(v18, v1, v2); // fdiv d18, d1, d2 + __ fabds(v29, v15, v3); // fabd s29, s15, s3 + __ fmuls(v11, v12, v15); // fmul s11, s12, s15 + __ fdivs(v30, v30, v17); // fdiv s30, s30, s17 + __ fadds(v19, v20, v15); // fadd s19, s20, s15 + __ fsubs(v15, v9, v21); // fsub s15, s9, s21 + __ fabdd(v2, v9, v27); // fabd d2, d9, d27 + __ fmuld(v7, v29, v30); // fmul d7, d29, d30 + __ fdivd(v17, v1, v2); // fdiv d17, d1, d2 __ faddd(v6, v10, v3); // fadd d6, d10, d3 - __ fsubd(v25, v11, v7); // fsub d25, d11, d7 + __ fsubd(v24, v11, v7); // fsub d24, d11, d7 // FourRegFloatOp - __ fmadds(v1, v12, v0, v3); // fmadd s1, s12, s0, s3 - __ fmsubs(v19, v29, v6, v23); // fmsub s19, s29, s6, s23 - __ fnmadds(v6, v0, v28, v27); // fnmadd s6, s0, s28, s27 - __ fnmadds(v2, v5, v7, v29); // fnmadd s2, s5, s7, s29 - __ fmaddd(v12, v25, v13, v12); // fmadd d12, d25, d13, d12 - __ fmsubd(v24, v19, v8, v18); // fmsub d24, d19, d8, d18 - __ fnmaddd(v22, v26, v21, v20); // fnmadd d22, d26, d21, d20 - __ fnmaddd(v19, v2, v30, v22); // fnmadd d19, d2, d30, d22 + __ fmadds(v1, v11, v0, v3); // fmadd s1, s11, s0, s3 + __ fmsubs(v17, v28, v6, v22); // fmsub s17, s28, s6, s22 + __ fnmadds(v6, v0, v27, v26); // fnmadd s6, s0, s27, s26 + __ fnmadds(v2, v5, v7, v28); // fnmadd s2, s5, s7, s28 + __ fmaddd(v11, v25, v13, v11); // fmadd d11, d25, d13, d11 + __ fmsubd(v23, v19, v8, v17); // fmsub d23, d19, d8, d17 + __ fnmaddd(v21, v25, v20, v19); // fnmadd d21, d25, d20, d19 + __ fnmaddd(v17, v2, v29, v22); // fnmadd d17, d2, d29, d22 // TwoRegFloatOp - __ fmovs(v8, v22); // fmov s8, s22 - __ fabss(v19, v21); // fabs s19, s21 - __ fnegs(v12, v18); // fneg s12, s18 - __ fsqrts(v21, v6); // fsqrt s21, s6 - __ fcvts(v16, v3); // fcvt d16, s3 - __ fcvtsh(v3, v29); // fcvt h3, s29 - __ fcvths(v3, v28); // fcvt s3, h28 - __ fmovd(v15, v14); // fmov d15, d14 - __ fabsd(v10, v13); // fabs d10, d13 - __ fnegd(v12, v18); // fneg d12, d18 - __ fsqrtd(v10, v26); // fsqrt d10, d26 + __ fmovs(v8, v21); // fmov s8, s21 + __ fabss(v19, v20); // fabs s19, s20 + __ fnegs(v11, v17); // fneg s11, s17 + __ fsqrts(v20, v6); // fsqrt s20, s6 + __ fcvts(v15, v3); // fcvt d15, s3 + __ fcvtsh(v3, v28); // fcvt h3, s28 + __ fcvths(v3, v27); // fcvt s3, h27 + __ fmovd(v14, v14); // fmov d14, d14 + __ fabsd(v10, v12); // fabs d10, d12 + __ fnegd(v11, v17); // fneg d11, d17 + __ fsqrtd(v10, v25); // fsqrt d10, d25 __ fcvtd(v7, v7); // fcvt s7, d7 // FloatConvertOp - __ fcvtzsw(r14, v29); // fcvtzs w14, s29 - __ fcvtzs(r0, v23); // fcvtzs x0, s23 + __ fcvtzsw(r14, v28); // fcvtzs w14, s28 + __ fcvtzs(r0, v22); // fcvtzs x0, s22 __ fcvtzdw(r0, v12); // fcvtzs w0, d12 - __ fcvtzd(r23, v14); // fcvtzs x23, d14 + __ fcvtzd(r23, v13); // fcvtzs x23, d13 __ scvtfws(v13, r7); // scvtf s13, w7 - __ scvtfs(v15, r7); // scvtf s15, x7 - __ scvtfwd(v9, r20); // scvtf d9, w20 - __ scvtfd(v19, r28); // scvtf d19, x28 + __ scvtfs(v14, r7); // scvtf s14, x7 + __ scvtfwd(v8, r20); // scvtf d8, w20 + __ scvtfd(v17, r28); // scvtf d17, x28 __ fcvtassw(r30, v16); // fcvtas w30, s16 __ fcvtasd(r2, v9); // fcvtas x2, d9 - __ fcvtmssw(r16, v21); // fcvtms w16, s21 + __ fcvtmssw(r16, v20); // fcvtms w16, s20 __ fcvtmsd(r29, v4); // fcvtms x29, d4 - __ fmovs(r1, v27); // fmov w1, s27 - __ fmovd(r24, v24); // fmov x24, d24 + __ fmovs(r1, v26); // fmov w1, s26 + __ fmovd(r24, v23); // fmov x24, d23 __ fmovs(v14, r21); // fmov s14, w21 - __ fmovd(v13, r5); // fmov d13, x5 + __ fmovd(v12, r5); // fmov d12, x5 // TwoRegFloatOp - __ fcmps(v12, v25); // fcmp s12, s25 - __ fcmpd(v25, v30); // fcmp d25, d30 - __ fcmps(v28, 0.0); // fcmp s28, #0.0 + __ fcmps(v12, v24); // fcmp s12, s24 + __ fcmpd(v24, v29); // fcmp d24, d29 + __ fcmps(v27, 0.0); // fcmp s27, #0.0 __ fcmpd(v21, 0.0); // fcmp d21, #0.0 // LoadStorePairOp @@ -573,265 +573,250 @@ // LdStNEONOp __ ld1(v0, __ T8B, Address(r11)); // ld1 {v0.8B}, [x11] __ ld1(v16, v17, __ T16B, Address(__ post(r26, 32))); // ld1 {v16.16B, v17.16B}, [x26], 32 - __ ld1(v22, v23, v24, __ T1D, Address(__ post(r26, r17))); // ld1 {v22.1D, v23.1D, v24.1D}, [x26], x17 - __ ld1(v27, v28, v29, v30, __ T8H, Address(__ post(r29, 64))); // ld1 {v27.8H, v28.8H, v29.8H, v30.8H}, [x29], 64 - __ ld1r(v22, __ T8B, Address(r6)); // ld1r {v22.8B}, [x6] - __ ld1r(v14, __ T4S, Address(__ post(r29, 4))); // ld1r {v14.4S}, [x29], 4 - __ ld1r(v22, __ T1D, Address(__ post(r12, r16))); // ld1r {v22.1D}, [x12], x16 + __ ld1(v21, v22, v23, __ T1D, Address(__ post(r26, r17))); // ld1 {v21.1D, v22.1D, v23.1D}, [x26], x17 + __ ld1(v26, v27, v28, v29, __ T8H, Address(__ post(r29, 64))); // ld1 {v26.8H, v27.8H, v28.8H, v29.8H}, [x29], 64 + __ ld1r(v21, __ T8B, Address(r6)); // ld1r {v21.8B}, [x6] + __ ld1r(v13, __ T4S, Address(__ post(r29, 4))); // ld1r {v13.4S}, [x29], 4 + __ ld1r(v21, __ T1D, Address(__ post(r12, r16))); // ld1r {v21.1D}, [x12], x16 __ ld2(v1, v2, __ T2D, Address(r0)); // ld2 {v1.2D, v2.2D}, [x0] - __ ld2(v10, v11, __ T4H, Address(__ post(r21, 16))); // ld2 {v10.4H, v11.4H}, [x21], 16 + __ ld2(v9, v10, __ T4H, Address(__ post(r21, 16))); // ld2 {v9.4H, v10.4H}, [x21], 16 __ ld2r(v7, v8, __ T16B, Address(r25)); // ld2r {v7.16B, v8.16B}, [x25] - __ ld2r(v9, v10, __ T2S, Address(__ post(r9, 8))); // ld2r {v9.2S, v10.2S}, [x9], 8 + __ ld2r(v8, v9, __ T2S, Address(__ post(r9, 8))); // ld2r {v8.2S, v9.2S}, [x9], 8 __ ld2r(v9, v10, __ T2D, Address(__ post(r12, r14))); // ld2r {v9.2D, v10.2D}, [x12], x14 __ ld3(v7, v8, v9, __ T4S, Address(__ post(r4, r17))); // ld3 {v7.4S, v8.4S, v9.4S}, [x4], x17 __ ld3(v23, v24, v25, __ T2S, Address(r17)); // ld3 {v23.2S, v24.2S, v25.2S}, [x17] - __ ld3r(v4, v5, v6, __ T8H, Address(r22)); // ld3r {v4.8H, v5.8H, v6.8H}, [x22] - __ ld3r(v13, v14, v15, __ T4S, Address(__ post(r2, 12))); // ld3r {v13.4S, v14.4S, v15.4S}, [x2], 12 - __ ld3r(v16, v17, v18, __ T1D, Address(__ post(r10, r12))); // ld3r {v16.1D, v17.1D, v18.1D}, [x10], x12 + __ ld3r(v3, v4, v5, __ T8H, Address(r22)); // ld3r {v3.8H, v4.8H, v5.8H}, [x22] + __ ld3r(v12, v13, v14, __ T4S, Address(__ post(r2, 12))); // ld3r {v12.4S, v13.4S, v14.4S}, [x2], 12 + __ ld3r(v15, v16, v17, __ T1D, Address(__ post(r10, r12))); // ld3r {v15.1D, v16.1D, v17.1D}, [x10], x12 __ ld4(v4, v5, v6, v7, __ T8H, Address(__ post(r2, 64))); // ld4 {v4.8H, v5.8H, v6.8H, v7.8H}, [x2], 64 __ ld4(v6, v7, v8, v9, __ T8B, Address(__ post(r20, r11))); // ld4 {v6.8B, v7.8B, v8.8B, v9.8B}, [x20], x11 - __ ld4r(v12, v13, v14, v15, __ T8B, Address(r12)); // ld4r {v12.8B, v13.8B, v14.8B, v15.8B}, [x12] - __ ld4r(v16, v17, v18, v19, __ T4H, Address(__ post(r17, 8))); // ld4r {v16.4H, v17.4H, v18.4H, v19.4H}, [x17], 8 + __ ld4r(v11, v12, v13, v14, __ T8B, Address(r12)); // ld4r {v11.8B, v12.8B, v13.8B, v14.8B}, [x12] + __ ld4r(v15, v16, v17, v18, __ T4H, Address(__ post(r17, 8))); // ld4r {v15.4H, v16.4H, v17.4H, v18.4H}, [x17], 8 __ ld4r(v14, v15, v16, v17, __ T2S, Address(__ post(r25, r16))); // ld4r {v14.2S, v15.2S, v16.2S, v17.2S}, [x25], x16 // NEONReduceInstruction __ addv(v20, __ T8B, v21); // addv b20, v21.8B __ addv(v1, __ T16B, v2); // addv b1, v2.16B - __ addv(v23, __ T4H, v24); // addv h23, v24.4H + __ addv(v22, __ T4H, v23); // addv h22, v23.4H __ addv(v30, __ T8H, v31); // addv h30, v31.8H __ addv(v14, __ T4S, v15); // addv s14, v15.4S __ smaxv(v2, __ T8B, v3); // smaxv b2, v3.8B __ smaxv(v6, __ T16B, v7); // smaxv b6, v7.16B __ smaxv(v3, __ T4H, v4); // smaxv h3, v4.4H - __ smaxv(v8, __ T8H, v9); // smaxv h8, v9.8H - __ smaxv(v25, __ T4S, v26); // smaxv s25, v26.4S + __ smaxv(v7, __ T8H, v8); // smaxv h7, v8.8H + __ smaxv(v24, __ T4S, v25); // smaxv s24, v25.4S __ fmaxv(v0, __ T4S, v1); // fmaxv s0, v1.4S __ sminv(v27, __ T8B, v28); // sminv b27, v28.8B - __ uminv(v30, __ T8B, v31); // uminv b30, v31.8B + __ uminv(v29, __ T8B, v30); // uminv b29, v30.8B __ sminv(v5, __ T16B, v6); // sminv b5, v6.16B __ uminv(v5, __ T16B, v6); // uminv b5, v6.16B - __ sminv(v30, __ T4H, v31); // sminv h30, v31.4H + __ sminv(v29, __ T4H, v30); // sminv h29, v30.4H __ uminv(v11, __ T4H, v12); // uminv h11, v12.4H __ sminv(v25, __ T8H, v26); // sminv h25, v26.8H __ uminv(v0, __ T8H, v1); // uminv h0, v1.8H - __ sminv(v31, __ T4S, v0); // sminv s31, v0.4S + __ sminv(v30, __ T4S, v31); // sminv s30, v31.4S __ uminv(v0, __ T4S, v1); // uminv s0, v1.4S - __ fminv(v19, __ T4S, v20); // fminv s19, v20.4S - __ fmaxp(v29, v30, __ S); // fmaxp s29, v30.2S - __ fmaxp(v26, v27, __ D); // fmaxp d26, v27.2D + __ fminv(v17, __ T4S, v18); // fminv s17, v18.4S + __ fmaxp(v28, v29, __ S); // fmaxp s28, v29.2S + __ fmaxp(v25, v26, __ D); // fmaxp d25, v26.2D __ fminp(v9, v10, __ S); // fminp s9, v10.2S - __ fminp(v26, v27, __ D); // fminp d26, v27.2D + __ fminp(v25, v26, __ D); // fminp d25, v26.2D // NEONFloatCompareWithZero __ fcm(Assembler::GT, v12, __ T2S, v13); // fcmgt v12.2S, v13.2S, #0.0 __ fcm(Assembler::GT, v15, __ T4S, v16); // fcmgt v15.4S, v16.4S, #0.0 __ fcm(Assembler::GT, v11, __ T2D, v12); // fcmgt v11.2D, v12.2D, #0.0 - __ fcm(Assembler::GE, v11, __ T2S, v12); // fcmge v11.2S, v12.2S, #0.0 - __ fcm(Assembler::GE, v18, __ T4S, v19); // fcmge v18.4S, v19.4S, #0.0 - __ fcm(Assembler::GE, v25, __ T2D, v26); // fcmge v25.2D, v26.2D, #0.0 - __ fcm(Assembler::EQ, v22, __ T2S, v23); // fcmeq v22.2S, v23.2S, #0.0 - __ fcm(Assembler::EQ, v24, __ T4S, v25); // fcmeq v24.4S, v25.4S, #0.0 + __ fcm(Assembler::GE, v10, __ T2S, v11); // fcmge v10.2S, v11.2S, #0.0 + __ fcm(Assembler::GE, v17, __ T4S, v18); // fcmge v17.4S, v18.4S, #0.0 + __ fcm(Assembler::GE, v24, __ T2D, v25); // fcmge v24.2D, v25.2D, #0.0 + __ fcm(Assembler::EQ, v21, __ T2S, v22); // fcmeq v21.2S, v22.2S, #0.0 + __ fcm(Assembler::EQ, v23, __ T4S, v24); // fcmeq v23.4S, v24.4S, #0.0 __ fcm(Assembler::EQ, v0, __ T2D, v1); // fcmeq v0.2D, v1.2D, #0.0 - __ fcm(Assembler::LT, v17, __ T2S, v18); // fcmlt v17.2S, v18.2S, #0.0 - __ fcm(Assembler::LT, v11, __ T4S, v12); // fcmlt v11.4S, v12.4S, #0.0 + __ fcm(Assembler::LT, v16, __ T2S, v17); // fcmlt v16.2S, v17.2S, #0.0 + __ fcm(Assembler::LT, v10, __ T4S, v11); // fcmlt v10.4S, v11.4S, #0.0 __ fcm(Assembler::LT, v6, __ T2D, v7); // fcmlt v6.2D, v7.2D, #0.0 - __ fcm(Assembler::LE, v29, __ T2S, v30); // fcmle v29.2S, v30.2S, #0.0 + __ fcm(Assembler::LE, v28, __ T2S, v29); // fcmle v28.2S, v29.2S, #0.0 __ fcm(Assembler::LE, v6, __ T4S, v7); // fcmle v6.4S, v7.4S, #0.0 __ fcm(Assembler::LE, v5, __ T2D, v6); // fcmle v5.2D, v6.2D, #0.0 // TwoRegNEONOp __ absr(v5, __ T8B, v6); // abs v5.8B, v6.8B - __ absr(v21, __ T16B, v22); // abs v21.16B, v22.16B - __ absr(v19, __ T4H, v20); // abs v19.4H, v20.4H - __ absr(v16, __ T8H, v17); // abs v16.8H, v17.8H - __ absr(v18, __ T2S, v19); // abs v18.2S, v19.2S - __ absr(v30, __ T4S, v31); // abs v30.4S, v31.4S - __ absr(v27, __ T2D, v28); // abs v27.2D, v28.2D + __ absr(v20, __ T16B, v21); // abs v20.16B, v21.16B + __ absr(v17, __ T4H, v18); // abs v17.4H, v18.4H + __ absr(v15, __ T8H, v16); // abs v15.8H, v16.8H + __ absr(v17, __ T2S, v18); // abs v17.2S, v18.2S + __ absr(v29, __ T4S, v30); // abs v29.4S, v30.4S + __ absr(v26, __ T2D, v27); // abs v26.2D, v27.2D __ fabs(v28, __ T2S, v29); // fabs v28.2S, v29.2S __ fabs(v1, __ T4S, v2); // fabs v1.4S, v2.4S - __ fabs(v28, __ T2D, v29); // fabs v28.2D, v29.2D - __ fneg(v1, __ T2S, v2); // fneg v1.2S, v2.2S + __ fabs(v27, __ T2D, v28); // fabs v27.2D, v28.2D + __ fneg(v0, __ T2S, v1); // fneg v0.2S, v1.2S __ fneg(v20, __ T4S, v21); // fneg v20.4S, v21.4S - __ fneg(v29, __ T2D, v30); // fneg v29.2D, v30.2D - __ fsqrt(v16, __ T2S, v17); // fsqrt v16.2S, v17.2S - __ fsqrt(v13, __ T4S, v14); // fsqrt v13.4S, v14.4S + __ fneg(v28, __ T2D, v29); // fneg v28.2D, v29.2D + __ fsqrt(v15, __ T2S, v16); // fsqrt v15.2S, v16.2S + __ fsqrt(v12, __ T4S, v13); // fsqrt v12.4S, v13.4S __ fsqrt(v10, __ T2D, v11); // fsqrt v10.2D, v11.2D - __ notr(v29, __ T8B, v30); // not v29.8B, v30.8B - __ notr(v29, __ T16B, v30); // not v29.16B, v30.16B + __ notr(v28, __ T8B, v29); // not v28.8B, v29.8B + __ notr(v28, __ T16B, v29); // not v28.16B, v29.16B // ThreeRegNEONOp __ andr(v19, __ T8B, v20, v21); // and v19.8B, v20.8B, v21.8B __ andr(v22, __ T16B, v23, v24); // and v22.16B, v23.16B, v24.16B __ orr(v10, __ T8B, v11, v12); // orr v10.8B, v11.8B, v12.8B __ orr(v4, __ T16B, v5, v6); // orr v4.16B, v5.16B, v6.16B - __ eor(v31, __ T8B, v0, v1); // eor v31.8B, v0.8B, v1.8B - __ eor(v21, __ T16B, v22, v23); // eor v21.16B, v22.16B, v23.16B + __ eor(v30, __ T8B, v31, v0); // eor v30.8B, v31.8B, v0.8B + __ eor(v20, __ T16B, v21, v22); // eor v20.16B, v21.16B, v22.16B __ addv(v8, __ T8B, v9, v10); // add v8.8B, v9.8B, v10.8B - __ addv(v31, __ T16B, v0, v1); // add v31.16B, v0.16B, v1.16B - __ addv(v19, __ T4H, v20, v21); // add v19.4H, v20.4H, v21.4H + __ addv(v30, __ T16B, v31, v0); // add v30.16B, v31.16B, v0.16B + __ addv(v17, __ T4H, v18, v19); // add v17.4H, v18.4H, v19.4H __ addv(v10, __ T8H, v11, v12); // add v10.8H, v11.8H, v12.8H - __ addv(v28, __ T2S, v29, v30); // add v28.2S, v29.2S, v30.2S + __ addv(v27, __ T2S, v28, v29); // add v27.2S, v28.2S, v29.2S __ addv(v2, __ T4S, v3, v4); // add v2.4S, v3.4S, v4.4S - __ addv(v25, __ T2D, v26, v27); // add v25.2D, v26.2D, v27.2D - __ fadd(v5, __ T2S, v6, v7); // fadd v5.2S, v6.2S, v7.2S + __ addv(v24, __ T2D, v25, v26); // add v24.2D, v25.2D, v26.2D + __ fadd(v4, __ T2S, v5, v6); // fadd v4.2S, v5.2S, v6.2S __ fadd(v3, __ T4S, v4, v5); // fadd v3.4S, v4.4S, v5.4S __ fadd(v8, __ T2D, v9, v10); // fadd v8.2D, v9.2D, v10.2D __ subv(v22, __ T8B, v23, v24); // sub v22.8B, v23.8B, v24.8B - __ subv(v19, __ T16B, v20, v21); // sub v19.16B, v20.16B, v21.16B + __ subv(v17, __ T16B, v18, v19); // sub v17.16B, v18.16B, v19.16B __ subv(v13, __ T4H, v14, v15); // sub v13.4H, v14.4H, v15.4H - __ subv(v5, __ T8H, v6, v7); // sub v5.8H, v6.8H, v7.8H - __ subv(v29, __ T2S, v30, v31); // sub v29.2S, v30.2S, v31.2S - __ subv(v24, __ T4S, v25, v26); // sub v24.4S, v25.4S, v26.4S + __ subv(v4, __ T8H, v5, v6); // sub v4.8H, v5.8H, v6.8H + __ subv(v28, __ T2S, v29, v30); // sub v28.2S, v29.2S, v30.2S + __ subv(v23, __ T4S, v24, v25); // sub v23.4S, v24.4S, v25.4S __ subv(v21, __ T2D, v22, v23); // sub v21.2D, v22.2D, v23.2D - __ fsub(v26, __ T2S, v27, v28); // fsub v26.2S, v27.2S, v28.2S + __ fsub(v25, __ T2S, v26, v27); // fsub v25.2S, v26.2S, v27.2S __ fsub(v24, __ T4S, v25, v26); // fsub v24.4S, v25.4S, v26.4S __ fsub(v3, __ T2D, v4, v5); // fsub v3.2D, v4.2D, v5.2D - __ mulv(v24, __ T8B, v25, v26); // mul v24.8B, v25.8B, v26.8B + __ mulv(v23, __ T8B, v24, v25); // mul v23.8B, v24.8B, v25.8B __ mulv(v26, __ T16B, v27, v28); // mul v26.16B, v27.16B, v28.16B __ mulv(v23, __ T4H, v24, v25); // mul v23.4H, v24.4H, v25.4H - __ mulv(v15, __ T8H, v16, v17); // mul v15.8H, v16.8H, v17.8H + __ mulv(v14, __ T8H, v15, v16); // mul v14.8H, v15.8H, v16.8H __ mulv(v21, __ T2S, v22, v23); // mul v21.2S, v22.2S, v23.2S __ mulv(v3, __ T4S, v4, v5); // mul v3.4S, v4.4S, v5.4S - __ fabd(v24, __ T2S, v25, v26); // fabd v24.2S, v25.2S, v26.2S + __ fabd(v23, __ T2S, v24, v25); // fabd v23.2S, v24.2S, v25.2S __ fabd(v8, __ T4S, v9, v10); // fabd v8.4S, v9.4S, v10.4S - __ fabd(v25, __ T2D, v26, v27); // fabd v25.2D, v26.2D, v27.2D - __ faddp(v20, __ T2S, v21, v22); // faddp v20.2S, v21.2S, v22.2S - __ faddp(v16, __ T4S, v17, v18); // faddp v16.4S, v17.4S, v18.4S - __ faddp(v17, __ T2D, v18, v19); // faddp v17.2D, v18.2D, v19.2D + __ fabd(v24, __ T2D, v25, v26); // fabd v24.2D, v25.2D, v26.2D + __ faddp(v19, __ T2S, v20, v21); // faddp v19.2S, v20.2S, v21.2S + __ faddp(v15, __ T4S, v16, v17); // faddp v15.4S, v16.4S, v17.4S + __ faddp(v16, __ T2D, v17, v18); // faddp v16.2D, v17.2D, v18.2D __ fmul(v2, __ T2S, v3, v4); // fmul v2.2S, v3.2S, v4.2S __ fmul(v1, __ T4S, v2, v3); // fmul v1.4S, v2.4S, v3.4S __ fmul(v0, __ T2D, v1, v2); // fmul v0.2D, v1.2D, v2.2D __ mlav(v24, __ T4H, v25, v26); // mla v24.4H, v25.4H, v26.4H __ mlav(v4, __ T8H, v5, v6); // mla v4.8H, v5.8H, v6.8H __ mlav(v3, __ T2S, v4, v5); // mla v3.2S, v4.2S, v5.2S - __ mlav(v12, __ T4S, v13, v14); // mla v12.4S, v13.4S, v14.4S - __ fmla(v31, __ T2S, v0, v1); // fmla v31.2S, v0.2S, v1.2S - __ fmla(v28, __ T4S, v29, v30); // fmla v28.4S, v29.4S, v30.4S - __ fmla(v10, __ T2D, v11, v12); // fmla v10.2D, v11.2D, v12.2D - __ mlsv(v26, __ T4H, v27, v28); // mls v26.4H, v27.4H, v28.4H + __ mlav(v11, __ T4S, v12, v13); // mla v11.4S, v12.4S, v13.4S + __ fmla(v30, __ T2S, v31, v0); // fmla v30.2S, v31.2S, v0.2S + __ fmla(v27, __ T4S, v28, v29); // fmla v27.4S, v28.4S, v29.4S + __ fmla(v9, __ T2D, v10, v11); // fmla v9.2D, v10.2D, v11.2D + __ mlsv(v25, __ T4H, v26, v27); // mls v25.4H, v26.4H, v27.4H __ mlsv(v2, __ T8H, v3, v4); // mls v2.8H, v3.8H, v4.8H __ mlsv(v12, __ T2S, v13, v14); // mls v12.2S, v13.2S, v14.2S - __ mlsv(v18, __ T4S, v19, v20); // mls v18.4S, v19.4S, v20.4S - __ fmls(v31, __ T2S, v0, v1); // fmls v31.2S, v0.2S, v1.2S + __ mlsv(v17, __ T4S, v18, v19); // mls v17.4S, v18.4S, v19.4S + __ fmls(v30, __ T2S, v31, v0); // fmls v30.2S, v31.2S, v0.2S __ fmls(v1, __ T4S, v2, v3); // fmls v1.4S, v2.4S, v3.4S - __ fmls(v13, __ T2D, v14, v15); // fmls v13.2D, v14.2D, v15.2D - __ fdiv(v29, __ T2S, v30, v31); // fdiv v29.2S, v30.2S, v31.2S + __ fmls(v12, __ T2D, v13, v14); // fmls v12.2D, v13.2D, v14.2D + __ fdiv(v28, __ T2S, v29, v30); // fdiv v28.2S, v29.2S, v30.2S __ fdiv(v0, __ T4S, v1, v2); // fdiv v0.4S, v1.4S, v2.4S - __ fdiv(v19, __ T2D, v20, v21); // fdiv v19.2D, v20.2D, v21.2D + __ fdiv(v17, __ T2D, v18, v19); // fdiv v17.2D, v18.2D, v19.2D __ maxv(v12, __ T8B, v13, v14); // smax v12.8B, v13.8B, v14.8B __ maxv(v17, __ T16B, v18, v19); // smax v17.16B, v18.16B, v19.16B - __ maxv(v22, __ T4H, v23, v24); // smax v22.4H, v23.4H, v24.4H - __ maxv(v13, __ T8H, v14, v15); // smax v13.8H, v14.8H, v15.8H - __ maxv(v28, __ T2S, v29, v30); // smax v28.2S, v29.2S, v30.2S - __ maxv(v30, __ T4S, v31, v0); // smax v30.4S, v31.4S, v0.4S - __ smaxp(v31, __ T8B, v0, v1); // smaxp v31.8B, v0.8B, v1.8B + __ maxv(v21, __ T4H, v22, v23); // smax v21.4H, v22.4H, v23.4H + __ maxv(v12, __ T8H, v13, v14); // smax v12.8H, v13.8H, v14.8H + __ maxv(v27, __ T2S, v28, v29); // smax v27.2S, v28.2S, v29.2S + __ maxv(v29, __ T4S, v30, v31); // smax v29.4S, v30.4S, v31.4S + __ smaxp(v30, __ T8B, v31, v0); // smaxp v30.8B, v31.8B, v0.8B __ smaxp(v1, __ T16B, v2, v3); // smaxp v1.16B, v2.16B, v3.16B - __ smaxp(v26, __ T4H, v27, v28); // smaxp v26.4H, v27.4H, v28.4H - __ smaxp(v28, __ T8H, v29, v30); // smaxp v28.8H, v29.8H, v30.8H + __ smaxp(v25, __ T4H, v26, v27); // smaxp v25.4H, v26.4H, v27.4H + __ smaxp(v27, __ T8H, v28, v29); // smaxp v27.8H, v28.8H, v29.8H __ smaxp(v4, __ T2S, v5, v6); // smaxp v4.2S, v5.2S, v6.2S - __ smaxp(v30, __ T4S, v31, v0); // smaxp v30.4S, v31.4S, v0.4S - __ fmax(v4, __ T2S, v5, v6); // fmax v4.2S, v5.2S, v6.2S + __ smaxp(v29, __ T4S, v30, v31); // smaxp v29.4S, v30.4S, v31.4S + __ fmax(v3, __ T2S, v4, v5); // fmax v3.2S, v4.2S, v5.2S __ fmax(v6, __ T4S, v7, v8); // fmax v6.4S, v7.4S, v8.4S - __ fmax(v30, __ T2D, v31, v0); // fmax v30.2D, v31.2D, v0.2D - __ minv(v26, __ T8B, v27, v28); // smin v26.8B, v27.8B, v28.8B - __ minv(v18, __ T16B, v19, v20); // smin v18.16B, v19.16B, v20.16B - __ minv(v9, __ T4H, v10, v11); // smin v9.4H, v10.4H, v11.4H - __ minv(v8, __ T8H, v9, v10); // smin v8.8H, v9.8H, v10.8H + __ fmax(v29, __ T2D, v30, v31); // fmax v29.2D, v30.2D, v31.2D + __ minv(v25, __ T8B, v26, v27); // smin v25.8B, v26.8B, v27.8B + __ minv(v17, __ T16B, v18, v19); // smin v17.16B, v18.16B, v19.16B + __ minv(v8, __ T4H, v9, v10); // smin v8.4H, v9.4H, v10.4H + __ minv(v7, __ T8H, v8, v9); // smin v7.8H, v8.8H, v9.8H __ minv(v12, __ T2S, v13, v14); // smin v12.2S, v13.2S, v14.2S __ minv(v0, __ T4S, v1, v2); // smin v0.4S, v1.4S, v2.4S - __ sminp(v20, __ T8B, v21, v22); // sminp v20.8B, v21.8B, v22.8B + __ sminp(v19, __ T8B, v20, v21); // sminp v19.8B, v20.8B, v21.8B __ sminp(v1, __ T16B, v2, v3); // sminp v1.16B, v2.16B, v3.16B - __ sminp(v24, __ T4H, v25, v26); // sminp v24.4H, v25.4H, v26.4H + __ sminp(v23, __ T4H, v24, v25); // sminp v23.4H, v24.4H, v25.4H __ sminp(v2, __ T8H, v3, v4); // sminp v2.8H, v3.8H, v4.8H __ sminp(v0, __ T2S, v1, v2); // sminp v0.2S, v1.2S, v2.2S - __ sminp(v9, __ T4S, v10, v11); // sminp v9.4S, v10.4S, v11.4S - __ fmin(v24, __ T2S, v25, v26); // fmin v24.2S, v25.2S, v26.2S - __ fmin(v26, __ T4S, v27, v28); // fmin v26.4S, v27.4S, v28.4S - __ fmin(v16, __ T2D, v17, v18); // fmin v16.2D, v17.2D, v18.2D - __ facgt(v30, __ T2S, v31, v0); // facgt v30.2S, v31.2S, v0.2S + __ sminp(v8, __ T4S, v9, v10); // sminp v8.4S, v9.4S, v10.4S + __ fmin(v23, __ T2S, v24, v25); // fmin v23.2S, v24.2S, v25.2S + __ fmin(v25, __ T4S, v26, v27); // fmin v25.4S, v26.4S, v27.4S + __ fmin(v15, __ T2D, v16, v17); // fmin v15.2D, v16.2D, v17.2D + __ facgt(v29, __ T2S, v30, v31); // facgt v29.2S, v30.2S, v31.2S __ facgt(v3, __ T4S, v4, v5); // facgt v3.4S, v4.4S, v5.4S __ facgt(v10, __ T2D, v11, v12); // facgt v10.2D, v11.2D, v12.2D -// VectorScalarNEONInstruction - __ fmlavs(v5, __ T2S, v6, v7, 1); // fmla v5.2S, v6.2S, v7.S[1] - __ mulvs(v9, __ T4S, v10, v11, 0); // mul v9.4S, v10.4S, v11.S[0] - __ fmlavs(v5, __ T2D, v6, v7, 0); // fmla v5.2D, v6.2D, v7.D[0] - __ fmlsvs(v5, __ T2S, v6, v7, 0); // fmls v5.2S, v6.2S, v7.S[0] - __ mulvs(v8, __ T4S, v9, v10, 1); // mul v8.4S, v9.4S, v10.S[1] - __ fmlsvs(v5, __ T2D, v6, v7, 0); // fmls v5.2D, v6.2D, v7.D[0] - __ fmulxvs(v6, __ T2S, v7, v8, 0); // fmulx v6.2S, v7.2S, v8.S[0] - __ mulvs(v6, __ T4S, v7, v8, 1); // mul v6.4S, v7.4S, v8.S[1] - __ fmulxvs(v3, __ T2D, v4, v5, 0); // fmulx v3.2D, v4.2D, v5.D[0] - __ mulvs(v13, __ T4H, v14, v15, 2); // mul v13.4H, v14.4H, v15.H[2] - __ mulvs(v2, __ T8H, v3, v4, 4); // mul v2.8H, v3.8H, v4.H[4] - __ mulvs(v2, __ T2S, v3, v4, 0); // mul v2.2S, v3.2S, v4.S[0] - __ mulvs(v9, __ T4S, v10, v11, 1); // mul v9.4S, v10.4S, v11.S[1] - // NEONVectorCompare - __ cm(Assembler::GT, v21, __ T8B, v22, v23); // cmgt v21.8B, v22.8B, v23.8B - __ cm(Assembler::GT, v16, __ T16B, v17, v18); // cmgt v16.16B, v17.16B, v18.16B - __ cm(Assembler::GT, v18, __ T4H, v19, v20); // cmgt v18.4H, v19.4H, v20.4H - __ cm(Assembler::GT, v11, __ T8H, v12, v13); // cmgt v11.8H, v12.8H, v13.8H - __ cm(Assembler::GT, v21, __ T2S, v22, v23); // cmgt v21.2S, v22.2S, v23.2S - __ cm(Assembler::GT, v23, __ T4S, v24, v25); // cmgt v23.4S, v24.4S, v25.4S - __ cm(Assembler::GT, v12, __ T2D, v13, v14); // cmgt v12.2D, v13.2D, v14.2D - __ cm(Assembler::GE, v26, __ T8B, v27, v28); // cmge v26.8B, v27.8B, v28.8B - __ cm(Assembler::GE, v23, __ T16B, v24, v25); // cmge v23.16B, v24.16B, v25.16B - __ cm(Assembler::GE, v28, __ T4H, v29, v30); // cmge v28.4H, v29.4H, v30.4H - __ cm(Assembler::GE, v14, __ T8H, v15, v16); // cmge v14.8H, v15.8H, v16.8H - __ cm(Assembler::GE, v11, __ T2S, v12, v13); // cmge v11.2S, v12.2S, v13.2S - __ cm(Assembler::GE, v24, __ T4S, v25, v26); // cmge v24.4S, v25.4S, v26.4S - __ cm(Assembler::GE, v1, __ T2D, v2, v3); // cmge v1.2D, v2.2D, v3.2D - __ cm(Assembler::EQ, v12, __ T8B, v13, v14); // cmeq v12.8B, v13.8B, v14.8B - __ cm(Assembler::EQ, v31, __ T16B, v0, v1); // cmeq v31.16B, v0.16B, v1.16B - __ cm(Assembler::EQ, v10, __ T4H, v11, v12); // cmeq v10.4H, v11.4H, v12.4H - __ cm(Assembler::EQ, v16, __ T8H, v17, v18); // cmeq v16.8H, v17.8H, v18.8H - __ cm(Assembler::EQ, v7, __ T2S, v8, v9); // cmeq v7.2S, v8.2S, v9.2S - __ cm(Assembler::EQ, v2, __ T4S, v3, v4); // cmeq v2.4S, v3.4S, v4.4S - __ cm(Assembler::EQ, v3, __ T2D, v4, v5); // cmeq v3.2D, v4.2D, v5.2D - __ cm(Assembler::HI, v13, __ T8B, v14, v15); // cmhi v13.8B, v14.8B, v15.8B - __ cm(Assembler::HI, v19, __ T16B, v20, v21); // cmhi v19.16B, v20.16B, v21.16B - __ cm(Assembler::HI, v17, __ T4H, v18, v19); // cmhi v17.4H, v18.4H, v19.4H - __ cm(Assembler::HI, v16, __ T8H, v17, v18); // cmhi v16.8H, v17.8H, v18.8H - __ cm(Assembler::HI, v3, __ T2S, v4, v5); // cmhi v3.2S, v4.2S, v5.2S - __ cm(Assembler::HI, v1, __ T4S, v2, v3); // cmhi v1.4S, v2.4S, v3.4S - __ cm(Assembler::HI, v11, __ T2D, v12, v13); // cmhi v11.2D, v12.2D, v13.2D - __ cm(Assembler::HS, v30, __ T8B, v31, v0); // cmhs v30.8B, v31.8B, v0.8B - __ cm(Assembler::HS, v5, __ T16B, v6, v7); // cmhs v5.16B, v6.16B, v7.16B - __ cm(Assembler::HS, v8, __ T4H, v9, v10); // cmhs v8.4H, v9.4H, v10.4H - __ cm(Assembler::HS, v15, __ T8H, v16, v17); // cmhs v15.8H, v16.8H, v17.8H - __ cm(Assembler::HS, v29, __ T2S, v30, v31); // cmhs v29.2S, v30.2S, v31.2S - __ cm(Assembler::HS, v30, __ T4S, v31, v0); // cmhs v30.4S, v31.4S, v0.4S - __ cm(Assembler::HS, v0, __ T2D, v1, v2); // cmhs v0.2D, v1.2D, v2.2D - __ fcm(Assembler::EQ, v20, __ T2S, v21, v22); // fcmeq v20.2S, v21.2S, v22.2S - __ fcm(Assembler::EQ, v7, __ T4S, v8, v9); // fcmeq v7.4S, v8.4S, v9.4S - __ fcm(Assembler::EQ, v20, __ T2D, v21, v22); // fcmeq v20.2D, v21.2D, v22.2D - __ fcm(Assembler::GT, v23, __ T2S, v24, v25); // fcmgt v23.2S, v24.2S, v25.2S - __ fcm(Assembler::GT, v28, __ T4S, v29, v30); // fcmgt v28.4S, v29.4S, v30.4S - __ fcm(Assembler::GT, v21, __ T2D, v22, v23); // fcmgt v21.2D, v22.2D, v23.2D - __ fcm(Assembler::GE, v27, __ T2S, v28, v29); // fcmge v27.2S, v28.2S, v29.2S - __ fcm(Assembler::GE, v25, __ T4S, v26, v27); // fcmge v25.4S, v26.4S, v27.4S - __ fcm(Assembler::GE, v5, __ T2D, v6, v7); // fcmge v5.2D, v6.2D, v7.2D + __ cm(Assembler::GT, v22, __ T8B, v23, v24); // cmgt v22.8B, v23.8B, v24.8B + __ cm(Assembler::GT, v10, __ T16B, v11, v12); // cmgt v10.16B, v11.16B, v12.16B + __ cm(Assembler::GT, v4, __ T4H, v5, v6); // cmgt v4.4H, v5.4H, v6.4H + __ cm(Assembler::GT, v17, __ T8H, v18, v19); // cmgt v17.8H, v18.8H, v19.8H + __ cm(Assembler::GT, v1, __ T2S, v2, v3); // cmgt v1.2S, v2.2S, v3.2S + __ cm(Assembler::GT, v11, __ T4S, v12, v13); // cmgt v11.4S, v12.4S, v13.4S + __ cm(Assembler::GT, v7, __ T2D, v8, v9); // cmgt v7.2D, v8.2D, v9.2D + __ cm(Assembler::GE, v10, __ T8B, v11, v12); // cmge v10.8B, v11.8B, v12.8B + __ cm(Assembler::GE, v15, __ T16B, v16, v17); // cmge v15.16B, v16.16B, v17.16B + __ cm(Assembler::GE, v16, __ T4H, v17, v18); // cmge v16.4H, v17.4H, v18.4H + __ cm(Assembler::GE, v2, __ T8H, v3, v4); // cmge v2.8H, v3.8H, v4.8H + __ cm(Assembler::GE, v9, __ T2S, v10, v11); // cmge v9.2S, v10.2S, v11.2S + __ cm(Assembler::GE, v11, __ T4S, v12, v13); // cmge v11.4S, v12.4S, v13.4S + __ cm(Assembler::GE, v12, __ T2D, v13, v14); // cmge v12.2D, v13.2D, v14.2D + __ cm(Assembler::EQ, v14, __ T8B, v15, v16); // cmeq v14.8B, v15.8B, v16.8B + __ cm(Assembler::EQ, v13, __ T16B, v14, v15); // cmeq v13.16B, v14.16B, v15.16B + __ cm(Assembler::EQ, v2, __ T4H, v3, v4); // cmeq v2.4H, v3.4H, v4.4H + __ cm(Assembler::EQ, v6, __ T8H, v7, v8); // cmeq v6.8H, v7.8H, v8.8H + __ cm(Assembler::EQ, v19, __ T2S, v20, v21); // cmeq v19.2S, v20.2S, v21.2S + __ cm(Assembler::EQ, v25, __ T4S, v26, v27); // cmeq v25.4S, v26.4S, v27.4S + __ cm(Assembler::EQ, v15, __ T2D, v16, v17); // cmeq v15.2D, v16.2D, v17.2D + __ cm(Assembler::HI, v4, __ T8B, v5, v6); // cmhi v4.8B, v5.8B, v6.8B + __ cm(Assembler::HI, v2, __ T16B, v3, v4); // cmhi v2.16B, v3.16B, v4.16B + __ cm(Assembler::HI, v4, __ T4H, v5, v6); // cmhi v4.4H, v5.4H, v6.4H + __ cm(Assembler::HI, v11, __ T8H, v12, v13); // cmhi v11.8H, v12.8H, v13.8H + __ cm(Assembler::HI, v17, __ T2S, v18, v19); // cmhi v17.2S, v18.2S, v19.2S + __ cm(Assembler::HI, v20, __ T4S, v21, v22); // cmhi v20.4S, v21.4S, v22.4S + __ cm(Assembler::HI, v16, __ T2D, v17, v18); // cmhi v16.2D, v17.2D, v18.2D + __ cm(Assembler::HS, v17, __ T8B, v18, v19); // cmhs v17.8B, v18.8B, v19.8B + __ cm(Assembler::HS, v10, __ T16B, v11, v12); // cmhs v10.16B, v11.16B, v12.16B + __ cm(Assembler::HS, v20, __ T4H, v21, v22); // cmhs v20.4H, v21.4H, v22.4H + __ cm(Assembler::HS, v22, __ T8H, v23, v24); // cmhs v22.8H, v23.8H, v24.8H + __ cm(Assembler::HS, v12, __ T2S, v13, v14); // cmhs v12.2S, v13.2S, v14.2S + __ cm(Assembler::HS, v25, __ T4S, v26, v27); // cmhs v25.4S, v26.4S, v27.4S + __ cm(Assembler::HS, v23, __ T2D, v24, v25); // cmhs v23.2D, v24.2D, v25.2D + __ fcm(Assembler::EQ, v28, __ T2S, v29, v30); // fcmeq v28.2S, v29.2S, v30.2S + __ fcm(Assembler::EQ, v14, __ T4S, v15, v16); // fcmeq v14.4S, v15.4S, v16.4S + __ fcm(Assembler::EQ, v10, __ T2D, v11, v12); // fcmeq v10.2D, v11.2D, v12.2D + __ fcm(Assembler::GT, v24, __ T2S, v25, v26); // fcmgt v24.2S, v25.2S, v26.2S + __ fcm(Assembler::GT, v1, __ T4S, v2, v3); // fcmgt v1.4S, v2.4S, v3.4S + __ fcm(Assembler::GT, v11, __ T2D, v12, v13); // fcmgt v11.2D, v12.2D, v13.2D + __ fcm(Assembler::GE, v30, __ T2S, v31, v0); // fcmge v30.2S, v31.2S, v0.2S + __ fcm(Assembler::GE, v10, __ T4S, v11, v12); // fcmge v10.4S, v11.4S, v12.4S + __ fcm(Assembler::GE, v15, __ T2D, v16, v17); // fcmge v15.2D, v16.2D, v17.2D // SVEComparisonWithZero - __ sve_fcm(Assembler::EQ, p0, __ D, p7, z23, 0.0); // fcmeq p0.d, p7/z, z23.d, #0.0 - __ sve_fcm(Assembler::GT, p2, __ S, p7, z12, 0.0); // fcmgt p2.s, p7/z, z12.s, #0.0 - __ sve_fcm(Assembler::GE, p7, __ D, p7, z29, 0.0); // fcmge p7.d, p7/z, z29.d, #0.0 - __ sve_fcm(Assembler::LT, p9, __ S, p3, z31, 0.0); // fcmlt p9.s, p3/z, z31.s, #0.0 - __ sve_fcm(Assembler::LE, p9, __ D, p6, z31, 0.0); // fcmle p9.d, p6/z, z31.d, #0.0 - __ sve_fcm(Assembler::NE, p10, __ S, p2, z16, 0.0); // fcmne p10.s, p2/z, z16.s, #0.0 + __ sve_fcm(Assembler::EQ, p3, __ S, p3, z2, 0.0); // fcmeq p3.s, p3/z, z2.s, #0.0 + __ sve_fcm(Assembler::GT, p9, __ D, p0, z16, 0.0); // fcmgt p9.d, p0/z, z16.d, #0.0 + __ sve_fcm(Assembler::GE, p0, __ D, p1, z11, 0.0); // fcmge p0.d, p1/z, z11.d, #0.0 + __ sve_fcm(Assembler::LT, p4, __ D, p7, z14, 0.0); // fcmlt p4.d, p7/z, z14.d, #0.0 + __ sve_fcm(Assembler::LE, p0, __ S, p5, z20, 0.0); // fcmle p0.s, p5/z, z20.s, #0.0 + __ sve_fcm(Assembler::NE, p11, __ D, p6, z27, 0.0); // fcmne p11.d, p6/z, z27.d, #0.0 // SVEComparisonWithImm - __ sve_cmp(Assembler::EQ, p4, __ D, p4, z6, 11); // cmpeq p4.d, p4/z, z6.d, #11 - __ sve_cmp(Assembler::GT, p14, __ B, p2, z30, 4); // cmpgt p14.b, p2/z, z30.b, #4 - __ sve_cmp(Assembler::GE, p5, __ D, p4, z4, 1); // cmpge p5.d, p4/z, z4.d, #1 - __ sve_cmp(Assembler::LT, p11, __ D, p3, z3, 6); // cmplt p11.d, p3/z, z3.d, #6 - __ sve_cmp(Assembler::LE, p9, __ S, p0, z19, -1); // cmple p9.s, p0/z, z19.s, #-1 - __ sve_cmp(Assembler::NE, p3, __ S, p2, z12, -3); // cmpne p3.s, p2/z, z12.s, #-3 - __ sve_cmp(Assembler::HS, p11, __ D, p4, z1, 20); // cmphs p11.d, p4/z, z1.d, #20 - __ sve_cmp(Assembler::HI, p8, __ S, p5, z2, 53); // cmphi p8.s, p5/z, z2.s, #53 - __ sve_cmp(Assembler::LS, p5, __ D, p6, z21, 49); // cmpls p5.d, p6/z, z21.d, #49 - __ sve_cmp(Assembler::LO, p13, __ B, p7, z3, 97); // cmplo p13.b, p7/z, z3.b, #97 + __ sve_cmp(Assembler::EQ, p12, __ B, p5, z4, 0); // cmpeq p12.b, p5/z, z4.b, #0 + __ sve_cmp(Assembler::GT, p15, __ H, p2, z5, 12); // cmpgt p15.h, p2/z, z5.h, #12 + __ sve_cmp(Assembler::GE, p7, __ S, p7, z28, 3); // cmpge p7.s, p7/z, z28.s, #3 + __ sve_cmp(Assembler::LT, p15, __ H, p4, z5, 15); // cmplt p15.h, p4/z, z5.h, #15 + __ sve_cmp(Assembler::LE, p9, __ S, p4, z26, -4); // cmple p9.s, p4/z, z26.s, #-4 + __ sve_cmp(Assembler::NE, p5, __ B, p7, z9, 1); // cmpne p5.b, p7/z, z9.b, #1 + __ sve_cmp(Assembler::HS, p13, __ D, p1, z27, 43); // cmphs p13.d, p1/z, z27.d, #43 + __ sve_cmp(Assembler::HI, p10, __ B, p6, z9, 70); // cmphi p10.b, p6/z, z9.b, #70 + __ sve_cmp(Assembler::LS, p8, __ B, p7, z22, 61); // cmpls p8.b, p7/z, z22.b, #61 + __ sve_cmp(Assembler::LO, p11, __ S, p5, z17, 11); // cmplo p11.s, p5/z, z17.s, #11 // SpecialCases __ ccmn(zr, zr, 3u, Assembler::LE); // ccmn xzr, xzr, #3, LE @@ -1086,229 +1071,215 @@ __ fmovd(v0, -1.0625); // fmov d0, #-1.0625 // LSEOp - __ swp(Assembler::xword, r19, r17, r9); // swp x19, x17, [x9] - __ ldadd(Assembler::xword, r28, r27, r15); // ldadd x28, x27, [x15] - __ ldbic(Assembler::xword, r7, r21, r23); // ldclr x7, x21, [x23] - __ ldeor(Assembler::xword, zr, r25, r2); // ldeor xzr, x25, [x2] - __ ldorr(Assembler::xword, zr, r27, r15); // ldset xzr, x27, [x15] - __ ldsmin(Assembler::xword, r10, r23, r19); // ldsmin x10, x23, [x19] - __ ldsmax(Assembler::xword, r3, r16, r0); // ldsmax x3, x16, [x0] - __ ldumin(Assembler::xword, r25, r26, r23); // ldumin x25, x26, [x23] - __ ldumax(Assembler::xword, r2, r16, r12); // ldumax x2, x16, [x12] + __ swp(Assembler::xword, r15, r6, r12); // swp x15, x6, [x12] + __ ldadd(Assembler::xword, r16, r11, r13); // ldadd x16, x11, [x13] + __ ldbic(Assembler::xword, r23, r1, r30); // ldclr x23, x1, [x30] + __ ldeor(Assembler::xword, r19, r5, r17); // ldeor x19, x5, [x17] + __ ldorr(Assembler::xword, r2, r16, r22); // ldset x2, x16, [x22] + __ ldsmin(Assembler::xword, r13, r10, r21); // ldsmin x13, x10, [x21] + __ ldsmax(Assembler::xword, r29, r27, r12); // ldsmax x29, x27, [x12] + __ ldumin(Assembler::xword, r27, r3, r1); // ldumin x27, x3, [x1] + __ ldumax(Assembler::xword, zr, r24, r19); // ldumax xzr, x24, [x19] // LSEOp - __ swpa(Assembler::xword, r4, r28, r30); // swpa x4, x28, [x30] - __ ldadda(Assembler::xword, r29, r16, r27); // ldadda x29, x16, [x27] - __ ldbica(Assembler::xword, r6, r9, r29); // ldclra x6, x9, [x29] - __ ldeora(Assembler::xword, r16, r7, r4); // ldeora x16, x7, [x4] - __ ldorra(Assembler::xword, r7, r15, r9); // ldseta x7, x15, [x9] - __ ldsmina(Assembler::xword, r23, r8, r2); // ldsmina x23, x8, [x2] - __ ldsmaxa(Assembler::xword, r28, r21, sp); // ldsmaxa x28, x21, [sp] - __ ldumina(Assembler::xword, r5, r27, r0); // ldumina x5, x27, [x0] - __ ldumaxa(Assembler::xword, r17, r15, r4); // ldumaxa x17, x15, [x4] + __ swpa(Assembler::xword, r17, r9, r28); // swpa x17, x9, [x28] + __ ldadda(Assembler::xword, r27, r15, r7); // ldadda x27, x15, [x7] + __ ldbica(Assembler::xword, r21, r23, sp); // ldclra x21, x23, [sp] + __ ldeora(Assembler::xword, r25, r2, sp); // ldeora x25, x2, [sp] + __ ldorra(Assembler::xword, r27, r16, r10); // ldseta x27, x16, [x10] + __ ldsmina(Assembler::xword, r23, r19, r3); // ldsmina x23, x19, [x3] + __ ldsmaxa(Assembler::xword, r16, r0, r25); // ldsmaxa x16, x0, [x25] + __ ldumina(Assembler::xword, r26, r23, r2); // ldumina x26, x23, [x2] + __ ldumaxa(Assembler::xword, r16, r12, r4); // ldumaxa x16, x12, [x4] // LSEOp - __ swpal(Assembler::xword, r26, r8, r28); // swpal x26, x8, [x28] - __ ldaddal(Assembler::xword, r22, r27, r27); // ldaddal x22, x27, [x27] - __ ldbical(Assembler::xword, r25, r23, r0); // ldclral x25, x23, [x0] - __ ldeoral(Assembler::xword, r4, r6, r15); // ldeoral x4, x6, [x15] - __ ldorral(Assembler::xword, r0, r4, r15); // ldsetal x0, x4, [x15] - __ ldsminal(Assembler::xword, r1, r10, r7); // ldsminal x1, x10, [x7] - __ ldsmaxal(Assembler::xword, r5, r10, r28); // ldsmaxal x5, x10, [x28] - __ lduminal(Assembler::xword, r7, r20, r23); // lduminal x7, x20, [x23] - __ ldumaxal(Assembler::xword, r21, r6, r11); // ldumaxal x21, x6, [x11] + __ swpal(Assembler::xword, r28, r30, r29); // swpal x28, x30, [x29] + __ ldaddal(Assembler::xword, r16, r27, r6); // ldaddal x16, x27, [x6] + __ ldbical(Assembler::xword, r9, r29, r15); // ldclral x9, x29, [x15] + __ ldeoral(Assembler::xword, r7, r4, r7); // ldeoral x7, x4, [x7] + __ ldorral(Assembler::xword, r15, r9, r23); // ldsetal x15, x9, [x23] + __ ldsminal(Assembler::xword, r8, r2, r28); // ldsminal x8, x2, [x28] + __ ldsmaxal(Assembler::xword, r21, zr, r5); // ldsmaxal x21, xzr, [x5] + __ lduminal(Assembler::xword, r27, r0, r17); // lduminal x27, x0, [x17] + __ ldumaxal(Assembler::xword, r15, r4, r26); // ldumaxal x15, x4, [x26] // LSEOp - __ swpl(Assembler::xword, r8, r17, sp); // swpl x8, x17, [sp] - __ ldaddl(Assembler::xword, r6, r17, r2); // ldaddl x6, x17, [x2] - __ ldbicl(Assembler::xword, r12, r30, r29); // ldclrl x12, x30, [x29] - __ ldeorl(Assembler::xword, r3, r27, r22); // ldeorl x3, x27, [x22] - __ ldorrl(Assembler::xword, r29, r14, r13); // ldsetl x29, x14, [x13] - __ ldsminl(Assembler::xword, r28, r17, r24); // ldsminl x28, x17, [x24] - __ ldsmaxl(Assembler::xword, r5, r2, r14); // ldsmaxl x5, x2, [x14] - __ lduminl(Assembler::xword, r10, r16, r11); // lduminl x10, x16, [x11] - __ ldumaxl(Assembler::xword, r27, r23, r12); // ldumaxl x27, x23, [x12] + __ swpl(Assembler::xword, r8, r28, r22); // swpl x8, x28, [x22] + __ ldaddl(Assembler::xword, r27, r27, r25); // ldaddl x27, x27, [x25] + __ ldbicl(Assembler::xword, r23, r0, r4); // ldclrl x23, x0, [x4] + __ ldeorl(Assembler::xword, r6, r16, r0); // ldeorl x6, x16, [x0] + __ ldorrl(Assembler::xword, r4, r15, r1); // ldsetl x4, x15, [x1] + __ ldsminl(Assembler::xword, r10, r7, r5); // ldsminl x10, x7, [x5] + __ ldsmaxl(Assembler::xword, r10, r28, r7); // ldsmaxl x10, x28, [x7] + __ lduminl(Assembler::xword, r20, r23, r21); // lduminl x20, x23, [x21] + __ ldumaxl(Assembler::xword, r6, r11, r8); // ldumaxl x6, x11, [x8] // LSEOp - __ swp(Assembler::word, r4, r22, r17); // swp w4, w22, [x17] - __ ldadd(Assembler::word, r4, r1, r19); // ldadd w4, w1, [x19] - __ ldbic(Assembler::word, r16, r16, r13); // ldclr w16, w16, [x13] - __ ldeor(Assembler::word, r14, r12, r2); // ldeor w14, w12, [x2] - __ ldorr(Assembler::word, r17, r3, r21); // ldset w17, w3, [x21] - __ ldsmin(Assembler::word, r23, r5, r6); // ldsmin w23, w5, [x6] - __ ldsmax(Assembler::word, r7, r19, r13); // ldsmax w7, w19, [x13] - __ ldumin(Assembler::word, r28, r17, r16); // ldumin w28, w17, [x16] - __ ldumax(Assembler::word, r6, r2, r29); // ldumax w6, w2, [x29] + __ swp(Assembler::word, r17, zr, r6); // swp w17, wzr, [x6] + __ ldadd(Assembler::word, r17, r2, r12); // ldadd w17, w2, [x12] + __ ldbic(Assembler::word, r30, r29, r3); // ldclr w30, w29, [x3] + __ ldeor(Assembler::word, r27, r22, r29); // ldeor w27, w22, [x29] + __ ldorr(Assembler::word, r14, r13, r28); // ldset w14, w13, [x28] + __ ldsmin(Assembler::word, r17, r24, r5); // ldsmin w17, w24, [x5] + __ ldsmax(Assembler::word, r2, r14, r10); // ldsmax w2, w14, [x10] + __ ldumin(Assembler::word, r16, r11, r27); // ldumin w16, w11, [x27] + __ ldumax(Assembler::word, r23, r12, r4); // ldumax w23, w12, [x4] // LSEOp - __ swpa(Assembler::word, r3, r4, r6); // swpa w3, w4, [x6] - __ ldadda(Assembler::word, r16, r20, r13); // ldadda w16, w20, [x13] - __ ldbica(Assembler::word, r12, r20, r8); // ldclra w12, w20, [x8] - __ ldeora(Assembler::word, r25, r20, r19); // ldeora w25, w20, [x19] - __ ldorra(Assembler::word, r0, r11, r24); // ldseta w0, w11, [x24] - __ ldsmina(Assembler::word, r6, r20, sp); // ldsmina w6, w20, [sp] - __ ldsmaxa(Assembler::word, r14, r16, r6); // ldsmaxa w14, w16, [x6] - __ ldumina(Assembler::word, r0, r7, r15); // ldumina w0, w7, [x15] - __ ldumaxa(Assembler::word, r19, r26, r9); // ldumaxa w19, w26, [x9] + __ swpa(Assembler::word, r22, r17, r4); // swpa w22, w17, [x4] + __ ldadda(Assembler::word, r1, r19, r16); // ldadda w1, w19, [x16] + __ ldbica(Assembler::word, r16, r13, r14); // ldclra w16, w13, [x14] + __ ldeora(Assembler::word, r12, r2, r17); // ldeora w12, w2, [x17] + __ ldorra(Assembler::word, r3, r21, r23); // ldseta w3, w21, [x23] + __ ldsmina(Assembler::word, r5, r6, r7); // ldsmina w5, w6, [x7] + __ ldsmaxa(Assembler::word, r19, r13, r28); // ldsmaxa w19, w13, [x28] + __ ldumina(Assembler::word, r17, r16, r6); // ldumina w17, w16, [x6] + __ ldumaxa(Assembler::word, r2, r29, r3); // ldumaxa w2, w29, [x3] // LSEOp - __ swpal(Assembler::word, r10, r23, r21); // swpal w10, w23, [x21] - __ ldaddal(Assembler::word, r22, r28, r2); // ldaddal w22, w28, [x2] - __ ldbical(Assembler::word, r3, r15, r19); // ldclral w3, w15, [x19] - __ ldeoral(Assembler::word, r20, r7, r4); // ldeoral w20, w7, [x4] - __ ldorral(Assembler::word, r29, r7, r0); // ldsetal w29, w7, [x0] - __ ldsminal(Assembler::word, r9, r16, r20); // ldsminal w9, w16, [x20] - __ ldsmaxal(Assembler::word, r23, r4, r16); // ldsmaxal w23, w4, [x16] - __ lduminal(Assembler::word, r10, r23, r11); // lduminal w10, w23, [x11] - __ ldumaxal(Assembler::word, r25, r6, sp); // ldumaxal w25, w6, [sp] + __ swpal(Assembler::word, r4, r6, r15); // swpal w4, w6, [x15] + __ ldaddal(Assembler::word, r20, r13, r12); // ldaddal w20, w13, [x12] + __ ldbical(Assembler::word, r20, r8, r25); // ldclral w20, w8, [x25] + __ ldeoral(Assembler::word, r20, r19, r0); // ldeoral w20, w19, [x0] + __ ldorral(Assembler::word, r11, r24, r6); // ldsetal w11, w24, [x6] + __ ldsminal(Assembler::word, r20, zr, r14); // ldsminal w20, wzr, [x14] + __ ldsmaxal(Assembler::word, r16, r6, r0); // ldsmaxal w16, w6, [x0] + __ lduminal(Assembler::word, r7, r15, r19); // lduminal w7, w15, [x19] + __ ldumaxal(Assembler::word, r26, r9, r10); // ldumaxal w26, w9, [x10] // LSEOp - __ swpl(Assembler::word, r16, r13, r23); // swpl w16, w13, [x23] - __ ldaddl(Assembler::word, r12, r1, r14); // ldaddl w12, w1, [x14] - __ ldbicl(Assembler::word, r9, r21, r16); // ldclrl w9, w21, [x16] - __ ldeorl(Assembler::word, r26, r15, r4); // ldeorl w26, w15, [x4] - __ ldorrl(Assembler::word, r4, r16, r8); // ldsetl w4, w16, [x8] - __ ldsminl(Assembler::word, r6, r30, r4); // ldsminl w6, w30, [x4] - __ ldsmaxl(Assembler::word, r29, r17, r29); // ldsmaxl w29, w17, [x29] - __ lduminl(Assembler::word, r26, r9, r15); // lduminl w26, w9, [x15] - __ ldumaxl(Assembler::word, r2, r11, r29); // ldumaxl w2, w11, [x29] + __ swpl(Assembler::word, r23, r21, r22); // swpl w23, w21, [x22] + __ ldaddl(Assembler::word, r28, r2, r3); // ldaddl w28, w2, [x3] + __ ldbicl(Assembler::word, r15, r19, r20); // ldclrl w15, w19, [x20] + __ ldeorl(Assembler::word, r7, r4, r29); // ldeorl w7, w4, [x29] + __ ldorrl(Assembler::word, r7, r0, r9); // ldsetl w7, w0, [x9] + __ ldsminl(Assembler::word, r16, r20, r23); // ldsminl w16, w20, [x23] + __ ldsmaxl(Assembler::word, r4, r16, r10); // ldsmaxl w4, w16, [x10] + __ lduminl(Assembler::word, r23, r11, r25); // lduminl w23, w11, [x25] + __ ldumaxl(Assembler::word, r6, zr, r16); // ldumaxl w6, wzr, [x16] // SHA3SIMDOp - __ bcax(v3, __ T16B, v7, v1, v27); // bcax v3.16B, v7.16B, v1.16B, v27.16B - __ eor3(v21, __ T16B, v18, v14, v8); // eor3 v21.16B, v18.16B, v14.16B, v8.16B - __ rax1(v18, __ T2D, v22, v25); // rax1 v18.2D, v22.2D, v25.2D - __ xar(v5, __ T2D, v20, v21, 37); // xar v5.2D, v20.2D, v21.2D, #37 + __ bcax(v13, __ T16B, v22, v11, v1); // bcax v13.16B, v22.16B, v11.16B, v1.16B + __ eor3(v13, __ T16B, v8, v20, v16); // eor3 v13.16B, v8.16B, v20.16B, v16.16B + __ rax1(v25, __ T2D, v15, v4); // rax1 v25.2D, v15.2D, v4.2D + __ xar(v4, __ T2D, v17, v8, 13); // xar v4.2D, v17.2D, v8.2D, #13 // SHA512SIMDOp - __ sha512h(v23, __ T2D, v16, v30); // sha512h q23, q16, v30.2D - __ sha512h2(v20, __ T2D, v20, v0); // sha512h2 q20, q20, v0.2D - __ sha512su0(v4, __ T2D, v19); // sha512su0 v4.2D, v19.2D - __ sha512su1(v24, __ T2D, v4, v20); // sha512su1 v24.2D, v4.2D, v20.2D + __ sha512h(v29, __ T2D, v4, v28); // sha512h q29, q4, v28.2D + __ sha512h2(v16, __ T2D, v29, v26); // sha512h2 q16, q29, v26.2D + __ sha512su0(v9, __ T2D, v14); // sha512su0 v9.2D, v14.2D + __ sha512su1(v2, __ T2D, v11, v28); // sha512su1 v2.2D, v11.2D, v28.2D // SVEBinaryImmOp - __ sve_add(z4, __ D, 210u); // add z4.d, z4.d, #0xd2 - __ sve_sub(z19, __ B, 71u); // sub z19.b, z19.b, #0x47 - __ sve_and(z8, __ H, 49663u); // and z8.h, z8.h, #0xc1ff - __ sve_eor(z31, __ S, 4294967231u); // eor z31.s, z31.s, #0xffffffbf - __ sve_orr(z1, __ H, 16368u); // orr z1.h, z1.h, #0x3ff0 + __ sve_add(z3, __ B, 10u); // add z3.b, z3.b, #0xa + __ sve_sub(z26, __ S, 150u); // sub z26.s, z26.s, #0x96 + __ sve_and(z14, __ H, 57343u); // and z14.h, z14.h, #0xdfff + __ sve_eor(z24, __ B, 191u); // eor z24.b, z24.b, #0xbf + __ sve_orr(z17, __ S, 4294966791u); // orr z17.s, z17.s, #0xfffffe07 // SVEBinaryImmOp - __ sve_add(z0, __ H, 61u); // add z0.h, z0.h, #0x3d - __ sve_sub(z24, __ S, 36u); // sub z24.s, z24.s, #0x24 - __ sve_and(z27, __ B, 243u); // and z27.b, z27.b, #0xf3 - __ sve_eor(z24, __ H, 65534u); // eor z24.h, z24.h, #0xfffe - __ sve_orr(z22, __ S, 4294967293u); // orr z22.s, z22.s, #0xfffffffd + __ sve_add(z20, __ S, 3u); // add z20.s, z20.s, #0x3 + __ sve_sub(z4, __ S, 196u); // sub z4.s, z4.s, #0xc4 + __ sve_and(z4, __ S, 4286578691u); // and z4.s, z4.s, #0xff800003 + __ sve_eor(z25, __ S, 33553408u); // eor z25.s, z25.s, #0x1fffc00 + __ sve_orr(z8, __ H, 49663u); // orr z8.h, z8.h, #0xc1ff // SVEBinaryImmOp - __ sve_add(z29, __ H, 113u); // add z29.h, z29.h, #0x71 - __ sve_sub(z20, __ B, 165u); // sub z20.b, z20.b, #0xa5 - __ sve_and(z28, __ H, 32256u); // and z28.h, z28.h, #0x7e00 - __ sve_eor(z12, __ S, 4287102855u); // eor z12.s, z12.s, #0xff87ff87 - __ sve_orr(z9, __ S, 3825205247u); // orr z9.s, z9.s, #0xe3ffffff + __ sve_add(z30, __ S, 36u); // add z30.s, z30.s, #0x24 + __ sve_sub(z30, __ B, 85u); // sub z30.b, z30.b, #0x55 + __ sve_and(z19, __ H, 4032u); // and z19.h, z19.h, #0xfc0 + __ sve_eor(z7, __ D, 274877904896u); // eor z7.d, z7.d, #0x3ffffff800 + __ sve_orr(z27, __ B, 243u); // orr z27.b, z27.b, #0xf3 // SVEBinaryImmOp - __ sve_add(z18, __ S, 41u); // add z18.s, z18.s, #0x29 - __ sve_sub(z0, __ B, 98u); // sub z0.b, z0.b, #0x62 - __ sve_and(z8, __ H, 32768u); // and z8.h, z8.h, #0x8000 - __ sve_eor(z4, __ H, 508u); // eor z4.h, z4.h, #0x1fc - __ sve_orr(z0, __ H, 64512u); // orr z0.h, z0.h, #0xfc00 + __ sve_add(z23, __ H, 132u); // add z23.h, z23.h, #0x84 + __ sve_sub(z30, __ S, 183u); // sub z30.s, z30.s, #0xb7 + __ sve_and(z20, __ D, 4503599627354112u); // and z20.d, z20.d, #0xfffffffffc000 + __ sve_eor(z13, __ S, 4042322160u); // eor z13.s, z13.s, #0xf0f0f0f0 + __ sve_orr(z28, __ H, 32256u); // orr z28.h, z28.h, #0x7e00 // SVEBinaryImmOp - __ sve_add(z3, __ B, 79u); // add z3.b, z3.b, #0x4f - __ sve_sub(z19, __ D, 84u); // sub z19.d, z19.d, #0x54 - __ sve_and(z24, __ B, 62u); // and z24.b, z24.b, #0x3e - __ sve_eor(z24, __ D, 18428729675200069887u); // eor z24.d, z24.d, #0xffc00000000000ff - __ sve_orr(z11, __ D, 17296056810822168583u); // orr z11.d, z11.d, #0xf007f007f007f007 + __ sve_add(z11, __ S, 13u); // add z11.s, z11.s, #0xd + __ sve_sub(z24, __ H, 159u); // sub z24.h, z24.h, #0x9f + __ sve_and(z13, __ S, 2151677951u); // and z13.s, z13.s, #0x803fffff + __ sve_eor(z4, __ B, 124u); // eor z4.b, z4.b, #0x7c + __ sve_orr(z7, __ H, 32768u); // orr z7.h, z7.h, #0x8000 // SVEBinaryImmOp - __ sve_add(z31, __ S, 115u); // add z31.s, z31.s, #0x73 - __ sve_sub(z3, __ D, 134u); // sub z3.d, z3.d, #0x86 - __ sve_and(z22, __ S, 4042322160u); // and z22.s, z22.s, #0xf0f0f0f0 - __ sve_eor(z3, __ B, 225u); // eor z3.b, z3.b, #0xe1 - __ sve_orr(z9, __ S, 4164941887u); // orr z9.s, z9.s, #0xf83ff83f + __ sve_add(z4, __ H, 243u); // add z4.h, z4.h, #0xf3 + __ sve_sub(z5, __ B, 86u); // sub z5.b, z5.b, #0x56 + __ sve_and(z21, __ D, 8064u); // and z21.d, z21.d, #0x1f80 + __ sve_eor(z9, __ S, 130023424u); // eor z9.s, z9.s, #0x7c00000 + __ sve_orr(z24, __ B, 62u); // orr z24.b, z24.b, #0x3e // SVEVectorOp - __ sve_add(z0, __ D, z4, z2); // add z0.d, z4.d, z2.d - __ sve_sub(z14, __ S, z6, z11); // sub z14.s, z6.s, z11.s - __ sve_fadd(z14, __ S, z17, z30); // fadd z14.s, z17.s, z30.s - __ sve_fmul(z3, __ S, z3, z23); // fmul z3.s, z3.s, z23.s - __ sve_fsub(z3, __ S, z24, z28); // fsub z3.s, z24.s, z28.s - __ sve_abs(z19, __ D, p5, z7); // abs z19.d, p5/m, z7.d - __ sve_add(z21, __ H, p3, z5); // add z21.h, p3/m, z21.h, z5.h - __ sve_and(z26, __ S, p1, z22); // and z26.s, p1/m, z26.s, z22.s - __ sve_asr(z17, __ H, p0, z3); // asr z17.h, p0/m, z17.h, z3.h - __ sve_bic(z20, __ H, p3, z8); // bic z20.h, p3/m, z20.h, z8.h - __ sve_clz(z14, __ H, p4, z17); // clz z14.h, p4/m, z17.h - __ sve_cnt(z13, __ D, p6, z18); // cnt z13.d, p6/m, z18.d - __ sve_eor(z19, __ H, p2, z16); // eor z19.h, p2/m, z19.h, z16.h - __ sve_lsl(z27, __ S, p5, z28); // lsl z27.s, p5/m, z27.s, z28.s - __ sve_lsr(z8, __ D, p2, z5); // lsr z8.d, p2/m, z8.d, z5.d - __ sve_mul(z28, __ H, p2, z0); // mul z28.h, p2/m, z28.h, z0.h - __ sve_neg(z25, __ B, p5, z21); // neg z25.b, p5/m, z21.b - __ sve_not(z3, __ B, p5, z26); // not z3.b, p5/m, z26.b - __ sve_orr(z26, __ S, p7, z19); // orr z26.s, p7/m, z26.s, z19.s - __ sve_rbit(z1, __ D, p3, z14); // rbit z1.d, p3/m, z14.d - __ sve_revb(z14, __ H, p0, z18); // revb z14.h, p0/m, z18.h - __ sve_smax(z31, __ S, p5, z23); // smax z31.s, p5/m, z31.s, z23.s - __ sve_smin(z30, __ B, p3, z8); // smin z30.b, p3/m, z30.b, z8.b - __ sve_sub(z0, __ S, p3, z23); // sub z0.s, p3/m, z0.s, z23.s - __ sve_fabs(z0, __ D, p4, z26); // fabs z0.d, p4/m, z26.d - __ sve_fadd(z24, __ D, p3, z22); // fadd z24.d, p3/m, z24.d, z22.d - __ sve_fdiv(z2, __ D, p0, z11); // fdiv z2.d, p0/m, z2.d, z11.d - __ sve_fmax(z12, __ D, p5, z24); // fmax z12.d, p5/m, z12.d, z24.d - __ sve_fmin(z9, __ D, p7, z17); // fmin z9.d, p7/m, z9.d, z17.d - __ sve_fmul(z20, __ D, p5, z4); // fmul z20.d, p5/m, z20.d, z4.d - __ sve_fneg(z13, __ D, p7, z22); // fneg z13.d, p7/m, z22.d - __ sve_frintm(z31, __ D, p6, z18); // frintm z31.d, p6/m, z18.d - __ sve_frintn(z15, __ D, p2, z13); // frintn z15.d, p2/m, z13.d - __ sve_frintp(z20, __ S, p1, z1); // frintp z20.s, p1/m, z1.s - __ sve_fsqrt(z14, __ S, p0, z7); // fsqrt z14.s, p0/m, z7.s - __ sve_fsub(z12, __ D, p4, z4); // fsub z12.d, p4/m, z12.d, z4.d - __ sve_fmad(z15, __ S, p0, z3, z30); // fmad z15.s, p0/m, z3.s, z30.s - __ sve_fmla(z20, __ D, p1, z20, z31); // fmla z20.d, p1/m, z20.d, z31.d - __ sve_fmls(z13, __ D, p3, z9, z14); // fmls z13.d, p3/m, z9.d, z14.d - __ sve_fmsb(z1, __ S, p3, z28, z3); // fmsb z1.s, p3/m, z28.s, z3.s - __ sve_fnmad(z26, __ S, p2, z25, z9); // fnmad z26.s, p2/m, z25.s, z9.s - __ sve_fnmsb(z26, __ D, p2, z14, z1); // fnmsb z26.d, p2/m, z14.d, z1.d - __ sve_fnmla(z26, __ D, p1, z29, z20); // fnmla z26.d, p1/m, z29.d, z20.d - __ sve_fnmls(z6, __ D, p7, z13, z1); // fnmls z6.d, p7/m, z13.d, z1.d - __ sve_mla(z11, __ B, p2, z1, z1); // mla z11.b, p2/m, z1.b, z1.b - __ sve_mls(z27, __ B, p6, z15, z2); // mls z27.b, p6/m, z15.b, z2.b - __ sve_and(z30, z17, z25); // and z30.d, z17.d, z25.d - __ sve_eor(z2, z24, z3); // eor z2.d, z24.d, z3.d - __ sve_orr(z29, z13, z3); // orr z29.d, z13.d, z3.d - __ sve_bic(z14, z16, z28); // bic z14.d, z16.d, z28.d - __ sve_uzp1(z4, __ S, z11, z27); // uzp1 z4.s, z11.s, z27.s - __ sve_uzp2(z2, __ D, z16, z1); // uzp2 z2.d, z16.d, z1.d - __ sve_fabd(z7, __ D, p5, z31); // fabd z7.d, p5/m, z7.d, z31.d - __ sve_bext(z16, __ S, z10, z22); // bext z16.s, z10.s, z22.s - __ sve_bdep(z29, __ B, z7, z22); // bdep z29.b, z7.b, z22.b - __ sve_eor3(z12, z24, z11); // eor3 z12.d, z12.d, z24.d, z11.d + __ sve_add(z23, __ S, z28, z13); // add z23.s, z28.s, z13.s + __ sve_sub(z10, __ S, z26, z12); // sub z10.s, z26.s, z12.s + __ sve_fadd(z30, __ S, z17, z14); // fadd z30.s, z17.s, z14.s + __ sve_fmul(z29, __ D, z16, z21); // fmul z29.d, z16.d, z21.d + __ sve_fsub(z7, __ S, z19, z2); // fsub z7.s, z19.s, z2.s + __ sve_abs(z26, __ S, p4, z9); // abs z26.s, p4/m, z9.s + __ sve_add(z17, __ B, p5, z0); // add z17.b, p5/m, z17.b, z0.b + __ sve_and(z2, __ B, p6, z14); // and z2.b, p6/m, z2.b, z14.b + __ sve_asr(z11, __ S, p5, z14); // asr z11.s, p5/m, z11.s, z14.s + __ sve_bic(z29, __ B, p3, z3); // bic z29.b, p3/m, z29.b, z3.b + __ sve_clz(z22, __ D, p2, z3); // clz z22.d, p2/m, z3.d + __ sve_cnt(z27, __ S, p0, z19); // cnt z27.s, p0/m, z19.s + __ sve_eor(z7, __ H, p6, z21); // eor z7.h, p6/m, z7.h, z21.h + __ sve_lsl(z5, __ B, p2, z25); // lsl z5.b, p2/m, z5.b, z25.b + __ sve_lsr(z21, __ B, p4, z17); // lsr z21.b, p4/m, z21.b, z17.b + __ sve_mul(z3, __ H, p2, z19); // mul z3.h, p2/m, z3.h, z19.h + __ sve_neg(z7, __ S, p3, z14); // neg z7.s, p3/m, z14.s + __ sve_not(z17, __ D, p2, z13); // not z17.d, p2/m, z13.d + __ sve_orr(z17, __ H, p7, z17); // orr z17.h, p7/m, z17.h, z17.h + __ sve_rbit(z15, __ S, p3, z26); // rbit z15.s, p3/m, z26.s + __ sve_revb(z27, __ H, p5, z7); // revb z27.h, p5/m, z7.h + __ sve_smax(z5, __ H, p7, z27); // smax z5.h, p7/m, z5.h, z27.h + __ sve_smin(z0, __ S, p3, z24); // smin z0.s, p3/m, z0.s, z24.s + __ sve_sub(z20, __ S, p0, z3); // sub z20.s, p0/m, z20.s, z3.s + __ sve_fabs(z25, __ D, p1, z25); // fabs z25.d, p1/m, z25.d + __ sve_fadd(z17, __ S, p4, z1); // fadd z17.s, p4/m, z17.s, z1.s + __ sve_fdiv(z14, __ S, p7, z13); // fdiv z14.s, p7/m, z14.s, z13.s + __ sve_fmax(z17, __ D, p0, z30); // fmax z17.d, p0/m, z17.d, z30.d + __ sve_fmin(z22, __ S, p5, z29); // fmin z22.s, p5/m, z22.s, z29.s + __ sve_fmul(z8, __ S, p0, z0); // fmul z8.s, p0/m, z8.s, z0.s + __ sve_fneg(z23, __ D, p5, z0); // fneg z23.d, p5/m, z0.d + __ sve_frintm(z25, __ S, p6, z23); // frintm z25.s, p6/m, z23.s + __ sve_frintn(z21, __ S, p5, z1); // frintn z21.s, p5/m, z1.s + __ sve_frintp(z10, __ D, p5, z11); // frintp z10.d, p5/m, z11.d + __ sve_fsqrt(z23, __ D, p6, z8); // fsqrt z23.d, p6/m, z8.d + __ sve_fsub(z17, __ D, p5, z19); // fsub z17.d, p5/m, z17.d, z19.d + __ sve_fmad(z4, __ D, p5, z13, z30); // fmad z4.d, p5/m, z13.d, z30.d + __ sve_fmla(z30, __ D, p7, z25, z17); // fmla z30.d, p7/m, z25.d, z17.d + __ sve_fmls(z14, __ D, p2, z12, z28); // fmls z14.d, p2/m, z12.d, z28.d + __ sve_fmsb(z5, __ S, p0, z13, z13); // fmsb z5.s, p0/m, z13.s, z13.s + __ sve_fnmad(z7, __ S, p2, z11, z19); // fnmad z7.s, p2/m, z11.s, z19.s + __ sve_fnmsb(z25, __ D, p3, z2, z3); // fnmsb z25.d, p3/m, z2.d, z3.d + __ sve_fnmla(z0, __ D, p5, z5, z20); // fnmla z0.d, p5/m, z5.d, z20.d + __ sve_fnmls(z28, __ S, p3, z13, z8); // fnmls z28.s, p3/m, z13.s, z8.s + __ sve_mla(z29, __ B, p0, z14, z27); // mla z29.b, p0/m, z14.b, z27.b + __ sve_mls(z3, __ H, p6, z8, z24); // mls z3.h, p6/m, z8.h, z24.h + __ sve_and(z1, z25, z10); // and z1.d, z25.d, z10.d + __ sve_eor(z1, z20, z25); // eor z1.d, z20.d, z25.d + __ sve_orr(z28, z19, z16); // orr z28.d, z19.d, z16.d + __ sve_bic(z27, z13, z1); // bic z27.d, z13.d, z1.d + __ sve_uzp1(z11, __ B, z9, z1); // uzp1 z11.b, z9.b, z1.b + __ sve_uzp2(z1, __ H, z27, z26); // uzp2 z1.h, z27.h, z26.h + __ sve_fabd(z2, __ D, p1, z29); // fabd z2.d, p1/m, z2.d, z29.d + __ sve_bext(z24, __ D, z2, z2); // bext z24.d, z2.d, z2.d + __ sve_bdep(z3, __ H, z25, z28); // bdep z3.h, z25.h, z28.h + __ sve_eor3(z3, z22, z13); // eor3 z3.d, z3.d, z22.d, z13.d // SVEReductionOp - __ sve_andv(v11, __ B, p2, z0); // andv b11, p2, z0.b - __ sve_orv(v23, __ B, p5, z20); // orv b23, p5, z20.b - __ sve_eorv(v3, __ B, p3, z15); // eorv b3, p3, z15.b - __ sve_smaxv(v30, __ B, p6, z27); // smaxv b30, p6, z27.b - __ sve_sminv(v21, __ D, p6, z10); // sminv d21, p6, z10.d - __ sve_fminv(v3, __ S, p6, z4); // fminv s3, p6, z4.s - __ sve_fmaxv(v6, __ S, p0, z21); // fmaxv s6, p0, z21.s - __ sve_fadda(v25, __ D, p6, z30); // fadda d25, p6, d25, z30.d - __ sve_uaddv(v31, __ H, p4, z1); // uaddv d31, p4, z1.h - -// AddWideNEONOp - __ saddwv(v12, v13, __ T8H, v14, __ T8B); // saddw v12.8H, v13.8H, v14.8B - __ saddwv2(v30, v31, __ T8H, v0, __ T16B); // saddw2 v30.8H, v31.8H, v0.16B - __ saddwv(v13, v14, __ T4S, v15, __ T4H); // saddw v13.4S, v14.4S, v15.4H - __ saddwv2(v8, v9, __ T4S, v10, __ T8H); // saddw2 v8.4S, v9.4S, v10.8H - __ saddwv(v25, v26, __ T2D, v27, __ T2S); // saddw v25.2D, v26.2D, v27.2S - __ saddwv2(v29, v30, __ T2D, v31, __ T4S); // saddw2 v29.2D, v30.2D, v31.4S - __ uaddwv(v1, v2, __ T8H, v3, __ T8B); // uaddw v1.8H, v2.8H, v3.8B - __ uaddwv2(v31, v0, __ T8H, v1, __ T16B); // uaddw2 v31.8H, v0.8H, v1.16B - __ uaddwv(v23, v24, __ T4S, v25, __ T4H); // uaddw v23.4S, v24.4S, v25.4H - __ uaddwv2(v31, v0, __ T4S, v1, __ T8H); // uaddw2 v31.4S, v0.4S, v1.8H - __ uaddwv(v20, v21, __ T2D, v22, __ T2S); // uaddw v20.2D, v21.2D, v22.2S - __ uaddwv2(v0, v1, __ T2D, v2, __ T4S); // uaddw2 v0.2D, v1.2D, v2.4S + __ sve_andv(v27, __ H, p4, z4); // andv h27, p4, z4.h + __ sve_orv(v26, __ S, p4, z2); // orv s26, p4, z2.s + __ sve_eorv(v1, __ S, p7, z7); // eorv s1, p7, z7.s + __ sve_smaxv(v30, __ H, p7, z16); // smaxv h30, p7, z16.h + __ sve_sminv(v21, __ B, p4, z28); // sminv b21, p4, z28.b + __ sve_fminv(v21, __ D, p1, z12); // fminv d21, p1, z12.d + __ sve_fmaxv(v11, __ S, p2, z10); // fmaxv s11, p2, z10.s + __ sve_fadda(v0, __ D, p1, z22); // fadda d0, p1, d0, z22.d + __ sve_uaddv(v20, __ H, p1, z3); // uaddv d20, p1, z3.h __ bind(forth); @@ -1327,30 +1298,30 @@ 0x9101a1a0, 0xb10a5cc8, 0xd10810aa, 0xf10fd061, 0x120cb166, 0x321764bc, 0x52174681, 0x720c0227, 0x9241018e, 0xb25a2969, 0xd278b411, 0xf26aad01, - 0x14000000, 0x17ffffd7, 0x14000441, 0x94000000, - 0x97ffffd4, 0x9400043e, 0x3400000a, 0x34fffa2a, - 0x3400876a, 0x35000008, 0x35fff9c8, 0x35008708, - 0xb400000b, 0xb4fff96b, 0xb40086ab, 0xb500001d, - 0xb5fff91d, 0xb500865d, 0x10000013, 0x10fff8b3, - 0x100085f3, 0x90000013, 0x36300016, 0x3637f836, - 0x36308576, 0x3758000c, 0x375ff7cc, 0x3758850c, + 0x14000000, 0x17ffffd7, 0x14000428, 0x94000000, + 0x97ffffd4, 0x94000425, 0x3400000a, 0x34fffa2a, + 0x3400844a, 0x35000008, 0x35fff9c8, 0x350083e8, + 0xb400000b, 0xb4fff96b, 0xb400838b, 0xb500001d, + 0xb5fff91d, 0xb500833d, 0x10000013, 0x10fff8b3, + 0x100082d3, 0x90000013, 0x36300016, 0x3637f836, + 0x36308256, 0x3758000c, 0x375ff7cc, 0x375881ec, 0x128313a0, 0x528a32c7, 0x7289173b, 0x92ab3acc, 0xd2a0bf94, 0xf2c285e8, 0x9358722f, 0x330e652f, 0x53067f3b, 0x93577c53, 0xb34a1aac, 0xd35a4016, 0x13946c63, 0x93c3dbc8, 0x54000000, 0x54fff5a0, - 0x540082e0, 0x54000001, 0x54fff541, 0x54008281, - 0x54000002, 0x54fff4e2, 0x54008222, 0x54000002, - 0x54fff482, 0x540081c2, 0x54000003, 0x54fff423, - 0x54008163, 0x54000003, 0x54fff3c3, 0x54008103, - 0x54000004, 0x54fff364, 0x540080a4, 0x54000005, - 0x54fff305, 0x54008045, 0x54000006, 0x54fff2a6, - 0x54007fe6, 0x54000007, 0x54fff247, 0x54007f87, - 0x54000008, 0x54fff1e8, 0x54007f28, 0x54000009, - 0x54fff189, 0x54007ec9, 0x5400000a, 0x54fff12a, - 0x54007e6a, 0x5400000b, 0x54fff0cb, 0x54007e0b, - 0x5400000c, 0x54fff06c, 0x54007dac, 0x5400000d, - 0x54fff00d, 0x54007d4d, 0x5400000e, 0x54ffefae, - 0x54007cee, 0x5400000f, 0x54ffef4f, 0x54007c8f, + 0x54007fc0, 0x54000001, 0x54fff541, 0x54007f61, + 0x54000002, 0x54fff4e2, 0x54007f02, 0x54000002, + 0x54fff482, 0x54007ea2, 0x54000003, 0x54fff423, + 0x54007e43, 0x54000003, 0x54fff3c3, 0x54007de3, + 0x54000004, 0x54fff364, 0x54007d84, 0x54000005, + 0x54fff305, 0x54007d25, 0x54000006, 0x54fff2a6, + 0x54007cc6, 0x54000007, 0x54fff247, 0x54007c67, + 0x54000008, 0x54fff1e8, 0x54007c08, 0x54000009, + 0x54fff189, 0x54007ba9, 0x5400000a, 0x54fff12a, + 0x54007b4a, 0x5400000b, 0x54fff0cb, 0x54007aeb, + 0x5400000c, 0x54fff06c, 0x54007a8c, 0x5400000d, + 0x54fff00d, 0x54007a2d, 0x5400000e, 0x54ffefae, + 0x540079ce, 0x5400000f, 0x54ffef4f, 0x5400796f, 0xd40658e1, 0xd4014d22, 0xd4046543, 0xd4273f60, 0xd44cad80, 0xd503201f, 0xd503203f, 0xd503205f, 0xd503209f, 0xd50320bf, 0xd503219f, 0xd50323bf, @@ -1375,23 +1346,23 @@ 0xb81b1022, 0x381ea354, 0x79002fd7, 0xf85cf39a, 0xb8580309, 0x385e218c, 0x784051e1, 0x389e11d8, 0x789fa1f8, 0x79c01865, 0xb881131b, 0xfc5dd3ad, - 0xbc5d1137, 0xfc00900b, 0xbc181015, 0xf818ec7d, + 0xbc5d1136, 0xfc00900b, 0xbc181014, 0xf818ec7d, 0xb81b8c91, 0x381efc40, 0x78007c3d, 0xf857beb0, 0xb8413dd4, 0x385fddd6, 0x78409e2f, 0x389eddea, 0x789e7d94, 0x78de3d55, 0xb8805c13, 0xfc5cadc0, - 0xbc428c23, 0xfc1a2dc4, 0xbc1caf92, 0xf81475f6, + 0xbc428c23, 0xfc1a2dc4, 0xbc1caf91, 0xf81475f6, 0xb81f95d1, 0x381e757e, 0x78014561, 0xf8402436, 0xb85896e2, 0x385f4763, 0x785db4f0, 0x3880374f, 0x789e25e7, 0x78dd0563, 0xb88166f9, 0xfc529540, - 0xbc4374d3, 0xfc1166ae, 0xbc1ba6c0, 0xf820ea7b, + 0xbc4374d1, 0xfc1166ad, 0xbc1ba6c0, 0xf820ea7b, 0xb82d68c8, 0x38367a04, 0x782f4b59, 0xf878c8a4, 0xb8674a24, 0x386b78f1, 0x78776bc0, 0x38a15aca, - 0x78bedbd5, 0x78fcd94b, 0xb8aa4a7c, 0xfc6ecbbe, - 0xbc65d8a8, 0xfc2de919, 0xbc3a7b11, 0xf91f1193, + 0x78bedbd5, 0x78fcd94b, 0xb8aa4a7c, 0xfc6ecbbd, + 0xbc65d8a8, 0xfc2de918, 0xbc3a7b11, 0xf91f1193, 0xb91ed5f7, 0x391ec9bd, 0x79182ceb, 0xf95d4b0a, 0xb9581010, 0x395fc034, 0x795fb221, 0x399d8731, 0x799efb3b, 0x79dd1a2e, 0xb998e4ea, 0xfd583723, - 0xbd5ea12c, 0xfd18dc38, 0xbd1b0e83, 0x58ffdaa2, + 0xbd5ea12c, 0xfd18dc37, 0xbd1b0e83, 0x58ffdaa2, 0x1800001d, 0xf885d1c0, 0xd8ffda40, 0xf8a77820, 0xf9980220, 0x1a030301, 0x3a140311, 0x5a0d000b, 0x7a07015c, 0x9a1001e4, 0xba140182, 0xda0d01bd, @@ -1412,193 +1383,187 @@ 0x9ad521f7, 0x9adb263c, 0x9ac0286a, 0x9ac92f27, 0x9bdd7de6, 0x9b427d4f, 0x1b0b2cf1, 0x1b1ddcf7, 0x9b0b2f6e, 0x9b0cbf04, 0x9b2b728e, 0x9b2cdd6d, - 0x9bae275e, 0x9ba7954d, 0x7ea3d5fe, 0x1e30098c, - 0x1e321bff, 0x1e302ab3, 0x1e35394f, 0x7efcd542, - 0x1e7f0bc7, 0x1e621832, 0x1e632946, 0x1e673979, - 0x1f000d81, 0x1f06dfb3, 0x1f3c6c06, 0x1f2774a2, - 0x1f4d332c, 0x1f48ca78, 0x1f755356, 0x1f7e5853, - 0x1e2042c8, 0x1e20c2b3, 0x1e21424c, 0x1e21c0d5, - 0x1e22c070, 0x1e23c3a3, 0x1ee24383, 0x1e6041cf, - 0x1e60c1aa, 0x1e61424c, 0x1e61c34a, 0x1e6240e7, - 0x1e3803ae, 0x9e3802e0, 0x1e780180, 0x9e7801d7, - 0x1e2200ed, 0x9e2200ef, 0x1e620289, 0x9e620393, - 0x1e24021e, 0x9e640122, 0x1e3002b0, 0x9e70009d, - 0x1e260361, 0x9e660318, 0x1e2702ae, 0x9e6700ad, - 0x1e392180, 0x1e7e2320, 0x1e202388, 0x1e6022a8, + 0x9bae275e, 0x9ba7954d, 0x7ea3d5fd, 0x1e2f098b, + 0x1e311bde, 0x1e2f2a93, 0x1e35392f, 0x7efbd522, + 0x1e7e0ba7, 0x1e621831, 0x1e632946, 0x1e673978, + 0x1f000d61, 0x1f06db91, 0x1f3b6806, 0x1f2770a2, + 0x1f4d2f2b, 0x1f48c677, 0x1f744f35, 0x1f7d5851, + 0x1e2042a8, 0x1e20c293, 0x1e21422b, 0x1e21c0d4, + 0x1e22c06f, 0x1e23c383, 0x1ee24363, 0x1e6041ce, + 0x1e60c18a, 0x1e61422b, 0x1e61c32a, 0x1e6240e7, + 0x1e38038e, 0x9e3802c0, 0x1e780180, 0x9e7801b7, + 0x1e2200ed, 0x9e2200ee, 0x1e620288, 0x9e620391, + 0x1e24021e, 0x9e640122, 0x1e300290, 0x9e70009d, + 0x1e260341, 0x9e6602f8, 0x1e2702ae, 0x9e6700ac, + 0x1e382180, 0x1e7d2300, 0x1e202368, 0x1e6022a8, 0x293a1796, 0x29426e73, 0x697c68fc, 0xa93d0486, 0xa97b5eba, 0x29b47934, 0x29c2534d, 0x69f62dbd, 0xa9bd54bb, 0xa9c503c6, 0x28a63e13, 0x28e25d2c, 0x68c469e0, 0xa8b34748, 0xa8f51c59, 0x28264433, 0x285036c0, 0xa8005f7d, 0xa872290b, 0x0c407160, - 0x4cdfa350, 0x0cd16f56, 0x4cdf27bb, 0x0d40c0d6, - 0x4ddfcbae, 0x0dd0cd96, 0x4c408c01, 0x0cdf86aa, - 0x4d60c327, 0x0dffc929, 0x4deecd89, 0x4cd14887, - 0x0c404a37, 0x4d40e6c4, 0x4ddfe84d, 0x0dcced50, - 0x4cdf0444, 0x0ccb0286, 0x0d60e18c, 0x0dffe630, - 0x0df0eb2e, 0x0e31bab4, 0x4e31b841, 0x0e71bb17, + 0x4cdfa350, 0x0cd16f55, 0x4cdf27ba, 0x0d40c0d5, + 0x4ddfcbad, 0x0dd0cd95, 0x4c408c01, 0x0cdf86a9, + 0x4d60c327, 0x0dffc928, 0x4deecd89, 0x4cd14887, + 0x0c404a37, 0x4d40e6c3, 0x4ddfe84c, 0x0dcced4f, + 0x4cdf0444, 0x0ccb0286, 0x0d60e18b, 0x0dffe62f, + 0x0df0eb2e, 0x0e31bab4, 0x4e31b841, 0x0e71baf6, 0x4e71bbfe, 0x4eb1b9ee, 0x0e30a862, 0x4e30a8e6, - 0x0e70a883, 0x4e70a928, 0x4eb0ab59, 0x6e30f820, - 0x0e31ab9b, 0x2e31abfe, 0x4e31a8c5, 0x6e31a8c5, - 0x0e71abfe, 0x2e71a98b, 0x4e71ab59, 0x6e71a820, - 0x4eb1a81f, 0x6eb1a820, 0x6eb0fa93, 0x7e30fbdd, - 0x7e70fb7a, 0x7eb0f949, 0x7ef0fb7a, 0x0ea0c9ac, - 0x4ea0ca0f, 0x4ee0c98b, 0x2ea0c98b, 0x6ea0ca72, - 0x6ee0cb59, 0x0ea0daf6, 0x4ea0db38, 0x4ee0d820, - 0x0ea0ea51, 0x4ea0e98b, 0x4ee0e8e6, 0x2ea0dbdd, - 0x6ea0d8e6, 0x6ee0d8c5, 0x0e20b8c5, 0x4e20bad5, - 0x0e60ba93, 0x4e60ba30, 0x0ea0ba72, 0x4ea0bbfe, - 0x4ee0bb9b, 0x0ea0fbbc, 0x4ea0f841, 0x4ee0fbbc, - 0x2ea0f841, 0x6ea0fab4, 0x6ee0fbdd, 0x2ea1fa30, - 0x6ea1f9cd, 0x6ee1f96a, 0x2e205bdd, 0x6e205bdd, + 0x0e70a883, 0x4e70a907, 0x4eb0ab38, 0x6e30f820, + 0x0e31ab9b, 0x2e31abdd, 0x4e31a8c5, 0x6e31a8c5, + 0x0e71abdd, 0x2e71a98b, 0x4e71ab59, 0x6e71a820, + 0x4eb1abfe, 0x6eb1a820, 0x6eb0fa51, 0x7e30fbbc, + 0x7e70fb59, 0x7eb0f949, 0x7ef0fb59, 0x0ea0c9ac, + 0x4ea0ca0f, 0x4ee0c98b, 0x2ea0c96a, 0x6ea0ca51, + 0x6ee0cb38, 0x0ea0dad5, 0x4ea0db17, 0x4ee0d820, + 0x0ea0ea30, 0x4ea0e96a, 0x4ee0e8e6, 0x2ea0dbbc, + 0x6ea0d8e6, 0x6ee0d8c5, 0x0e20b8c5, 0x4e20bab4, + 0x0e60ba51, 0x4e60ba0f, 0x0ea0ba51, 0x4ea0bbdd, + 0x4ee0bb7a, 0x0ea0fbbc, 0x4ea0f841, 0x4ee0fb9b, + 0x2ea0f820, 0x6ea0fab4, 0x6ee0fbbc, 0x2ea1fa0f, + 0x6ea1f9ac, 0x6ee1f96a, 0x2e205bbc, 0x6e205bbc, 0x0e351e93, 0x4e381ef6, 0x0eac1d6a, 0x4ea61ca4, - 0x2e211c1f, 0x6e371ed5, 0x0e2a8528, 0x4e21841f, - 0x0e758693, 0x4e6c856a, 0x0ebe87bc, 0x4ea48462, - 0x4efb8759, 0x0e27d4c5, 0x4e25d483, 0x4e6ad528, - 0x2e3886f6, 0x6e358693, 0x2e6f85cd, 0x6e6784c5, - 0x2ebf87dd, 0x6eba8738, 0x6ef786d5, 0x0ebcd77a, - 0x4ebad738, 0x4ee5d483, 0x0e3a9f38, 0x4e3c9f7a, - 0x0e799f17, 0x4e719e0f, 0x0eb79ed5, 0x4ea59c83, - 0x2ebad738, 0x6eaad528, 0x6efbd759, 0x2e36d6b4, - 0x6e32d630, 0x6e73d651, 0x2e24dc62, 0x6e23dc41, + 0x2e201ffe, 0x6e361eb4, 0x0e2a8528, 0x4e2087fe, + 0x0e738651, 0x4e6c856a, 0x0ebd879b, 0x4ea48462, + 0x4efa8738, 0x0e26d4a4, 0x4e25d483, 0x4e6ad528, + 0x2e3886f6, 0x6e338651, 0x2e6f85cd, 0x6e6684a4, + 0x2ebe87bc, 0x6eb98717, 0x6ef786d5, 0x0ebbd759, + 0x4ebad738, 0x4ee5d483, 0x0e399f17, 0x4e3c9f7a, + 0x0e799f17, 0x4e709dee, 0x0eb79ed5, 0x4ea59c83, + 0x2eb9d717, 0x6eaad528, 0x6efad738, 0x2e35d693, + 0x6e31d60f, 0x6e72d630, 0x2e24dc62, 0x6e23dc41, 0x6e62dc20, 0x0e7a9738, 0x4e6694a4, 0x0ea59483, - 0x4eae95ac, 0x0e21cc1f, 0x4e3ecfbc, 0x4e6ccd6a, - 0x2e7c977a, 0x6e649462, 0x2eae95ac, 0x6eb49672, - 0x0ea1cc1f, 0x4ea3cc41, 0x4eefcdcd, 0x2e3fffdd, - 0x6e22fc20, 0x6e75fe93, 0x0e2e65ac, 0x4e336651, - 0x0e7866f6, 0x4e6f65cd, 0x0ebe67bc, 0x4ea067fe, - 0x0e21a41f, 0x4e23a441, 0x0e7ca77a, 0x4e7ea7bc, - 0x0ea6a4a4, 0x4ea0a7fe, 0x0e26f4a4, 0x4e28f4e6, - 0x4e60f7fe, 0x0e3c6f7a, 0x4e346e72, 0x0e6b6d49, - 0x4e6a6d28, 0x0eae6dac, 0x4ea26c20, 0x0e36aeb4, - 0x4e23ac41, 0x0e7aaf38, 0x4e64ac62, 0x0ea2ac20, - 0x4eabad49, 0x0ebaf738, 0x4ebcf77a, 0x4ef2f630, - 0x2ea0effe, 0x6ea5ec83, 0x6eeced6a, 0x0fa710c5, - 0x4f8b8149, 0x4fc710c5, 0x0f8750c5, 0x4faa8128, - 0x4fc750c5, 0x2f8890e6, 0x4fa880e6, 0x6fc59083, - 0x0f6f81cd, 0x4f448862, 0x0f848062, 0x4fab8149, - 0x0e3736d5, 0x4e323630, 0x0e743672, 0x4e6d358b, - 0x0eb736d5, 0x4eb93717, 0x4eee35ac, 0x0e3c3f7a, - 0x4e393f17, 0x0e7e3fbc, 0x4e703dee, 0x0ead3d8b, - 0x4eba3f38, 0x4ee33c41, 0x2e2e8dac, 0x6e218c1f, - 0x2e6c8d6a, 0x6e728e30, 0x2ea98d07, 0x6ea48c62, - 0x6ee58c83, 0x2e2f35cd, 0x6e353693, 0x2e733651, - 0x6e723630, 0x2ea53483, 0x6ea33441, 0x6eed358b, - 0x2e203ffe, 0x6e273cc5, 0x2e6a3d28, 0x6e713e0f, - 0x2ebf3fdd, 0x6ea03ffe, 0x6ee23c20, 0x0e36e6b4, - 0x4e29e507, 0x4e76e6b4, 0x2eb9e717, 0x6ebee7bc, - 0x6ef7e6d5, 0x2e3de79b, 0x6e3be759, 0x6e67e4c5, - 0x65d23ee0, 0x65903d92, 0x65d03fa7, 0x65912fe9, - 0x65d13bf9, 0x65932a0a, 0x25cb90c4, 0x25040bde, - 0x25c11085, 0x25c62c6b, 0x259f2279, 0x259d8993, - 0x24e5102b, 0x24ad5458, 0x24ec7ab5, 0x24387c6d, - 0xba5fd3e3, 0x3a5f03e5, 0xfa411be4, 0x7a42cbe2, - 0x93df03ff, 0xc820ffff, 0x8822fc7f, 0xc8247cbf, - 0x88267fff, 0x4e010fe0, 0x5e040420, 0x4e081fe1, - 0x4e0c1fe1, 0x4e0a1fe1, 0x4e071fe1, 0x4e042c20, - 0x4e062c20, 0x4e052c20, 0x4e083c20, 0x0e0c3c20, - 0x0e0a3c20, 0x0e073c20, 0x9eae0020, 0x0f03f409, - 0x6f03f40e, 0x4cc0ac3f, 0x0ea1b820, 0x4e21c862, - 0x4e61b8a4, 0x05a08020, 0x05104fe0, 0x05505001, - 0x05906fe2, 0x05d03005, 0x05101fea, 0x05901feb, - 0x04b0e3e0, 0x0470e7e1, 0x042f9c20, 0x043f9c35, - 0x047f9c20, 0x04ff9c20, 0x04299420, 0x04319160, - 0x0461943e, 0x04a19020, 0x04038100, 0x040381a0, - 0x040387e1, 0x04438be2, 0x04c38fe3, 0x040181e0, - 0x04018100, 0x04018621, 0x04418b22, 0x04418822, - 0x04818c23, 0x040081e0, 0x04008120, 0x04008761, - 0x04008621, 0x04408822, 0x04808c23, 0x042053ff, - 0x047f5401, 0x25208028, 0x2538cfe0, 0x2578d001, - 0x25b8efe2, 0x25f8f007, 0x2538dfea, 0x25b8dfeb, - 0xa400a3e0, 0xa420a7e0, 0xa4484be0, 0xa467afe0, - 0xa4a8a7ea, 0xa547a814, 0xa4084ffe, 0xa55c53e0, - 0xa5e1540b, 0xe400fbf6, 0xe408ffff, 0xe420e7e0, - 0xe4484be0, 0xe460efe0, 0xe547e400, 0xe4014be0, - 0xe4a84fe0, 0xe5f15000, 0x858043e0, 0x85a043ff, - 0xe59f5d08, 0x0420e3e9, 0x0460e3ea, 0x04a0e3eb, - 0x04e0e3ec, 0x25104042, 0x25104871, 0x25904861, - 0x25904c92, 0x05344020, 0x05744041, 0x05b44062, - 0x05f44083, 0x252c8840, 0x253c1420, 0x25681572, - 0x25a21ce3, 0x25ea1e34, 0x253c0421, 0x25680572, - 0x25a20ce3, 0x25ea0e34, 0x0522c020, 0x05e6c0a4, - 0x2401a001, 0x2443a051, 0x24858881, 0x24c78cd1, - 0x24850891, 0x24c70cc1, 0x250f9001, 0x25508051, - 0x25802491, 0x25df28c1, 0x25850c81, 0x251e10d1, - 0x65816001, 0x65c36051, 0x65854891, 0x65c74cc1, - 0x05733820, 0x05b238a4, 0x05f138e6, 0x0570396a, - 0x65d0a001, 0x65d6a443, 0x65d4a826, 0x6594ac26, - 0x6554ac26, 0x6556ac26, 0x6552ac26, 0x65cbac85, - 0x65caac01, 0x6589ac85, 0x6588ac01, 0x65c9ac85, - 0x65c8ac01, 0x65dea833, 0x659ca509, 0x65d8a801, - 0x65dcac01, 0x655cb241, 0x0520a1e0, 0x0521a601, - 0x052281e0, 0x05238601, 0x04a14026, 0x042244a6, - 0x046344a6, 0x04a444a6, 0x04e544a7, 0x0568aca7, - 0x05b23230, 0x853040af, 0xc5b040af, 0xe57080af, - 0xe5b080af, 0x25034440, 0x254054c4, 0x25034640, - 0x25415a05, 0x25834440, 0x25c54489, 0x250b5d3a, - 0x2550dc20, 0x2518e3e1, 0x2518e021, 0x2518e0a1, - 0x2518e121, 0x2518e1a1, 0x2558e3e2, 0x2558e042, - 0x2558e0c2, 0x2558e142, 0x2598e3e3, 0x2598e063, - 0x2598e0e3, 0x2598e163, 0x25d8e3e4, 0x25d8e084, - 0x25d8e104, 0x25d8e184, 0x2518e407, 0x05214800, - 0x05614800, 0x05a14800, 0x05e14800, 0x05214c00, - 0x05614c00, 0x05a14c00, 0x05e14c00, 0x05304001, - 0x05314001, 0x05a18610, 0x05e18610, 0x05271e11, - 0x6545e891, 0x6585e891, 0x65c5e891, 0x6545c891, - 0x6585c891, 0x65c5c891, 0x45b0c210, 0x45f1c231, - 0x1e601000, 0x1e603000, 0x1e621000, 0x1e623000, - 0x1e641000, 0x1e643000, 0x1e661000, 0x1e663000, - 0x1e681000, 0x1e683000, 0x1e6a1000, 0x1e6a3000, - 0x1e6c1000, 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, - 0x1e701000, 0x1e703000, 0x1e721000, 0x1e723000, - 0x1e741000, 0x1e743000, 0x1e761000, 0x1e763000, - 0x1e781000, 0x1e783000, 0x1e7a1000, 0x1e7a3000, - 0x1e7c1000, 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, - 0xf8338131, 0xf83c01fb, 0xf82712f5, 0xf83f2059, - 0xf83f31fb, 0xf82a5277, 0xf8234010, 0xf83972fa, - 0xf8226190, 0xf8a483dc, 0xf8bd0370, 0xf8a613a9, - 0xf8b02087, 0xf8a7312f, 0xf8b75048, 0xf8bc43f5, - 0xf8a5701b, 0xf8b1608f, 0xf8fa8388, 0xf8f6037b, - 0xf8f91017, 0xf8e421e6, 0xf8e031e4, 0xf8e150ea, - 0xf8e5438a, 0xf8e772f4, 0xf8f56166, 0xf86883f1, - 0xf8660051, 0xf86c13be, 0xf86322db, 0xf87d31ae, - 0xf87c5311, 0xf86541c2, 0xf86a7170, 0xf87b6197, - 0xb8248236, 0xb8240261, 0xb83011b0, 0xb82e204c, - 0xb83132a3, 0xb83750c5, 0xb82741b3, 0xb83c7211, - 0xb82663a2, 0xb8a380c4, 0xb8b001b4, 0xb8ac1114, - 0xb8b92274, 0xb8a0330b, 0xb8a653f4, 0xb8ae40d0, - 0xb8a071e7, 0xb8b3613a, 0xb8ea82b7, 0xb8f6005c, - 0xb8e3126f, 0xb8f42087, 0xb8fd3007, 0xb8e95290, - 0xb8f74204, 0xb8ea7177, 0xb8f963e6, 0xb87082ed, - 0xb86c01c1, 0xb8691215, 0xb87a208f, 0xb8643110, - 0xb866509e, 0xb87d43b1, 0xb87a71e9, 0xb86263ab, - 0xce216ce3, 0xce0e2255, 0xce798ed2, 0xce959685, - 0xce7e8217, 0xce608694, 0xcec08264, 0xce748898, - 0x25e0da44, 0x2521c8f3, 0x05801548, 0x0540cbdf, - 0x05006521, 0x2560c7a0, 0x25a1c498, 0x058026bb, - 0x05407dd8, 0x0500f3d6, 0x2560ce3d, 0x2521d4b4, - 0x05803cbc, 0x05404d6c, 0x05001b89, 0x25a0c532, - 0x2521cc40, 0x05800c08, 0x054074c4, 0x050034a0, - 0x2520c9e3, 0x25e1ca93, 0x05803e98, 0x05425238, - 0x050024cb, 0x25a0ce7f, 0x25e1d0c3, 0x05802676, - 0x05401e63, 0x05002d49, 0x04e20080, 0x04ab04ce, - 0x659e022e, 0x65970863, 0x659c0703, 0x04d6b4f3, - 0x04400cb5, 0x049a06da, 0x04508071, 0x045b0d14, - 0x0459b22e, 0x04daba4d, 0x04590a13, 0x0493979b, - 0x04d188a8, 0x0450081c, 0x0417b6b9, 0x041eb743, - 0x04981e7a, 0x05e78dc1, 0x0564824e, 0x048816ff, - 0x040a0d1e, 0x04810ee0, 0x04dcb340, 0x65c08ed8, - 0x65cd8162, 0x65c6970c, 0x65c79e29, 0x65c29494, - 0x04ddbecd, 0x65c2ba5f, 0x65c0a9af, 0x6581a434, - 0x658da0ee, 0x65c1908c, 0x65be806f, 0x65ff0694, - 0x65ee2d2d, 0x65a3af81, 0x65a9cb3a, 0x65e1e9da, - 0x65f447ba, 0x65e17da6, 0x0401482b, 0x040279fb, - 0x0439323e, 0x04a33302, 0x046331bd, 0x04fc320e, - 0x05bb6964, 0x05e16e02, 0x65c897e7, 0x4596b150, - 0x4516b4fd, 0x0438396c, 0x041a280b, 0x04183697, - 0x04192de3, 0x04083b7e, 0x04ca3955, 0x65873883, - 0x658622a6, 0x65d83bd9, 0x0441303f, 0x0e2e11ac, - 0x4e2013fe, 0x0e6f11cd, 0x4e6a1128, 0x0ebb1359, - 0x4ebf13dd, 0x2e231041, 0x6e21101f, 0x2e791317, - 0x6e61101f, 0x2eb612b4, 0x6ea21020, + 0x4ead958b, 0x0e20cffe, 0x4e3dcf9b, 0x4e6bcd49, + 0x2e7b9759, 0x6e649462, 0x2eae95ac, 0x6eb39651, + 0x0ea0cffe, 0x4ea3cc41, 0x4eeecdac, 0x2e3effbc, + 0x6e22fc20, 0x6e73fe51, 0x0e2e65ac, 0x4e336651, + 0x0e7766d5, 0x4e6e65ac, 0x0ebd679b, 0x4ebf67dd, + 0x0e20a7fe, 0x4e23a441, 0x0e7ba759, 0x4e7da79b, + 0x0ea6a4a4, 0x4ebfa7dd, 0x0e25f483, 0x4e28f4e6, + 0x4e7ff7dd, 0x0e3b6f59, 0x4e336e51, 0x0e6a6d28, + 0x4e696d07, 0x0eae6dac, 0x4ea26c20, 0x0e35ae93, + 0x4e23ac41, 0x0e79af17, 0x4e64ac62, 0x0ea2ac20, + 0x4eaaad28, 0x0eb9f717, 0x4ebbf759, 0x4ef1f60f, + 0x2ebfefdd, 0x6ea5ec83, 0x6eeced6a, 0x0e3836f6, + 0x4e2c356a, 0x0e6634a4, 0x4e733651, 0x0ea33441, + 0x4ead358b, 0x4ee93507, 0x0e2c3d6a, 0x4e313e0f, + 0x0e723e30, 0x4e643c62, 0x0eab3d49, 0x4ead3d8b, + 0x4eee3dac, 0x2e308dee, 0x6e2f8dcd, 0x2e648c62, + 0x6e688ce6, 0x2eb58e93, 0x6ebb8f59, 0x6ef18e0f, + 0x2e2634a4, 0x6e243462, 0x2e6634a4, 0x6e6d358b, + 0x2eb33651, 0x6eb636b4, 0x6ef23630, 0x2e333e51, + 0x6e2c3d6a, 0x2e763eb4, 0x6e783ef6, 0x2eae3dac, + 0x6ebb3f59, 0x6ef93f17, 0x0e3ee7bc, 0x4e30e5ee, + 0x4e6ce56a, 0x2ebae738, 0x6ea3e441, 0x6eede58b, + 0x2e20e7fe, 0x6e2ce56a, 0x6e71e60f, 0x65922c43, + 0x65d02219, 0x65d02560, 0x65d13dc4, 0x65913690, + 0x65d33b6b, 0x2500948c, 0x254c08bf, 0x25831f87, + 0x254f30af, 0x259c3359, 0x25019d35, 0x24eac76d, + 0x2431993a, 0x242f7ed8, 0x24a2f62b, 0xba5fd3e3, + 0x3a5f03e5, 0xfa411be4, 0x7a42cbe2, 0x93df03ff, + 0xc820ffff, 0x8822fc7f, 0xc8247cbf, 0x88267fff, + 0x4e010fe0, 0x5e040420, 0x4e081fe1, 0x4e0c1fe1, + 0x4e0a1fe1, 0x4e071fe1, 0x4e042c20, 0x4e062c20, + 0x4e052c20, 0x4e083c20, 0x0e0c3c20, 0x0e0a3c20, + 0x0e073c20, 0x9eae0020, 0x0f03f409, 0x6f03f40e, + 0x4cc0ac3f, 0x0ea1b820, 0x4e21c862, 0x4e61b8a4, + 0x05a08020, 0x05104fe0, 0x05505001, 0x05906fe2, + 0x05d03005, 0x05101fea, 0x05901feb, 0x04b0e3e0, + 0x0470e7e1, 0x042f9c20, 0x043f9c35, 0x047f9c20, + 0x04ff9c20, 0x04299420, 0x04319160, 0x0461943e, + 0x04a19020, 0x04038100, 0x040381a0, 0x040387e1, + 0x04438be2, 0x04c38fe3, 0x040181e0, 0x04018100, + 0x04018621, 0x04418b22, 0x04418822, 0x04818c23, + 0x040081e0, 0x04008120, 0x04008761, 0x04008621, + 0x04408822, 0x04808c23, 0x042053ff, 0x047f5401, + 0x25208028, 0x2538cfe0, 0x2578d001, 0x25b8efe2, + 0x25f8f007, 0x2538dfea, 0x25b8dfeb, 0xa400a3e0, + 0xa420a7e0, 0xa4484be0, 0xa467afe0, 0xa4a8a7ea, + 0xa547a814, 0xa4084ffe, 0xa55c53e0, 0xa5e1540b, + 0xe400fbf6, 0xe408ffff, 0xe420e7e0, 0xe4484be0, + 0xe460efe0, 0xe547e400, 0xe4014be0, 0xe4a84fe0, + 0xe5f15000, 0x858043e0, 0x85a043ff, 0xe59f5d08, + 0x0420e3e9, 0x0460e3ea, 0x04a0e3eb, 0x04e0e3ec, + 0x25104042, 0x25104871, 0x25904861, 0x25904c92, + 0x05344020, 0x05744041, 0x05b44062, 0x05f44083, + 0x252c8840, 0x253c1420, 0x25681572, 0x25a21ce3, + 0x25ea1e34, 0x253c0421, 0x25680572, 0x25a20ce3, + 0x25ea0e34, 0x0522c020, 0x05e6c0a4, 0x2401a001, + 0x2443a051, 0x24858881, 0x24c78cd1, 0x24850891, + 0x24c70cc1, 0x250f9001, 0x25508051, 0x25802491, + 0x25df28c1, 0x25850c81, 0x251e10d1, 0x65816001, + 0x65c36051, 0x65854891, 0x65c74cc1, 0x05733820, + 0x05b238a4, 0x05f138e6, 0x0570396a, 0x65d0a001, + 0x65d6a443, 0x65d4a826, 0x6594ac26, 0x6554ac26, + 0x6556ac26, 0x6552ac26, 0x65cbac85, 0x65caac01, + 0x6589ac85, 0x6588ac01, 0x65c9ac85, 0x65c8ac01, + 0x65dea833, 0x659ca509, 0x65d8a801, 0x65dcac01, + 0x655cb241, 0x0520a1e0, 0x0521a601, 0x052281e0, + 0x05238601, 0x04a14026, 0x042244a6, 0x046344a6, + 0x04a444a6, 0x04e544a7, 0x0568aca7, 0x05b23230, + 0x853040af, 0xc5b040af, 0xe57080af, 0xe5b080af, + 0x25034440, 0x254054c4, 0x25034640, 0x25415a05, + 0x25834440, 0x25c54489, 0x250b5d3a, 0x2550dc20, + 0x2518e3e1, 0x2518e021, 0x2518e0a1, 0x2518e121, + 0x2518e1a1, 0x2558e3e2, 0x2558e042, 0x2558e0c2, + 0x2558e142, 0x2598e3e3, 0x2598e063, 0x2598e0e3, + 0x2598e163, 0x25d8e3e4, 0x25d8e084, 0x25d8e104, + 0x25d8e184, 0x2518e407, 0x05214800, 0x05614800, + 0x05a14800, 0x05e14800, 0x05214c00, 0x05614c00, + 0x05a14c00, 0x05e14c00, 0x05304001, 0x05314001, + 0x05a18610, 0x05e18610, 0x05271e11, 0x6545e891, + 0x6585e891, 0x65c5e891, 0x6545c891, 0x6585c891, + 0x65c5c891, 0x45b0c210, 0x45f1c231, 0x1e601000, + 0x1e603000, 0x1e621000, 0x1e623000, 0x1e641000, + 0x1e643000, 0x1e661000, 0x1e663000, 0x1e681000, + 0x1e683000, 0x1e6a1000, 0x1e6a3000, 0x1e6c1000, + 0x1e6c3000, 0x1e6e1000, 0x1e6e3000, 0x1e701000, + 0x1e703000, 0x1e721000, 0x1e723000, 0x1e741000, + 0x1e743000, 0x1e761000, 0x1e763000, 0x1e781000, + 0x1e783000, 0x1e7a1000, 0x1e7a3000, 0x1e7c1000, + 0x1e7c3000, 0x1e7e1000, 0x1e7e3000, 0xf82f8186, + 0xf83001ab, 0xf83713c1, 0xf8332225, 0xf82232d0, + 0xf82d52aa, 0xf83d419b, 0xf83b7023, 0xf83f6278, + 0xf8b18389, 0xf8bb00ef, 0xf8b513f7, 0xf8b923e2, + 0xf8bb3150, 0xf8b75073, 0xf8b04320, 0xf8ba7057, + 0xf8b0608c, 0xf8fc83be, 0xf8f000db, 0xf8e911fd, + 0xf8e720e4, 0xf8ef32e9, 0xf8e85382, 0xf8f540bf, + 0xf8fb7220, 0xf8ef6344, 0xf86882dc, 0xf87b033b, + 0xf8771080, 0xf8662010, 0xf864302f, 0xf86a50a7, + 0xf86a40fc, 0xf87472b7, 0xf866610b, 0xb83180df, + 0xb8310182, 0xb83e107d, 0xb83b23b6, 0xb82e338d, + 0xb83150b8, 0xb822414e, 0xb830736b, 0xb837608c, + 0xb8b68091, 0xb8a10213, 0xb8b011cd, 0xb8ac2222, + 0xb8a332f5, 0xb8a550e6, 0xb8b3438d, 0xb8b170d0, + 0xb8a2607d, 0xb8e481e6, 0xb8f4018d, 0xb8f41328, + 0xb8f42013, 0xb8eb30d8, 0xb8f451df, 0xb8f04006, + 0xb8e7726f, 0xb8fa6149, 0xb87782d5, 0xb87c0062, + 0xb86f1293, 0xb86723a4, 0xb8673120, 0xb87052f4, + 0xb8644150, 0xb877732b, 0xb866621f, 0xce2b06cd, + 0xce14410d, 0xce648df9, 0xce883624, 0xce7c809d, + 0xce7a87b0, 0xcec081c9, 0xce7c8962, 0x2520c143, + 0x25a1d2da, 0x058015ce, 0x05400ed8, 0x0500bb31, + 0x25a0c074, 0x25a1d884, 0x05804944, 0x0540b1d9, + 0x05001548, 0x25a0c49e, 0x2521cabe, 0x058054b3, + 0x0543ab47, 0x050026bb, 0x2560d097, 0x25a1d6fe, + 0x058394b4, 0x0540266d, 0x05003cbc, 0x25a0c1ab, + 0x2561d3f8, 0x05800acd, 0x05403684, 0x05000c07, + 0x2560de64, 0x2521cac5, 0x0583c8b5, 0x05405089, + 0x05003e98, 0x04ad0397, 0x04ac074a, 0x658e023e, + 0x65d50a1d, 0x65820667, 0x0496b13a, 0x04001411, + 0x041a19c2, 0x049095cb, 0x041b0c7d, 0x04d9a876, + 0x049aa27b, 0x04591aa7, 0x04138b25, 0x04119235, + 0x04500a63, 0x0497adc7, 0x04dea9b1, 0x04581e31, + 0x05a78f4f, 0x056494fb, 0x04481f65, 0x048a0f00, + 0x04810074, 0x04dca739, 0x65809031, 0x658d9dae, + 0x65c683d1, 0x658797b6, 0x65828008, 0x04ddb417, + 0x6582baf9, 0x6580b435, 0x65c1b56a, 0x65cdb917, + 0x65c19671, 0x65fe95a4, 0x65f11f3e, 0x65fc298e, + 0x65ada1a5, 0x65b3c967, 0x65e3ec59, 0x65f454a0, + 0x65a86dbc, 0x041b41dd, 0x04587903, 0x042a3321, + 0x04b93281, 0x0470327c, 0x04e131bb, 0x0521692b, + 0x057a6f61, 0x65c887a2, 0x45c2b058, 0x455cb723, + 0x043639a3, 0x045a309b, 0x0498305a, 0x04993ce1, + 0x04483e1e, 0x040a3395, 0x65c72595, 0x6586294b, + 0x65d826c0, 0x04412474, }; // END Generated code -- do not edit From e19c7d80f722395583fbdb4cc10dc9051c8602f2 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Mon, 30 Sep 2024 11:24:48 +0000 Subject: [PATCH 059/188] 8340874: Open source some of the AWT Geometry/Button tests Reviewed-by: prr --- .../BadActionEventTest.java | 93 +++++++++++++ .../jdk/java/awt/geom/Arc2D/Arc2DHitTest.java | 100 ++++++++++++++ test/jdk/java/awt/geom/Arc2D/BoundsBug.java | 123 ++++++++++++++++++ test/jdk/java/awt/geom/Area/Translate.java | 122 +++++++++++++++++ 4 files changed, 438 insertions(+) create mode 100644 test/jdk/java/awt/Button/BadActionEventTest/BadActionEventTest.java create mode 100644 test/jdk/java/awt/geom/Arc2D/Arc2DHitTest.java create mode 100644 test/jdk/java/awt/geom/Arc2D/BoundsBug.java create mode 100644 test/jdk/java/awt/geom/Area/Translate.java diff --git a/test/jdk/java/awt/Button/BadActionEventTest/BadActionEventTest.java b/test/jdk/java/awt/Button/BadActionEventTest/BadActionEventTest.java new file mode 100644 index 0000000000000..53aac7ab78751 --- /dev/null +++ b/test/jdk/java/awt/Button/BadActionEventTest/BadActionEventTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4530087 + * @summary Test if double-clicking causes ActionEvent on underlying button + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BadActionEventTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class BadActionEventTest implements ActionListener { + private static Button showBtn; + private static Button listBtn; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1) Click on 'Show File Dialog' to bring up the FileDialog window. + (If necessary, change to a directory with files (not just directories) in it.) + 2) Move the FileDialog so that one of the file names (again, a file, NOT a directory) in the list is + directly over the 'ActionListener' button. + 3) Double-click on the file name over the button. The FileDialog will disappear. + 4) If the 'ActionListener' button receives an ActionEvent, the test fails and a + message to that effect will be printed. + Otherwise, the test passes. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(BadActionEventTest::createUI) + .logArea(2) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame("BadActionEventTest"); + frame.setLayout(new GridLayout(1, 2)); + frame.setSize(400, 200); + showBtn = new Button("Show File Dialog"); + listBtn = new Button("ActionListener"); + showBtn.setSize(200, 200); + listBtn.setSize(200, 200); + showBtn.addActionListener(new BadActionEventTest()); + listBtn.addActionListener(new BadActionEventTest()); + frame.add(showBtn); + frame.add(listBtn); + return frame; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == showBtn) { + FileDialog fd = new FileDialog(new Frame()); + fd.setVisible(true); + } else if (e.getSource() == listBtn) { + listBtn.setBackground(Color.red); + listBtn.setLabel("TEST FAILS!"); + PassFailJFrame.log("*TEST FAILS!* ActionListener got ActionEvent! *TEST FAILS!*"); + } + } +} diff --git a/test/jdk/java/awt/geom/Arc2D/Arc2DHitTest.java b/test/jdk/java/awt/geom/Arc2D/Arc2DHitTest.java new file mode 100644 index 0000000000000..de6b39d5c6f7f --- /dev/null +++ b/test/jdk/java/awt/geom/Arc2D/Arc2DHitTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4178123 + * @summary Verifies that the Arc2D.contains(point) methods work correctly. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual Arc2DHitTest + */ + +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.Arc2D; + +public class Arc2DHitTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test displays an arc figure and lets the user click on it. + The arc will initially be drawn in red and only when the user clicks + within the arc in the window it will be redrawn into green otherwise + it should stay red. + + For convenience, the point being tested is drawn in black. Note + that rounding in the arc rendering routines may cause points near + the boundary of the arc to render incorrectly. Allow for a pixel + or two of leeway near the boundary. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + private static Frame initialize() { + Frame f = new Frame("Arc2DHitTest"); + ArcHitPanel panel = new ArcHitPanel(); + f.add(panel); + f.setSize(300, 250); + return f; + } +} + +class ArcHitPanel extends Panel { + private Arc2D arc; + private Point hit; + public ArcHitPanel() { + arc = new Arc2D.Float(10, 10, 100, 100, 0, 120, Arc2D.PIE); + this.addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + hit = e.getPoint(); + repaint(); + } + }); + } + + @Override + public void paint(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + g2.setColor(Color.white); + g2.fill(g2.getClipBounds()); + g2.setColor((hit != null && arc.contains(hit)) + ? Color.green : Color.red); + g2.fill(arc); + if (hit != null) { + g2.setColor(Color.black); + g2.fillRect(hit.x, hit.y, 1, 1); + } + } +} diff --git a/test/jdk/java/awt/geom/Arc2D/BoundsBug.java b/test/jdk/java/awt/geom/Arc2D/BoundsBug.java new file mode 100644 index 0000000000000..a17f45f9dad37 --- /dev/null +++ b/test/jdk/java/awt/geom/Arc2D/BoundsBug.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4197746 + * @summary Verifies that the getBounds2D method of Arc2D returns the + * correct result. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BoundsBug + */ + +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.Arc2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +public class BoundsBug { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test displays three figures and draws the outline of their + bounding boxes. The bounding boxes should correctly encompass + the 3 figures. + + This test also paints two highlight rectangles at the ends of the + angular extents of the arc. The two highlights should correctly + appear at the outer circumference of the arc where the radii lines + from its center intersect that circumference. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + private static Frame initialize() { + Frame f = new Frame("BoundsBug"); + ArcPanel panel = new ArcPanel(); + f.add(panel); + f.setSize(300, 250); + return f; + } +} + +class ArcPanel extends Panel { + protected void drawPoint(Graphics2D g2, Point2D p) { + g2.setColor(Color.green); + g2.fill(new Rectangle2D.Double(p.getX() - 5, p.getY() - 5, 10, 10)); + } + + protected void drawShapeAndBounds(Graphics2D g2, Shape s) { + g2.setColor(Color.orange); + g2.fill(s); + g2.setColor(Color.black); + g2.draw(s); + + Rectangle2D r = s.getBounds2D(); + g2.setColor(Color.gray); + g2.draw(r); + } + + @Override + public void paint(Graphics g) { + Graphics2D g2 = (Graphics2D)g; + g2.setColor(Color.white); + g2.fill(g.getClipBounds()); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + // Create some interesting shapes. + Ellipse2D ellipse = new Ellipse2D.Float(20, 40, 60, 80); + Arc2D arc = new Arc2D.Float(60, 40, 100, 120, + -30, -40, Arc2D.PIE); + GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD); + path.moveTo(0, 0); + path.lineTo(75, -25); + path.lineTo(25, 75); + path.lineTo(0, 25); + path.lineTo(100, 50); + path.lineTo(50, 0); + path.lineTo(25, 50); + path.closePath(); + // Now draw them and their bounds rectangles. + drawShapeAndBounds(g2, ellipse); + drawShapeAndBounds(g2, arc); + drawPoint(g2, arc.getStartPoint()); + drawPoint(g2, arc.getEndPoint()); + g2.translate(180, 65); + drawShapeAndBounds(g2, path); + } +} diff --git a/test/jdk/java/awt/geom/Area/Translate.java b/test/jdk/java/awt/geom/Area/Translate.java new file mode 100644 index 0000000000000..7519f1753bcf3 --- /dev/null +++ b/test/jdk/java/awt/geom/Area/Translate.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4183373 + * @summary Verifies that the translated Area objects display correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual Translate + */ + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Rectangle2D; + +public class Translate { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test displays two sets of rectangular figures. The two sets + should be displayed one on top of the other and should be lined + up vertically with each other. If the two sets of figures are + not directly above and below each other then the test fails + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + private static Frame initialize() { + Frame f = new Frame("Translate"); + TranslatePanel panel = new TranslatePanel(); + f.add(panel); + f.setSize(300, 250); + return f; + } +} + +class TranslatePanel extends Panel { + private static Image bufferedImage; + private static Area a1, a2, a3; + + public TranslatePanel() { + a1 = new Area(new Rectangle2D.Double(20.0, 20.0, 60.0, 60.0)); + + a2 = new Area((Area) a1.clone()); + a2.subtract(new Area(new Rectangle2D.Double(30.0, 30.0, 40.0, 40.0))); + + a3 = new Area((Area) a2.clone()); + a3.add(new Area(new Rectangle2D.Double(40.0, 40.0, 20.0, 20.0))); + + AffineTransform at2 = new AffineTransform(); + at2.translate(100.0, 0.0); + a2.transform(at2); + + AffineTransform at3 = new AffineTransform(); + at3.translate(200.0, 0.0); + a3.transform(at3); + } + private void paintRects(Graphics2D g2) { + Rectangle clip = g2.getClipBounds(); + g2.setColor(Color.white); + g2.fillRect(clip.x, clip.y, clip.width, clip.height); + g2.setPaint(Color.red); + g2.fill(a1); + g2.setPaint(Color.yellow); + g2.fill(a2); + g2.setPaint(Color.blue); + g2.fill(a3); + } + + @Override + public void paint(Graphics g) { + if (bufferedImage == null) { + bufferedImage = createImage(300, 100); + Graphics big = bufferedImage.getGraphics(); + // Notice that if you remove the translate() call, it works fine. + big.translate(-1, -1); + big.setClip(1, 1, 300, 100); + paintRects((Graphics2D)big); + big.translate(1, 1); + } + paintRects((Graphics2D)g); + g.drawImage(bufferedImage, 1, 100, this); + g.setColor(Color.black); + g.drawString("From offscreen image (with translate):", 10, 95); + g.drawString(" (should line up with rectangles above)", 10, 110); + } +} From 180affc5718c9bf2f009d6a7aa129cc36335384a Mon Sep 17 00:00:00 2001 From: Fredrik Bredberg Date: Mon, 30 Sep 2024 12:28:35 +0000 Subject: [PATCH 060/188] 8320318: ObjectMonitor Responsible thread Reviewed-by: aboldtch, coleenp, pchilanomate, eosterlund --- .../cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 72 +++- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 61 +++- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 62 +++- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 74 +++- src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp | 56 +-- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 133 +++---- src/hotspot/share/opto/c2_CodeStubs.hpp | 2 - src/hotspot/share/runtime/javaThread.cpp | 1 + src/hotspot/share/runtime/javaThread.hpp | 8 + src/hotspot/share/runtime/objectMonitor.cpp | 335 +++++++----------- src/hotspot/share/runtime/objectMonitor.hpp | 9 +- .../share/runtime/objectMonitor.inline.hpp | 19 +- src/hotspot/share/runtime/sharedRuntime.cpp | 20 ++ .../org/openjdk/bench/vm/lang/LockUnlock.java | 7 +- 14 files changed, 438 insertions(+), 421 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index b4c12ecd4a849..62831ee72ba05 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -150,10 +150,12 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Registe Register oop = objectReg; Register box = boxReg; Register disp_hdr = tmpReg; + Register owner_addr = tmpReg; Register tmp = tmp2Reg; Label cont; Label object_has_monitor; Label count, no_count; + Label unlocked; assert(LockingMode != LM_LIGHTWEIGHT, "lightweight locking should use fast_unlock_lightweight"); assert_different_registers(oop, box, tmp, disp_hdr); @@ -204,14 +206,40 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Registe b(cont); bind(notRecursive); + + // Compute owner address. + lea(owner_addr, Address(tmp, ObjectMonitor::owner_offset())); + + // Set owner to null. + // Release to satisfy the JMM + stlr(zr, owner_addr); + // We need a full fence after clearing owner to avoid stranding. + // StoreLoad achieves this. + membar(StoreLoad); + + // Check if the entry lists are empty. ldr(rscratch1, Address(tmp, ObjectMonitor::EntryList_offset())); - ldr(disp_hdr, Address(tmp, ObjectMonitor::cxq_offset())); - orr(rscratch1, rscratch1, disp_hdr); // Will be 0 if both are 0. - cmp(rscratch1, zr); // Sets flags for result - cbnz(rscratch1, cont); - // need a release store here - lea(tmp, Address(tmp, ObjectMonitor::owner_offset())); - stlr(zr, tmp); // set unowned + ldr(tmpReg, Address(tmp, ObjectMonitor::cxq_offset())); + orr(rscratch1, rscratch1, tmpReg); + cmp(rscratch1, zr); + br(Assembler::EQ, cont); // If so we are done. + + // Check if there is a successor. + ldr(rscratch1, Address(tmp, ObjectMonitor::succ_offset())); + cmp(rscratch1, zr); + br(Assembler::NE, unlocked); // If so we are done. + + // Save the monitor pointer in the current thread, so we can try to + // reacquire the lock in SharedRuntime::monitor_exit_helper(). + str(tmp, Address(rthread, JavaThread::unlocked_inflated_monitor_offset())); + + cmp(zr, rthread); // Set Flag to NE => slow path + b(cont); + + bind(unlocked); + cmp(zr, zr); // Set Flag to EQ => fast path + + // Intentional fall-through bind(cont); // flag == EQ indicates success @@ -498,33 +526,41 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Regi bind(not_recursive); - Label release; const Register t2_owner_addr = t2; // Compute owner address. lea(t2_owner_addr, Address(t1_monitor, ObjectMonitor::owner_offset())); + // Set owner to null. + // Release to satisfy the JMM + stlr(zr, t2_owner_addr); + // We need a full fence after clearing owner to avoid stranding. + // StoreLoad achieves this. + membar(StoreLoad); + // Check if the entry lists are empty. ldr(rscratch1, Address(t1_monitor, ObjectMonitor::EntryList_offset())); ldr(t3_t, Address(t1_monitor, ObjectMonitor::cxq_offset())); orr(rscratch1, rscratch1, t3_t); cmp(rscratch1, zr); - br(Assembler::EQ, release); + br(Assembler::EQ, unlocked); // If so we are done. - // The owner may be anonymous and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - str(rthread, Address(t2_owner_addr)); - b(slow_path); + // Check if there is a successor. + ldr(rscratch1, Address(t1_monitor, ObjectMonitor::succ_offset())); + cmp(rscratch1, zr); + br(Assembler::NE, unlocked); // If so we are done. - bind(release); - // Set owner to null. - // Release to satisfy the JMM - stlr(zr, t2_owner_addr); + // Save the monitor pointer in the current thread, so we can try to + // reacquire the lock in SharedRuntime::monitor_exit_helper(). + str(t1_monitor, Address(rthread, JavaThread::unlocked_inflated_monitor_offset())); + + cmp(zr, rthread); // Set Flag to NE => slow path + b(slow_path); } bind(unlocked); decrement(Address(rthread, JavaThread::held_monitor_count_offset())); + cmp(zr, zr); // Set Flags to EQ => fast path #ifdef ASSERT // Check that unlocked label is reached with Flags == EQ. diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index a8635af9582d1..8d8e39b8bbc00 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2715,13 +2715,34 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe b(success); bind(notRecursive); + + // Set owner to null. + // Release to satisfy the JMM + release(); + li(temp, 0); + std(temp, in_bytes(ObjectMonitor::owner_offset()), current_header); + // We need a full fence after clearing owner to avoid stranding. + // StoreLoad achieves this. + membar(StoreLoad); + + // Check if the entry lists are empty. ld(temp, in_bytes(ObjectMonitor::EntryList_offset()), current_header); ld(displaced_header, in_bytes(ObjectMonitor::cxq_offset()), current_header); orr(temp, temp, displaced_header); // Will be 0 if both are 0. cmpdi(flag, temp, 0); - bne(flag, failure); - release(); - std(temp, in_bytes(ObjectMonitor::owner_offset()), current_header); + beq(flag, success); // If so we are done. + + // Check if there is a successor. + ld(temp, in_bytes(ObjectMonitor::succ_offset()), current_header); + cmpdi(flag, temp, 0); + bne(flag, success); // If so we are done. + + // Save the monitor pointer in the current thread, so we can try + // to reacquire the lock in SharedRuntime::monitor_exit_helper(). + std(current_header, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread); + + crxor(flag, Assembler::equal, flag, Assembler::equal); // Set flag = NE => slow path + b(failure); // flag == EQ indicates success, decrement held monitor count // flag == NE indicates failure @@ -3028,27 +3049,39 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f bind(not_recursive); - Label release_; + Label set_eq_unlocked; const Register t2 = tmp2; + // Set owner to null. + // Release to satisfy the JMM + release(); + li(t, 0); + std(t, in_bytes(ObjectMonitor::owner_offset()), monitor); + // We need a full fence after clearing owner to avoid stranding. + // StoreLoad achieves this. + membar(StoreLoad); + // Check if the entry lists are empty. ld(t, in_bytes(ObjectMonitor::EntryList_offset()), monitor); ld(t2, in_bytes(ObjectMonitor::cxq_offset()), monitor); orr(t, t, t2); cmpdi(CCR0, t, 0); - beq(CCR0, release_); + beq(CCR0, unlocked); // If so we are done. - // The owner may be anonymous and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - std(R16_thread, in_bytes(ObjectMonitor::owner_offset()), monitor); + // Check if there is a successor. + ld(t, in_bytes(ObjectMonitor::succ_offset()), monitor); + cmpdi(CCR0, t, 0); + bne(CCR0, set_eq_unlocked); // If so we are done. + + // Save the monitor pointer in the current thread, so we can try + // to reacquire the lock in SharedRuntime::monitor_exit_helper(). + std(monitor, in_bytes(JavaThread::unlocked_inflated_monitor_offset()), R16_thread); + + crxor(CCR0, Assembler::equal, CCR0, Assembler::equal); // Set flag = NE => slow path b(slow_path); - bind(release_); - // Set owner to null. - release(); - // t contains 0 - std(t, in_bytes(ObjectMonitor::owner_offset()), monitor); + bind(set_eq_unlocked); + crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); // Set flag = EQ => fast path } bind(unlocked); diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index e2c9b9dd609e0..75f87e35adf41 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -165,6 +165,7 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, Register oop = objectReg; Register box = boxReg; Register disp_hdr = tmp1Reg; + Register owner_addr = tmp1Reg; Register tmp = tmp2Reg; Label object_has_monitor; // Finish fast lock successfully. MUST branch to with flag == 0 @@ -222,15 +223,33 @@ void C2_MacroAssembler::fast_unlock(Register objectReg, Register boxReg, j(unlocked); bind(notRecursive); - ld(t0, Address(tmp, ObjectMonitor::EntryList_offset())); - ld(disp_hdr, Address(tmp, ObjectMonitor::cxq_offset())); - orr(t0, t0, disp_hdr); // Will be 0 if both are 0. - bnez(t0, slow_path); + // Compute owner address. + la(owner_addr, Address(tmp, ObjectMonitor::owner_offset())); - // need a release store here - la(tmp, Address(tmp, ObjectMonitor::owner_offset())); + // Set owner to null. + // Release to satisfy the JMM membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - sd(zr, Address(tmp)); // set unowned + sd(zr, Address(owner_addr)); + // We need a full fence after clearing owner to avoid stranding. + // StoreLoad achieves this. + membar(StoreLoad); + + // Check if the entry lists are empty. + ld(t0, Address(tmp, ObjectMonitor::EntryList_offset())); + ld(tmp1Reg, Address(tmp, ObjectMonitor::cxq_offset())); + orr(t0, t0, tmp1Reg); + beqz(t0, unlocked); // If so we are done. + + // Check if there is a successor. + ld(t0, Address(tmp, ObjectMonitor::succ_offset())); + bnez(t0, unlocked); // If so we are done. + + // Save the monitor pointer in the current thread, so we can try to + // reacquire the lock in SharedRuntime::monitor_exit_helper(). + sd(tmp, Address(xthread, JavaThread::unlocked_inflated_monitor_offset())); + + mv(flag, 1); + j(slow_path); bind(unlocked); mv(flag, zr); @@ -534,28 +553,35 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, bind(not_recursive); - Label release; const Register tmp2_owner_addr = tmp2; // Compute owner address. la(tmp2_owner_addr, Address(tmp1_monitor, ObjectMonitor::owner_offset())); + // Set owner to null. + // Release to satisfy the JMM + membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + sd(zr, Address(tmp2_owner_addr)); + // We need a full fence after clearing owner to avoid stranding. + // StoreLoad achieves this. + membar(StoreLoad); + // Check if the entry lists are empty. ld(t0, Address(tmp1_monitor, ObjectMonitor::EntryList_offset())); ld(tmp3_t, Address(tmp1_monitor, ObjectMonitor::cxq_offset())); orr(t0, t0, tmp3_t); - beqz(t0, release); + beqz(t0, unlocked); // If so we are done. - // The owner may be anonymous and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - sd(xthread, Address(tmp2_owner_addr)); - j(slow_path); + // Check if there is a successor. + ld(tmp3_t, Address(tmp1_monitor, ObjectMonitor::succ_offset())); + bnez(tmp3_t, unlocked); // If so we are done. - bind(release); - // Set owner to null. - membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); - sd(zr, Address(tmp2_owner_addr)); + // Save the monitor pointer in the current thread, so we can try + // to reacquire the lock in SharedRuntime::monitor_exit_helper(). + sd(tmp1_monitor, Address(xthread, JavaThread::unlocked_inflated_monitor_offset())); + + mv(flag, 1); + j(slow_path); } bind(unlocked); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 6c26e17d5ce3b..af281345b1477 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -3655,12 +3655,38 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg bind(not_recursive); + NearLabel check_succ, set_eq_unlocked; + + // Set owner to null. + // Release to satisfy the JMM + z_release(); + z_lghi(temp, 0); + z_stg(temp, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), currentHeader); + // We need a full fence after clearing owner to avoid stranding. + z_fence(); + + // Check if the entry lists are empty. load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); - z_brne(done); + z_brne(check_succ); load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - z_brne(done); - z_release(); - z_stg(temp/*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), currentHeader); + z_bre(done); // If so we are done. + + bind(check_succ); + + // Check if there is a successor. + load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ))); + z_brne(set_eq_unlocked); // If so we are done. + + // Save the monitor pointer in the current thread, so we can try to + // reacquire the lock in SharedRuntime::monitor_exit_helper(). + z_xilf(currentHeader, markWord::monitor_value); + z_stg(currentHeader, Address(Z_thread, JavaThread::unlocked_inflated_monitor_offset())); + + z_ltgr(oop, oop); // Set flag = NE + z_bru(done); + + bind(set_eq_unlocked); + z_cr(temp, temp); // Set flag = EQ bind(done); @@ -6454,6 +6480,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag}; const Address cxq_address{monitor, ObjectMonitor::cxq_offset() - monitor_tag}; + const Address succ_address{monitor, ObjectMonitor::succ_offset() - monitor_tag}; const Address EntryList_address{monitor, ObjectMonitor::EntryList_offset() - monitor_tag}; const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag}; @@ -6471,25 +6498,40 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis bind(not_recursive); - NearLabel not_ok; + NearLabel check_succ, set_eq_unlocked; + + // Set owner to null. + // Release to satisfy the JMM + z_release(); + z_lghi(tmp2, 0); + z_stg(tmp2 /*=0*/, owner_address); + // We need a full fence after clearing owner to avoid stranding. + z_fence(); + // Check if the entry lists are empty. load_and_test_long(tmp2, EntryList_address); - z_brne(not_ok); + z_brne(check_succ); load_and_test_long(tmp2, cxq_address); - z_brne(not_ok); + z_bre(unlocked); // If so we are done. - z_release(); - z_stg(tmp2 /*=0*/, owner_address); + bind(check_succ); - z_bru(unlocked); // CC = EQ here + // Check if there is a successor. + load_and_test_long(tmp2, succ_address); + z_brne(set_eq_unlocked); // If so we are done. - bind(not_ok); + // Save the monitor pointer in the current thread, so we can try to + // reacquire the lock in SharedRuntime::monitor_exit_helper(). + if (!UseObjectMonitorTable) { + z_xilf(monitor, markWord::monitor_value); + } + z_stg(monitor, Address(Z_thread, JavaThread::unlocked_inflated_monitor_offset())); + + z_ltgr(obj, obj); // Set flag = NE + z_bru(slow_path); - // The owner may be anonymous, and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - z_stg(Z_thread, owner_address); - z_bru(slow_path); // CC = NE here + bind(set_eq_unlocked); + z_cr(tmp2, tmp2); // Set flag = EQ } bind(unlocked); diff --git a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp index 1990488d8a0df..44f897529e7ce 100644 --- a/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c2_CodeStubs_x86.cpp @@ -80,8 +80,6 @@ int C2FastUnlockLightweightStub::max_size() const { void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) { assert(_t == rax, "must be"); - Label restore_held_monitor_count_and_slow_path; - { // Restore lock-stack and handle the unlock in runtime. __ bind(_push_and_slow_path); @@ -91,61 +89,9 @@ void C2FastUnlockLightweightStub::emit(C2_MacroAssembler& masm) { __ movptr(Address(_thread, _t), _obj); #endif __ addl(Address(_thread, JavaThread::lock_stack_top_offset()), oopSize); - } - - { // Restore held monitor count and slow path. - - __ bind(restore_held_monitor_count_and_slow_path); - __ bind(_slow_path); - // Restore held monitor count. - __ increment(Address(_thread, JavaThread::held_monitor_count_offset())); - // increment will always result in ZF = 0 (no overflows). + // addl will always result in ZF = 0 (no overflows). __ jmp(slow_path_continuation()); } - - { // Handle monitor medium path. - - __ bind(_check_successor); - - Label fix_zf_and_unlocked; - const Register monitor = _mark; - -#ifndef _LP64 - __ jmpb(restore_held_monitor_count_and_slow_path); -#else // _LP64 - const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); - const Address succ_address(monitor, ObjectMonitor::succ_offset() - monitor_tag); - const Address owner_address(monitor, ObjectMonitor::owner_offset() - monitor_tag); - - // successor null check. - __ cmpptr(succ_address, NULL_WORD); - __ jccb(Assembler::equal, restore_held_monitor_count_and_slow_path); - - // Release lock. - __ movptr(owner_address, NULL_WORD); - - // Fence. - // Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack. - __ lock(); __ addl(Address(rsp, 0), 0); - - // Recheck successor. - __ cmpptr(succ_address, NULL_WORD); - // Observed a successor after the release -> fence we have handed off the monitor - __ jccb(Assembler::notEqual, fix_zf_and_unlocked); - - // Try to relock, if it fails the monitor has been handed over - // TODO: Caveat, this may fail due to deflation, which does - // not handle the monitor handoff. Currently only works - // due to the responsible thread. - __ xorptr(rax, rax); - __ lock(); __ cmpxchgptr(_thread, owner_address); - __ jccb (Assembler::equal, restore_held_monitor_count_and_slow_path); -#endif - - __ bind(fix_zf_and_unlocked); - __ xorl(rax, rax); - __ jmp(unlocked_continuation()); - } } #undef __ diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index c2801a791cb5a..839745f76ec6a 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -459,87 +459,43 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t // IA32's memory-model is SPO, so STs are ordered with respect to // each other and there's no need for an explicit barrier (fence). // See also http://gee.cs.oswego.edu/dl/jmm/cookbook.html. -#ifndef _LP64 - // Note that we could employ various encoding schemes to reduce - // the number of loads below (currently 4) to just 2 or 3. - // Refer to the comments in synchronizer.cpp. - // In practice the chain of fetches doesn't seem to impact performance, however. - xorptr(boxReg, boxReg); - orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - jccb (Assembler::notZero, DONE_LABEL); - movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); - orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - jccb (Assembler::notZero, DONE_LABEL); - movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); - jmpb (DONE_LABEL); -#else // _LP64 - // It's inflated - Label CheckSucc, LNotRecursive, LSuccess, LGoSlowPath; + Label LSuccess, LNotRecursive; cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 0); jccb(Assembler::equal, LNotRecursive); // Recursive inflated unlock - decq(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + decrement(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); jmpb(LSuccess); bind(LNotRecursive); - movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); - jccb (Assembler::notZero, CheckSucc); - // Without cast to int32_t this style of movptr will destroy r10 which is typically obj. + + // Set owner to null. + // Release to satisfy the JMM movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); - jmpb (DONE_LABEL); + // We need a full fence after clearing owner to avoid stranding. + // StoreLoad achieves this. + membar(StoreLoad); - // Try to avoid passing control into the slow_path ... - bind (CheckSucc); + // Check if the entry lists are empty. + movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); + orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); + jccb(Assembler::zero, LSuccess); // If so we are done. - // The following optional optimization can be elided if necessary - // Effectively: if (succ == null) goto slow path - // The code reduces the window for a race, however, - // and thus benefits performance. + // Check if there is a successor. cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD); - jccb (Assembler::zero, LGoSlowPath); - - xorptr(boxReg, boxReg); - // Without cast to int32_t this style of movptr will destroy r10 which is typically obj. - movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), NULL_WORD); + jccb(Assembler::notZero, LSuccess); // If so we are done. - // Memory barrier/fence - // Dekker pivot point -- fulcrum : ST Owner; MEMBAR; LD Succ - // Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack. - // This is faster on Nehalem and AMD Shanghai/Barcelona. - // See https://blogs.oracle.com/dave/entry/instruction_selection_for_volatile_fences - // We might also restructure (ST Owner=0;barrier;LD _Succ) to - // (mov box,0; xchgq box, &m->Owner; LD _succ) . - lock(); addl(Address(rsp, 0), 0); + // Save the monitor pointer in the current thread, so we can try to + // reacquire the lock in SharedRuntime::monitor_exit_helper(). + andptr(tmpReg, ~(int32_t)markWord::monitor_value); +#ifndef _LP64 + get_thread(boxReg); + movptr(Address(boxReg, JavaThread::unlocked_inflated_monitor_offset()), tmpReg); +#else // _LP64 + movptr(Address(r15_thread, JavaThread::unlocked_inflated_monitor_offset()), tmpReg); +#endif - cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), NULL_WORD); - jccb (Assembler::notZero, LSuccess); - - // Rare inopportune interleaving - race. - // The successor vanished in the small window above. - // The lock is contended -- (cxq|EntryList) != null -- and there's no apparent successor. - // We need to ensure progress and succession. - // Try to reacquire the lock. - // If that fails then the new owner is responsible for succession and this - // thread needs to take no further action and can exit via the fast path (success). - // If the re-acquire succeeds then pass control into the slow path. - // As implemented, this latter mode is horrible because we generated more - // coherence traffic on the lock *and* artificially extended the critical section - // length while by virtue of passing control into the slow path. - - // box is really RAX -- the following CMPXCHG depends on that binding - // cmpxchg R,[M] is equivalent to rax = CAS(M,rax,R) - lock(); - cmpxchgptr(r15_thread, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); - // There's no successor so we tried to regrab the lock. - // If that didn't work, then another thread grabbed the - // lock so we're done (and exit was a success). - jccb (Assembler::notEqual, LSuccess); - // Intentional fall-through into slow path - - bind (LGoSlowPath); orl (boxReg, 1); // set ICC.ZF=0 to indicate failure jmpb (DONE_LABEL); @@ -547,7 +503,6 @@ void C2_MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register t testl (boxReg, 0); // set ICC.ZF=1 to indicate success jmpb (DONE_LABEL); -#endif if (LockingMode == LM_LEGACY) { bind (Stacked); movptr(tmpReg, Address (boxReg, 0)); // re-fetch @@ -744,10 +699,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, // Handle inflated monitor. Label inflated, inflated_check_lock_stack; // Finish fast unlock successfully. MUST jump with ZF == 1 - Label unlocked; - - // Assume success. - decrement(Address(thread, JavaThread::held_monitor_count_offset())); + Label unlocked, slow_path; const Register mark = t; const Register monitor = t; @@ -763,8 +715,6 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, } Label& push_and_slow_path = stub == nullptr ? dummy : stub->push_and_slow_path(); - Label& check_successor = stub == nullptr ? dummy : stub->check_successor(); - Label& slow_path = stub == nullptr ? dummy : stub->slow_path(); { // Lightweight Unlock @@ -839,6 +789,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag}; const Address cxq_address{monitor, ObjectMonitor::cxq_offset() - monitor_tag}; + const Address succ_address{monitor, ObjectMonitor::succ_offset() - monitor_tag}; const Address EntryList_address{monitor, ObjectMonitor::EntryList_offset() - monitor_tag}; const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag}; @@ -846,27 +797,42 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, // Check if recursive. cmpptr(recursions_address, 0); - jccb(Assembler::notEqual, recursive); + jccb(Assembler::notZero, recursive); + + // Set owner to null. + // Release to satisfy the JMM + movptr(owner_address, NULL_WORD); + // We need a full fence after clearing owner to avoid stranding. + // StoreLoad achieves this. + membar(StoreLoad); // Check if the entry lists are empty. movptr(reg_rax, cxq_address); orptr(reg_rax, EntryList_address); - jcc(Assembler::notZero, check_successor); + jccb(Assembler::zero, unlocked); // If so we are done. - // Release lock. - movptr(owner_address, NULL_WORD); - jmpb(unlocked); + // Check if there is a successor. + cmpptr(succ_address, NULL_WORD); + jccb(Assembler::notZero, unlocked); // If so we are done. + + // Save the monitor pointer in the current thread, so we can try to + // reacquire the lock in SharedRuntime::monitor_exit_helper(). + if (!UseObjectMonitorTable) { + andptr(monitor, ~(int32_t)markWord::monitor_value); + } + movptr(Address(thread, JavaThread::unlocked_inflated_monitor_offset()), monitor); + + testl(monitor, monitor); // Fast Unlock ZF = 0 + jmpb(slow_path); // Recursive unlock. bind(recursive); decrement(recursions_address); - xorl(t, t); } bind(unlocked); - if (stub != nullptr) { - bind(stub->unlocked_continuation()); - } + decrement(Address(thread, JavaThread::held_monitor_count_offset())); + xorl(t, t); // Fast Unlock ZF = 1 #ifdef ASSERT // Check that unlocked label is reached with ZF set. @@ -875,6 +841,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, stop("Fast Unlock ZF != 1"); #endif + bind(slow_path); if (stub != nullptr) { bind(stub->slow_path_continuation()); } diff --git a/src/hotspot/share/opto/c2_CodeStubs.hpp b/src/hotspot/share/opto/c2_CodeStubs.hpp index 5db7596e072dc..318bc2f45fc76 100644 --- a/src/hotspot/share/opto/c2_CodeStubs.hpp +++ b/src/hotspot/share/opto/c2_CodeStubs.hpp @@ -105,7 +105,6 @@ class C2FastUnlockLightweightStub : public C2CodeStub { Register _thread; Label _slow_path; Label _push_and_slow_path; - Label _check_successor; Label _unlocked_continuation; public: C2FastUnlockLightweightStub(Register obj, Register mark, Register t, Register thread) : C2CodeStub(), @@ -114,7 +113,6 @@ class C2FastUnlockLightweightStub : public C2CodeStub { void emit(C2_MacroAssembler& masm); Label& slow_path() { return _slow_path; } Label& push_and_slow_path() { return _push_and_slow_path; } - Label& check_successor() { return _check_successor; } Label& unlocked_continuation() { return _unlocked_continuation; } Label& slow_path_continuation() { return continuation(); } }; diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 3528fc5b1bced..14528f6d908fc 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -487,6 +487,7 @@ JavaThread::JavaThread(MemTag mem_tag) : _cont_fastpath_thread_state(1), _held_monitor_count(0), _jni_monitor_count(0), + _unlocked_inflated_monitor(nullptr), _handshake(this), diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index e36b7dfe888a8..20bb08a4acbca 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -464,6 +464,7 @@ class JavaThread: public Thread { // It's signed for error detection. intx _held_monitor_count; // used by continuations for fast lock detection intx _jni_monitor_count; + ObjectMonitor* _unlocked_inflated_monitor; private: @@ -615,6 +616,12 @@ class JavaThread: public Thread { intx jni_monitor_count() { return _jni_monitor_count; } void clear_jni_monitor_count() { _jni_monitor_count = 0; } + // Support for SharedRuntime::monitor_exit_helper() + ObjectMonitor* unlocked_inflated_monitor() const { return _unlocked_inflated_monitor; } + void clear_unlocked_inflated_monitor() { + _unlocked_inflated_monitor = nullptr; + } + inline bool is_vthread_mounted() const; inline const ContinuationEntry* vthread_continuation() const; @@ -828,6 +835,7 @@ class JavaThread: public Thread { static ByteSize cont_fastpath_offset() { return byte_offset_of(JavaThread, _cont_fastpath); } static ByteSize held_monitor_count_offset() { return byte_offset_of(JavaThread, _held_monitor_count); } static ByteSize jni_monitor_count_offset() { return byte_offset_of(JavaThread, _jni_monitor_count); } + static ByteSize unlocked_inflated_monitor_offset() { return byte_offset_of(JavaThread, _unlocked_inflated_monitor); } #if INCLUDE_JVMTI static ByteSize is_in_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_VTMS_transition); } diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index 367d79a5283db..755d49d2c6c58 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -178,7 +178,7 @@ OopStorage* ObjectMonitor::_oop_storage = nullptr; // // Cxq points to the set of Recently Arrived Threads attempting entry. // Because we push threads onto _cxq with CAS, the RATs must take the form of -// a singly-linked LIFO. We drain _cxq into EntryList at unlock-time when +// a singly-linked LIFO. We drain _cxq into EntryList at unlock-time when // the unlocking thread notices that EntryList is null but _cxq is != null. // // The EntryList is ordered by the prevailing queue discipline and @@ -210,19 +210,6 @@ OopStorage* ObjectMonitor::_oop_storage = nullptr; // unpark the notifyee. Unparking a notifee in notify() is inefficient - // it's likely the notifyee would simply impale itself on the lock held // by the notifier. -// -// * An interesting alternative is to encode cxq as (List,LockByte) where -// the LockByte is 0 iff the monitor is owned. _owner is simply an auxiliary -// variable, like _recursions, in the scheme. The threads or Events that form -// the list would have to be aligned in 256-byte addresses. A thread would -// try to acquire the lock or enqueue itself with CAS, but exiting threads -// could use a 1-0 protocol and simply STB to set the LockByte to 0. -// Note that is is *not* word-tearing, but it does presume that full-word -// CAS operations are coherent with intermix with STB operations. That's true -// on most common processors. -// -// * See also http://blogs.sun.com/dave - // Check that object() and set_object() are called from the right context: static void check_object_context() { @@ -257,7 +244,6 @@ ObjectMonitor::ObjectMonitor(oop object) : _EntryList(nullptr), _cxq(nullptr), _succ(nullptr), - _Responsible(nullptr), _SpinDuration(ObjectMonitor::Knob_SpinLimit), _contentions(0), _WaitSet(nullptr), @@ -320,17 +306,11 @@ bool ObjectMonitor::enter_is_async_deflating() { return false; } -void ObjectMonitor::enter_for_with_contention_mark(JavaThread* locking_thread, ObjectMonitorContentionMark& contention_mark) { - // Used by ObjectSynchronizer::enter_for to enter for another thread. - // The monitor is private to or already owned by locking_thread which must be suspended. - // So this code may only contend with deflation. - assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); +bool ObjectMonitor::TryLockWithContentionMark(JavaThread* locking_thread, ObjectMonitorContentionMark& contention_mark) { assert(contention_mark._monitor == this, "must be"); assert(!is_being_async_deflated(), "must be"); - void* prev_owner = try_set_owner_from(nullptr, locking_thread); - bool success = false; if (prev_owner == nullptr) { @@ -343,8 +323,16 @@ void ObjectMonitor::enter_for_with_contention_mark(JavaThread* locking_thread, O // Racing with deflation. prev_owner = try_set_owner_from(DEFLATER_MARKER, locking_thread); if (prev_owner == DEFLATER_MARKER) { - // Cancelled deflation. Increment contentions as part of the deflation protocol. - add_to_contentions(1); + // We successfully cancelled the in-progress async deflation by + // changing owner from DEFLATER_MARKER to current. We now extend + // the lifetime of the contention_mark (e.g. contentions++) here + // to prevent the deflater thread from winning the last part of + // the 2-part async deflation protocol after the regular + // decrement occurs when the contention_mark goes out of + // scope. ObjectMonitor::deflate_monitor() which is called by + // the deflater thread will decrement contentions after it + // recognizes that the async deflation was cancelled. + contention_mark.extend(); success = true; } else if (prev_owner == nullptr) { // At this point we cannot race with deflation as we have both incremented @@ -360,12 +348,28 @@ void ObjectMonitor::enter_for_with_contention_mark(JavaThread* locking_thread, O set_owner_from_BasicLock(prev_owner, locking_thread); success = true; } + assert(!success || owner_raw() == locking_thread, "must be"); + + return success; +} + +void ObjectMonitor::enter_for_with_contention_mark(JavaThread* locking_thread, ObjectMonitorContentionMark& contention_mark) { + // Used by LightweightSynchronizer::inflate_and_enter in deoptimization path to enter for another thread. + // The monitor is private to or already owned by locking_thread which must be suspended. + // So this code may only contend with deflation. + assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); + bool success = TryLockWithContentionMark(locking_thread, contention_mark); + assert(success, "Failed to enter_for: locking_thread=" INTPTR_FORMAT - ", this=" INTPTR_FORMAT "{owner=" INTPTR_FORMAT "}, observed owner: " INTPTR_FORMAT, - p2i(locking_thread), p2i(this), p2i(owner_raw()), p2i(prev_owner)); + ", this=" INTPTR_FORMAT "{owner=" INTPTR_FORMAT "}", + p2i(locking_thread), p2i(this), p2i(owner_raw())); } bool ObjectMonitor::enter_for(JavaThread* locking_thread) { + // Used by ObjectSynchronizer::enter_for() to enter for another thread. + // The monitor is private to or already owned by locking_thread which must be suspended. + // So this code may only contend with deflation. + assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be"); // Block out deflation as soon as possible. ObjectMonitorContentionMark contention_mark(this); @@ -375,19 +379,29 @@ bool ObjectMonitor::enter_for(JavaThread* locking_thread) { return false; } - enter_for_with_contention_mark(locking_thread, contention_mark); + bool success = TryLockWithContentionMark(locking_thread, contention_mark); + + assert(success, "Failed to enter_for: locking_thread=" INTPTR_FORMAT + ", this=" INTPTR_FORMAT "{owner=" INTPTR_FORMAT "}", + p2i(locking_thread), p2i(this), p2i(owner_raw())); assert(owner_raw() == locking_thread, "must be"); return true; } -bool ObjectMonitor::try_enter(JavaThread* current) { - // TryLock avoids the CAS +bool ObjectMonitor::try_enter(JavaThread* current, bool check_for_recursion) { + // TryLock avoids the CAS and handles deflation. TryLockResult r = TryLock(current); if (r == TryLockResult::Success) { assert(_recursions == 0, "invariant"); return true; } + // If called from SharedRuntime::monitor_exit_helper(), we know that + // this thread doesn't already own the lock. + if (!check_for_recursion) { + return false; + } + if (r == TryLockResult::HasOwner && owner() == current) { _recursions++; return true; @@ -400,7 +414,6 @@ bool ObjectMonitor::try_enter(JavaThread* current) { set_owner_from_BasicLock(cur, current); // Convert from BasicLock* to Thread*. return true; } - return false; } @@ -561,16 +574,40 @@ void ObjectMonitor::enter_with_contention_mark(JavaThread *current, ObjectMonito ObjectMonitor::TryLockResult ObjectMonitor::TryLock(JavaThread* current) { void* own = owner_raw(); - if (own != nullptr) return TryLockResult::HasOwner; - if (try_set_owner_from(nullptr, current) == nullptr) { - assert(_recursions == 0, "invariant"); - return TryLockResult::Success; + void* first_own = own; + + for (;;) { + if (own == DEFLATER_MARKER) { + // Block out deflation as soon as possible. + ObjectMonitorContentionMark contention_mark(this); + + // Check for deflation. + if (enter_is_async_deflating()) { + // Treat deflation as interference. + return TryLockResult::Interference; + } + if (TryLockWithContentionMark(current, contention_mark)) { + assert(_recursions == 0, "invariant"); + return TryLockResult::Success; + } else { + // Deflation won or change of owner; dont spin + break; + } + } else if (own == nullptr) { + void* prev_own = try_set_owner_from(nullptr, current); + if (prev_own == nullptr) { + assert(_recursions == 0, "invariant"); + return TryLockResult::Success; + } else { + // The lock had been free momentarily, but we lost the race to the lock. + own = prev_own; + } + } else { + // Retry doesn't make as much sense because the lock was just acquired. + break; + } } - // The lock had been free momentarily, but we lost the race to the lock. - // Interference -- the CAS failed. - // We can either return -1 or retry. - // Retry doesn't make as much sense because the lock was just acquired. - return TryLockResult::Interference; + return first_own == own ? TryLockResult::HasOwner : TryLockResult::Interference; } // Deflate the specified ObjectMonitor if not in-use. Returns true if it @@ -746,8 +783,6 @@ const char* ObjectMonitor::is_busy_to_string(stringStream* ss) { return ss->base(); } -#define MAX_RECHECK_INTERVAL 1000 - void ObjectMonitor::EnterI(JavaThread* current) { assert(current->thread_state() == _thread_blocked, "invariant"); @@ -755,25 +790,6 @@ void ObjectMonitor::EnterI(JavaThread* current) { if (TryLock(current) == TryLockResult::Success) { assert(_succ != current, "invariant"); assert(owner_raw() == current, "invariant"); - assert(_Responsible != current, "invariant"); - return; - } - - if (try_set_owner_from(DEFLATER_MARKER, current) == DEFLATER_MARKER) { - // Cancelled the in-progress async deflation by changing owner from - // DEFLATER_MARKER to current. As part of the contended enter protocol, - // contentions was incremented to a positive value before EnterI() - // was called and that prevents the deflater thread from winning the - // last part of the 2-part async deflation protocol. After EnterI() - // returns to enter(), contentions is decremented because the caller - // now owns the monitor. We bump contentions an extra time here to - // prevent the deflater thread from winning the last part of the - // 2-part async deflation protocol after the regular decrement - // occurs in enter(). The deflater thread will decrement contentions - // after it recognizes that the async deflation was cancelled. - add_to_contentions(1); - assert(_succ != current, "invariant"); - assert(_Responsible != current, "invariant"); return; } @@ -789,14 +805,12 @@ void ObjectMonitor::EnterI(JavaThread* current) { if (TrySpin(current)) { assert(owner_raw() == current, "invariant"); assert(_succ != current, "invariant"); - assert(_Responsible != current, "invariant"); return; } // The Spin failed -- Enqueue and park the thread ... assert(_succ != current, "invariant"); assert(owner_raw() != current, "invariant"); - assert(_Responsible != current, "invariant"); // Enqueue "current" on ObjectMonitor's _cxq. // @@ -826,40 +840,10 @@ void ObjectMonitor::EnterI(JavaThread* current) { if (TryLock(current) == TryLockResult::Success) { assert(_succ != current, "invariant"); assert(owner_raw() == current, "invariant"); - assert(_Responsible != current, "invariant"); return; } } - // Check for cxq|EntryList edge transition to non-null. This indicates - // the onset of contention. While contention persists exiting threads - // will use a ST:MEMBAR:LD 1-1 exit protocol. When contention abates exit - // operations revert to the faster 1-0 mode. This enter operation may interleave - // (race) a concurrent 1-0 exit operation, resulting in stranding, so we - // arrange for one of the contending thread to use a timed park() operations - // to detect and recover from the race. (Stranding is form of progress failure - // where the monitor is unlocked but all the contending threads remain parked). - // That is, at least one of the contended threads will periodically poll _owner. - // One of the contending threads will become the designated "Responsible" thread. - // The Responsible thread uses a timed park instead of a normal indefinite park - // operation -- it periodically wakes and checks for and recovers from potential - // strandings admitted by 1-0 exit operations. We need at most one Responsible - // thread per-monitor at any given moment. Only threads on cxq|EntryList may - // be responsible for a monitor. - // - // Currently, one of the contended threads takes on the added role of "Responsible". - // A viable alternative would be to use a dedicated "stranding checker" thread - // that periodically iterated over all the threads (or active monitors) and unparked - // successors where there was risk of stranding. This would help eliminate the - // timer scalability issues we see on some platforms as we'd only have one thread - // -- the checker -- parked on a timer. - - if (nxt == nullptr && _EntryList == nullptr) { - // Try to assume the role of responsible thread for the monitor. - // CONSIDER: ST vs CAS vs { if (Responsible==null) Responsible=current } - Atomic::replace_if_null(&_Responsible, current); - } - // The lock might have been released while this thread was occupied queueing // itself onto _cxq. To close the race and avoid "stranding" and // progress-liveness failure we must resample-retry _owner before parking. @@ -871,8 +855,6 @@ void ObjectMonitor::EnterI(JavaThread* current) { // to defer the state transitions until absolutely necessary, // and in doing so avoid some transitions ... - int recheckInterval = 1; - for (;;) { if (TryLock(current) == TryLockResult::Success) { @@ -881,37 +863,12 @@ void ObjectMonitor::EnterI(JavaThread* current) { assert(owner_raw() != current, "invariant"); // park self - if (_Responsible == current) { - current->_ParkEvent->park((jlong) recheckInterval); - // Increase the recheckInterval, but clamp the value. - recheckInterval *= 8; - if (recheckInterval > MAX_RECHECK_INTERVAL) { - recheckInterval = MAX_RECHECK_INTERVAL; - } - } else { - current->_ParkEvent->park(); - } + current->_ParkEvent->park(); if (TryLock(current) == TryLockResult::Success) { break; } - if (try_set_owner_from(DEFLATER_MARKER, current) == DEFLATER_MARKER) { - // Cancelled the in-progress async deflation by changing owner from - // DEFLATER_MARKER to current. As part of the contended enter protocol, - // contentions was incremented to a positive value before EnterI() - // was called and that prevents the deflater thread from winning the - // last part of the 2-part async deflation protocol. After EnterI() - // returns to enter(), contentions is decremented because the caller - // now owns the monitor. We bump contentions an extra time here to - // prevent the deflater thread from winning the last part of the - // 2-part async deflation protocol after the regular decrement - // occurs in enter(). The deflater thread will decrement contentions - // after it recognizes that the async deflation was cancelled. - add_to_contentions(1); - break; - } - // The lock is still contested. // Keep a tally of the # of futile wakeups. @@ -953,44 +910,23 @@ void ObjectMonitor::EnterI(JavaThread* current) { assert(owner_raw() == current, "invariant"); UnlinkAfterAcquire(current, &node); - if (_succ == current) _succ = nullptr; - - assert(_succ != current, "invariant"); - if (_Responsible == current) { - _Responsible = nullptr; - OrderAccess::fence(); // Dekker pivot-point - - // We may leave threads on cxq|EntryList without a designated - // "Responsible" thread. This is benign. When this thread subsequently - // exits the monitor it can "see" such preexisting "old" threads -- - // threads that arrived on the cxq|EntryList before the fence, above -- - // by LDing cxq|EntryList. Newly arrived threads -- that is, threads - // that arrive on cxq after the ST:MEMBAR, above -- will set Responsible - // non-null and elect a new "Responsible" timer thread. - // - // This thread executes: - // ST Responsible=null; MEMBAR (in enter epilogue - here) - // LD cxq|EntryList (in subsequent exit) - // - // Entering threads in the slow/contended path execute: - // ST cxq=nonnull; MEMBAR; LD Responsible (in enter prolog) - // The (ST cxq; MEMBAR) is accomplished with CAS(). - // - // The MEMBAR, above, prevents the LD of cxq|EntryList in the subsequent - // exit operation from floating above the ST Responsible=null. + if (_succ == current) { + _succ = nullptr; + // Note that we don't need to do OrderAccess::fence() after clearing + // _succ here, since we own the lock. } // We've acquired ownership with CAS(). // CAS is serializing -- it has MEMBAR/FENCE-equivalent semantics. // But since the CAS() this thread may have also stored into _succ, - // EntryList, cxq or Responsible. These meta-data updates must be + // EntryList or cxq. These meta-data updates must be // visible __before this thread subsequently drops the lock. // Consider what could occur if we didn't enforce this constraint -- // STs to monitor meta-data and user-data could reorder with (become // visible after) the ST in exit that drops ownership of the lock. // Some other thread could then acquire the lock, but observe inconsistent // or old monitor meta-data and heap data. That violates the JMM. - // To that end, the 1-0 exit() operation must have at least STST|LDST + // To that end, the exit() operation must have at least STST|LDST // "release" barrier semantics. Specifically, there must be at least a // STST|LDST barrier in exit() before the ST of null into _owner that drops // the lock. The barrier ensures that changes to monitor meta-data and data @@ -1000,8 +936,7 @@ void ObjectMonitor::EnterI(JavaThread* current) { // // Critically, any prior STs to _succ or EntryList must be visible before // the ST of null into _owner in the *subsequent* (following) corresponding - // monitorexit. Recall too, that in 1-0 mode monitorexit does not necessarily - // execute a serializing instruction. + // monitorexit. return; } @@ -1174,39 +1109,32 @@ void ObjectMonitor::UnlinkAfterAcquire(JavaThread* current, ObjectWaiter* curren // In that case exit() is called with _thread_state == _thread_blocked, // but the monitor's _contentions field is > 0, which inhibits reclamation. // -// 1-0 exit -// ~~~~~~~~ -// ::exit() uses a canonical 1-1 idiom with a MEMBAR although some of -// the fast-path operators have been optimized so the common ::exit() -// operation is 1-0, e.g., see macroAssembler_x86.cpp: fast_unlock(). -// The code emitted by fast_unlock() elides the usual MEMBAR. This -// greatly improves latency -- MEMBAR and CAS having considerable local -// latency on modern processors -- but at the cost of "stranding". Absent the -// MEMBAR, a thread in fast_unlock() can race a thread in the slow -// ::enter() path, resulting in the entering thread being stranding -// and a progress-liveness failure. Stranding is extremely rare. -// We use timers (timed park operations) & periodic polling to detect -// and recover from stranding. Potentially stranded threads periodically -// wake up and poll the lock. See the usage of the _Responsible variable. +// This is the exit part of the locking protocol, often implemented in +// C2_MacroAssembler::fast_unlock() +// +// 1. A release barrier ensures that changes to monitor meta-data +// (_succ, _EntryList, _cxq) and data protected by the lock will be +// visible before we release the lock. +// 2. Release the lock by clearing the owner. +// 3. A storeload MEMBAR is needed between releasing the owner and +// subsequently reading meta-data to safely determine if the lock is +// contended (step 4) without an elected successor (step 5). +// 4. If both _EntryList and _cxq are null, we are done, since there is no +// other thread waiting on the lock to wake up. I.e. there is no +// contention. +// 5. If there is a successor (_succ is non-null), we are done. The +// responsibility for guaranteeing progress-liveness has now implicitly +// been moved from the exiting thread to the successor. +// 6. There are waiters in the entry list (_EntryList and/or cxq are +// non-null), but there is no successor (_succ is null), so we need to +// wake up (unpark) a waiting thread to avoid stranding. // -// The CAS() in enter provides for safety and exclusion, while the CAS or -// MEMBAR in exit provides for progress and avoids stranding. 1-0 locking -// eliminates the CAS/MEMBAR from the exit path, but it admits stranding. -// We detect and recover from stranding with timers. +// Note that since only the current lock owner can manipulate the _EntryList +// or drain _cxq, we need to reacquire the lock before we can wake up +// (unpark) a waiting thread. // -// If a thread transiently strands it'll park until (a) another -// thread acquires the lock and then drops the lock, at which time the -// exiting thread will notice and unpark the stranded thread, or, (b) -// the timer expires. If the lock is high traffic then the stranding latency -// will be low due to (a). If the lock is low traffic then the odds of -// stranding are lower, although the worst-case stranding latency -// is longer. Critically, we don't want to put excessive load in the -// platform's timer subsystem. We want to minimize both the timer injection -// rate (timers created/sec) as well as the number of timers active at -// any one time. (more precisely, we want to minimize timer-seconds, which is -// the integral of the # of active timers at any instant over time). -// Both impinge on OS scalability. Given that, at most one thread parked on -// a monitor will use a timer. +// The CAS() in enter provides for safety and exclusion, while the +// MEMBAR in exit provides for progress and avoids stranding. // // There is also the risk of a futile wake-up. If we drop the lock // another thread can reacquire the lock immediately, and we can @@ -1248,10 +1176,6 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) { return; } - // Invariant: after setting Responsible=null an thread must execute - // a MEMBAR or other serializing instruction before fetching EntryList|cxq. - _Responsible = nullptr; - #if INCLUDE_JFR // get the owner's thread id for the MonitorEnter event // if it is enabled and the thread isn't suspended @@ -1278,14 +1202,15 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) { // Other threads are blocked trying to acquire the lock. // Normally the exiting thread is responsible for ensuring succession, - // but if other successors are ready or other entering threads are spinning - // then this thread can simply store null into _owner and exit without - // waking a successor. The existence of spinners or ready successors - // guarantees proper succession (liveness). Responsibility passes to the - // ready or running successors. The exiting thread delegates the duty. - // More precisely, if a successor already exists this thread is absolved - // of the responsibility of waking (unparking) one. - // + // but if this thread observes other successors are ready or other + // entering threads are spinning after it has stored null into _owner + // then it can exit without waking a successor. The existence of + // spinners or ready successors guarantees proper succession (liveness). + // Responsibility passes to the ready or running successors. The exiting + // thread delegates the duty. More precisely, if a successor already + // exists this thread is absolved of the responsibility of waking + // (unparking) one. + // The _succ variable is critical to reducing futile wakeup frequency. // _succ identifies the "heir presumptive" thread that has been made // ready (unparked) but that has not yet run. We need only one such @@ -1296,24 +1221,20 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) { // Note that spinners in Enter() also set _succ non-null. // In the current implementation spinners opportunistically set // _succ so that exiting threads might avoid waking a successor. - // Another less appealing alternative would be for the exiting thread - // to drop the lock and then spin briefly to see if a spinner managed - // to acquire the lock. If so, the exiting thread could exit - // immediately without waking a successor, otherwise the exiting - // thread would need to dequeue and wake a successor. - // (Note that we'd need to make the post-drop spin short, but no - // shorter than the worst-case round-trip cache-line migration time. - // The dropped lock needs to become visible to the spinner, and then - // the acquisition of the lock by the spinner must become visible to - // the exiting thread). + // Which means that the exiting thread could exit immediately without + // waking a successor, if it observes a successor after it has dropped + // the lock. Note that the dropped lock needs to become visible to the + // spinner. // It appears that an heir-presumptive (successor) must be made ready. // Only the current lock owner can manipulate the EntryList or // drain _cxq, so we need to reacquire the lock. If we fail // to reacquire the lock the responsibility for ensuring succession // falls to the new owner. - // - if (try_set_owner_from(nullptr, current) != nullptr) { + + if (TryLock(current) != TryLockResult::Success) { + // Some other thread acquired the lock (or the monitor was + // deflated). Either way we are done. return; } @@ -1376,7 +1297,7 @@ void ObjectMonitor::exit(JavaThread* current, bool not_suspended) { q = p; } - // In 1-0 mode we need: ST EntryList; MEMBAR #storestore; ST _owner = nullptr + // We need to: ST EntryList; MEMBAR #storestore; ST _owner = nullptr // The MEMBAR is satisfied by the release_store() operation in ExitEpilog(). // See if we can abdicate to a spinner instead of waking a thread. @@ -1566,8 +1487,6 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { AddWaiter(&node); Thread::SpinRelease(&_WaitSetLock); - _Responsible = nullptr; - intx save = _recursions; // record the old recursion count _waiters++; // increment the number of waiters _recursions = 0; // set the recursion level to be 1 @@ -2245,7 +2164,6 @@ void ObjectMonitor::print() const { print_on(tty); } // _EntryList = 0x0000000000000000 // _cxq = 0x0000000000000000 // _succ = 0x0000000000000000 -// _Responsible = 0x0000000000000000 // _SpinDuration = 5000 // _contentions = 0 // _WaitSet = 0x0000700009756248 @@ -2274,7 +2192,6 @@ void ObjectMonitor::print_debug_style_on(outputStream* st) const { st->print_cr(" _EntryList = " INTPTR_FORMAT, p2i(_EntryList)); st->print_cr(" _cxq = " INTPTR_FORMAT, p2i(_cxq)); st->print_cr(" _succ = " INTPTR_FORMAT, p2i(_succ)); - st->print_cr(" _Responsible = " INTPTR_FORMAT, p2i(_Responsible)); st->print_cr(" _SpinDuration = %d", _SpinDuration); st->print_cr(" _contentions = %d", contentions()); st->print_cr(" _WaitSet = " INTPTR_FORMAT, p2i(_WaitSet)); diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index ef85559c2b6c3..30d2e5094162d 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -179,7 +179,6 @@ class ObjectMonitor : public CHeapObj { ObjectWaiter* volatile _cxq; // LL of recently-arrived threads blocked on entry. JavaThread* volatile _succ; // Heir presumptive thread - used for futile wakeup throttling - JavaThread* volatile _Responsible; volatile int _SpinDuration; @@ -348,7 +347,7 @@ class ObjectMonitor : public CHeapObj { void enter_for_with_contention_mark(JavaThread* locking_thread, ObjectMonitorContentionMark& contention_mark); bool enter_for(JavaThread* locking_thread); bool enter(JavaThread* current); - bool try_enter(JavaThread* current); + bool try_enter(JavaThread* current, bool check_for_recursion = true); bool spin_enter(JavaThread* current); void enter_with_contention_mark(JavaThread* current, ObjectMonitorContentionMark& contention_mark); void exit(JavaThread* current, bool not_suspended = true); @@ -377,6 +376,7 @@ class ObjectMonitor : public CHeapObj { enum class TryLockResult { Interference = -1, HasOwner = 0, Success = 1 }; + bool TryLockWithContentionMark(JavaThread* locking_thread, ObjectMonitorContentionMark& contention_mark); TryLockResult TryLock(JavaThread* current); bool TrySpin(JavaThread* current); @@ -395,12 +395,17 @@ class ObjectMonitorContentionMark : StackObj { DEBUG_ONLY(friend class ObjectMonitor;) ObjectMonitor* _monitor; + bool _extended; NONCOPYABLE(ObjectMonitorContentionMark); public: explicit ObjectMonitorContentionMark(ObjectMonitor* monitor); ~ObjectMonitorContentionMark(); + + // Extends the contention scope beyond this objects lifetime. + // Requires manual decrement of the contentions counter. + void extend(); }; #endif // SHARE_RUNTIME_OBJECTMONITOR_HPP diff --git a/src/hotspot/share/runtime/objectMonitor.inline.hpp b/src/hotspot/share/runtime/objectMonitor.inline.hpp index d26c459b1b415..6d3c6ff24c38b 100644 --- a/src/hotspot/share/runtime/objectMonitor.inline.hpp +++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp @@ -206,15 +206,32 @@ inline void ObjectMonitor::set_next_om(ObjectMonitor* new_value) { Atomic::store(&_next_om, new_value); } +// Block out deflation. inline ObjectMonitorContentionMark::ObjectMonitorContentionMark(ObjectMonitor* monitor) - : _monitor(monitor) { + : _monitor(monitor), _extended(false) { + // Contentions is incremented to a positive value as part of the + // contended enter protocol, which prevents the deflater thread from + // winning the last part of the 2-part async deflation + // protocol. See: ObjectMonitor::deflate_monitor() and + // ObjectMonitor::TryLockWithContentionMark(). _monitor->add_to_contentions(1); } inline ObjectMonitorContentionMark::~ObjectMonitorContentionMark() { + // Decrement contentions when the contention mark goes out of + // scope. This opens up for deflation, if the contention mark + // hasn't been extended. _monitor->add_to_contentions(-1); } +inline void ObjectMonitorContentionMark::extend() { + // Used by ObjectMonitor::TryLockWithContentionMark() to "extend the + // lifetime" of the contention mark. + assert(!_extended, "extending twice is probably a bad design"); + _monitor->add_to_contentions(1); + _extended = true; +} + inline oop ObjectMonitor::object_peek() const { if (_object.is_null()) { return nullptr; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 6ca7f42e038f5..e4d4e6aea0f8c 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -1963,6 +1963,26 @@ void SharedRuntime::monitor_exit_helper(oopDesc* obj, BasicLock* lock, JavaThrea assert(JavaThread::current() == current, "invariant"); // Exit must be non-blocking, and therefore no exceptions can be thrown. ExceptionMark em(current); + + // Check if C2_MacroAssembler::fast_unlock() or + // C2_MacroAssembler::fast_unlock_lightweight() unlocked an inflated + // monitor before going slow path. Since there is no safepoint + // polling when calling into the VM, we can be sure that the monitor + // hasn't been deallocated. + ObjectMonitor* m = current->unlocked_inflated_monitor(); + if (m != nullptr) { + assert(m->owner_raw() != current, "must be"); + current->clear_unlocked_inflated_monitor(); + + // We need to reacquire the lock before we can call ObjectSynchronizer::exit(). + if (!m->try_enter(current, /*check_for_recursion*/ false)) { + // Some other thread acquired the lock (or the monitor was + // deflated). Either way we are done. + current->dec_held_monitor_count(); + return; + } + } + // The object could become unlocked through a JNI call, which we have no other checks for. // Give a fatal message if CheckJNICalls. Otherwise we ignore it. if (obj->is_unlocked()) { diff --git a/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java b/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java index 3ed862e8218cd..39c8569532ec4 100644 --- a/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java +++ b/test/micro/org/openjdk/bench/vm/lang/LockUnlock.java @@ -309,10 +309,11 @@ private synchronized int fact(int n) { } /** - * With two threads lockObject1 will be contended so should be - * inflated. + * With three threads lockObject1 will be contended so should be + * inflated. Three threads is also needed to ensure a high level + * of code coverage in the locking code. */ - @Threads(2) + @Threads(3) @Benchmark public void testContendedLock() { synchronized (lockObject1) { From cff420d8d3cfbbb729ee47b00c8fe38e410eab1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Mon, 30 Sep 2024 13:06:49 +0000 Subject: [PATCH 061/188] 8339711: ZipFile.Source.initCEN needlessly reads END header Reviewed-by: lancea, jpai, redestad --- .../share/classes/java/util/zip/ZipFile.java | 21 +++++++++++-------- .../util/zip/ZipFile/CenSizeTooLarge.java | 4 +++- .../util/zip/ZipFile/EndOfCenValidation.java | 6 ++++-- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index d54e6c1e4fcb9..43b2261f1c60a 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -63,6 +63,7 @@ import jdk.internal.access.JavaUtilZipFileAccess; import jdk.internal.access.JavaUtilJarAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.util.ArraysSupport; import jdk.internal.util.OperatingSystem; import jdk.internal.perf.PerfCounter; import jdk.internal.ref.CleanerFactory; @@ -1178,6 +1179,8 @@ private static class Source { // "META-INF/".length() private static final int META_INF_LEN = 9; private static final int[] EMPTY_META_VERSIONS = new int[0]; + // CEN size is limited to the maximum array size in the JDK + private static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; private final Key key; // the key in files private final @Stable ZipCoder zc; // ZIP coder used to decode/encode @@ -1185,7 +1188,7 @@ private static class Source { private int refs = 1; private RandomAccessFile zfile; // zfile of the underlying ZIP file - private byte[] cen; // CEN & ENDHDR + private byte[] cen; // CEN private long locpos; // position of first LOC header (usually 0) private byte[] comment; // ZIP file comment // list of meta entries in META-INF dir @@ -1241,7 +1244,7 @@ private int checkAndAddEntry(int pos, int index) // should not exceed 65,535 bytes per the PKWare APP.NOTE // 4.4.10, 4.4.11, & 4.4.12. Also check that current CEN header will // not exceed the length of the CEN array - if (headerSize > 0xFFFF || pos + headerSize > cen.length - ENDHDR) { + if (headerSize > 0xFFFF || pos + headerSize > cen.length) { zerror("invalid CEN header (bad header size)"); } @@ -1294,7 +1297,7 @@ private void checkExtraFields(int cenPos, int startingOffset, } // CEN Offset where this Extra field ends int extraEndOffset = startingOffset + extraFieldLen; - if (extraEndOffset > cen.length - ENDHDR) { + if (extraEndOffset > cen.length) { zerror("Invalid CEN header (extra data field size too long)"); } int currentOffset = startingOffset; @@ -1732,12 +1735,12 @@ private void initCEN(int knownTotal) throws IOException { if (locpos < 0) { zerror("invalid END header (bad central directory offset)"); } - // read in the CEN and END - if (end.cenlen + ENDHDR >= Integer.MAX_VALUE) { + // read in the CEN + if (end.cenlen > MAX_CEN_SIZE) { zerror("invalid END header (central directory size too large)"); } - cen = this.cen = new byte[(int)(end.cenlen + ENDHDR)]; - if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen + ENDHDR) { + cen = this.cen = new byte[(int)end.cenlen]; + if (readFullyAt(cen, 0, cen.length, cenpos) != end.cenlen) { zerror("read CEN tables failed"); } this.total = end.centot; @@ -1766,7 +1769,7 @@ private void initCEN(int knownTotal) throws IOException { int idx = 0; // Index into the entries array int pos = 0; int entryPos = CENHDR; - int limit = cen.length - ENDHDR; + int limit = cen.length; manifestNum = 0; while (entryPos <= limit) { if (idx >= entriesLength) { @@ -1829,7 +1832,7 @@ private void initCEN(int knownTotal) throws IOException { } else { metaVersions = EMPTY_META_VERSIONS; } - if (pos + ENDHDR != cen.length) { + if (pos != cen.length) { zerror("invalid CEN header (bad header size)"); } } diff --git a/test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java b/test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java index 3a5430d0573e8..e3f0b20fce87c 100644 --- a/test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java +++ b/test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java @@ -23,10 +23,12 @@ /* @test * @bug 8272746 + * @modules java.base/jdk.internal.util * @summary Verify that ZipFile rejects a ZIP with a CEN size which does not fit in a Java byte array * @run junit CenSizeTooLarge */ +import jdk.internal.util.ArraysSupport; import org.junit.Before; import org.junit.Test; @@ -49,7 +51,7 @@ public class CenSizeTooLarge { public static final int NAME_LENGTH = 10; // Maximum allowed CEN size allowed by the ZipFile implementation - static final int MAX_CEN_SIZE = Integer.MAX_VALUE - ZipFile.ENDHDR - 1; + static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; /** * From the APPNOTE.txt specification: diff --git a/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java b/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java index 51ed2c28c12c2..ec6542768c58f 100644 --- a/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java +++ b/test/jdk/java/util/zip/ZipFile/EndOfCenValidation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,12 @@ /* @test * @bug 8272746 + * @modules java.base/jdk.internal.util * @summary Verify that ZipFile rejects files with CEN sizes exceeding the implementation limit * @run testng/othervm EndOfCenValidation */ +import jdk.internal.util.ArraysSupport; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -68,7 +70,7 @@ public class EndOfCenValidation { private static final int ENDSIZ = ZipFile.ENDSIZ; // Offset of CEN size field within ENDHDR private static final int ENDOFF = ZipFile.ENDOFF; // Offset of CEN offset field within ENDHDR // Maximum allowed CEN size allowed by ZipFile - private static int MAX_CEN_SIZE = Integer.MAX_VALUE - ENDHDR - 1; + private static int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; // Expected message when CEN size does not match file size private static final String INVALID_CEN_BAD_SIZE = "invalid END header (bad central directory size)"; From 860d49db22cf352eaf1b3b20fff43d090f0eebc8 Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Mon, 30 Sep 2024 13:43:40 +0000 Subject: [PATCH 062/188] 8211400: nsk.share.gc.Memory::getArrayLength returns wrong value Reviewed-by: kbarrett, tschatzl --- .../hotspot/jtreg/vmTestbase/nsk/share/gc/Memory.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Memory.java b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Memory.java index f5c70671e5e10..244bcf423c5bc 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Memory.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/gc/Memory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -150,12 +150,9 @@ public static int getReferenceObjectSize() { * @return length of array */ public static int getArrayLength(long memory, long objectSize) { - int referenceSize = getReferenceSize(); int arrayExtraSize = getArrayExtraSize(); - return (int) Math.min( - (memory - arrayExtraSize) / (objectSize + referenceSize), - Integer.MAX_VALUE - ); + return (int) Math.min((memory - arrayExtraSize) / objectSize, + Integer.MAX_VALUE); } /** @@ -166,7 +163,7 @@ public static int getArrayLength(long memory, long objectSize) { * @return size of array */ public static long getArraySize(int length, long objectSize) { - return getObjectExtraSize() + length * (objectSize + getReferenceSize()); + return getArrayExtraSize() + length * objectSize; } /** From f1bf469b4ee07b48b629a126111e307d3cab7fd7 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Mon, 30 Sep 2024 14:12:01 +0000 Subject: [PATCH 063/188] 8341199: Use ClassFile's new API loadConstant(int) Reviewed-by: liach, redestad --- .../java/lang/invoke/StringConcatFactory.java | 12 ++++++------ .../classes/java/lang/runtime/SwitchBootstraps.java | 2 +- .../classes/jdk/jfr/internal/EventClassBuilder.java | 2 +- .../jdk/jfr/internal/EventInstrumentation.java | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 4fbbec1769364..97848e1fcb3e5 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -1526,7 +1526,7 @@ public void accept(CodeBuilder cb) { * length = length(this.length, arg0, arg1, ..., argN); */ if (staticConcat) { - cb.ldc(length); + cb.loadConstant(length); } else { cb.aload(thisSlot) .getfield(concatClass, "length", CD_int); @@ -1549,7 +1549,7 @@ public void accept(CodeBuilder cb) { * length -= suffix.length(); */ if (staticConcat) { - cb.ldc(constants[paramCount].length()) + cb.loadConstant(constants[paramCount].length()) .isub() .istore(lengthSlot); } else { @@ -1557,7 +1557,7 @@ public void accept(CodeBuilder cb) { .getfield(concatClass, "constants", CD_Array_String) .dup() .astore(constantsSlot) - .ldc(paramCount) + .loadConstant(paramCount) .aaload() .dup() .astore(suffixSlot) @@ -1572,7 +1572,7 @@ public void accept(CodeBuilder cb) { * buf = newArrayWithSuffix(suffix, length, coder) */ if (staticConcat) { - cb.ldc(constants[paramCount]); + cb.loadConstant(constants[paramCount]); } else { cb.aload(suffixSlot); } @@ -1759,10 +1759,10 @@ public void accept(CodeBuilder cb) { .loadLocal(kind, cb.parameterSlot(i)); if (staticConcat) { - cb.ldc(constants[i - 3]); + cb.loadConstant(constants[i - 3]); } else { cb.aload(constantsSlot) - .ldc(i - 4) + .loadConstant(i - 4) .aaload(); } diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index bfdb76e2ef1b6..f380cf1070d1d 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -659,7 +659,7 @@ private static Consumer generateTypeSwitchSkeleton(Class selecto MethodTypeDesc.of(ConstantDescs.CD_char)); cb.labelBinding(compare); - cb.ldc(integerLabel); + cb.loadConstant(integerLabel); cb.if_icmpne(next); } else if ((caseLabel instanceof Long || caseLabel instanceof Float || diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java index 523622084843c..1373c3ca4968f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java @@ -84,7 +84,7 @@ private void buildSetMethod(ClassBuilder builder) { int index = 0; for (ValueDescriptor v : fields) { codeBuilder.iload(1); - codeBuilder.ldc(index); + codeBuilder.loadConstant(index); Label notEqual = codeBuilder.newLabel(); codeBuilder.if_icmpne(notEqual); codeBuilder.aload(0); // this diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java index 71dc97d114e2c..d962a535829ef 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java @@ -499,7 +499,7 @@ private void makeInstrumented() { // if (!settingsMethod(eventConfiguration.settingX)) goto fail; codeBuilder.aload(0); getEventConfiguration(codeBuilder); - codeBuilder.ldc(index); + codeBuilder.loadConstant(index); invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_GET_SETTING); MethodTypeDesc mdesc = MethodTypeDesc.ofDescriptor("(" + sd.paramType().descriptorString() + ")Z"); codeBuilder.checkcast(sd.paramType()); From 4168faf54c0558a7cff4ef6ac643bbbfdea0cec3 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 30 Sep 2024 16:10:02 +0000 Subject: [PATCH 064/188] 8341100: Add index entries for terms used in java.lang.Class Reviewed-by: liach --- src/java.base/share/classes/java/lang/Class.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 48ffeea5289ff..79cd57011b0ed 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -140,22 +140,24 @@ * }} * * It is also possible to get the {@code Class} object for a named - * class or interface (or for {@code void}) using a class literal. + * class or interface (or for {@code void}) using a class literal + * (JLS {@jls 15.8.2}). * For example: * * {@snippet lang="java" : - * System.out.println("The name of class Foo is: "+Foo.class.getName()); + * System.out.println("The name of class Foo is: " + Foo.class.getName()); // @highlight substring="Foo.class" * } * *

      Some methods of class {@code Class} expose whether the declaration of * a class or interface in Java source code was enclosed within * another declaration. Other methods describe how a class or interface - * is situated in a nest. A nest is a set of + * is situated in a {@index "nest"}. A nest is a set of * classes and interfaces, in the same run-time package, that * allow mutual access to their {@code private} members. - * The classes and interfaces are known as nestmates. + * The classes and interfaces are known as {@index "nestmates"} + * (JVMS {@jvms 4.7.29}). * One nestmate acts as the - * nest host, and enumerates the other nestmates which + * nest host (JVMS {@jvms 4.7.28}), and enumerates the other nestmates which * belong to the nest; each of them in turn records it as the nest host. * The classes and interfaces which belong to a nest, including its host, are * determined when @@ -167,7 +169,7 @@ *

      Hidden Classes

      * A class or interface created by the invocation of * {@link java.lang.invoke.MethodHandles.Lookup#defineHiddenClass(byte[], boolean, MethodHandles.Lookup.ClassOption...) - * Lookup::defineHiddenClass} is a {@linkplain Class#isHidden() hidden} + * Lookup::defineHiddenClass} is a {@linkplain Class#isHidden() hidden} * class or interface. * All kinds of class, including enum classes and record classes, may be * hidden classes; all kinds of interface, including annotation interfaces, @@ -216,7 +218,6 @@ * * @see java.lang.ClassLoader#defineClass(byte[], int, int) * @since 1.0 - * @jls 15.8.2 Class Literals */ public final class Class implements java.io.Serializable, GenericDeclaration, From 5586f83e34c2fe0bdc48daef8c456678cea55af1 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 30 Sep 2024 16:13:35 +0000 Subject: [PATCH 065/188] 8341064: Define anchor point and index term for "wrapper classes" Reviewed-by: prappo, liach --- .../share/classes/java/lang/Boolean.java | 10 ++-- .../share/classes/java/lang/Byte.java | 10 ++-- .../share/classes/java/lang/Character.java | 14 +++--- .../share/classes/java/lang/Double.java | 8 +-- .../share/classes/java/lang/Float.java | 8 +-- .../share/classes/java/lang/Integer.java | 7 +-- .../share/classes/java/lang/Long.java | 5 +- .../share/classes/java/lang/Short.java | 7 +-- .../share/classes/java/lang/package-info.java | 49 +++++++++++-------- .../classes/javax/lang/model/util/Types.java | 5 +- 10 files changed, 67 insertions(+), 56 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Boolean.java b/src/java.base/share/classes/java/lang/Boolean.java index ba88157dc923e..2c0925a979016 100644 --- a/src/java.base/share/classes/java/lang/Boolean.java +++ b/src/java.base/share/classes/java/lang/Boolean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,10 +37,10 @@ import static java.lang.constant.ConstantDescs.CD_Boolean; /** - * The Boolean class wraps a value of the primitive type - * {@code boolean} in an object. An object of type - * {@code Boolean} contains a single field whose type is - * {@code boolean}. + * The {@code Boolean} class is the {@linkplain + * java.lang##wrapperClass wrapper class} for values of the primitive + * type {@code boolean}. An object of type {@code Boolean} contains a + * single field whose type is {@code boolean}. * *

      In addition, this class provides many methods for * converting a {@code boolean} to a {@code String} and a diff --git a/src/java.base/share/classes/java/lang/Byte.java b/src/java.base/share/classes/java/lang/Byte.java index 18502abf69c4d..ade75a7a99eeb 100644 --- a/src/java.base/share/classes/java/lang/Byte.java +++ b/src/java.base/share/classes/java/lang/Byte.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,10 +39,10 @@ import static java.lang.constant.ConstantDescs.DEFAULT_NAME; /** - * - * The {@code Byte} class wraps a value of primitive type {@code byte} - * in an object. An object of type {@code Byte} contains a single - * field whose type is {@code byte}. + * The {@code Byte} class is the {@linkplain + * java.lang##wrapperClass wrapper class} for values of the primitive + * type {@code byte}. An object of type {@code Byte} contains a + * single field whose type is {@code byte}. * *

      In addition, this class provides several methods for converting * a {@code byte} to a {@code String} and a {@code String} to a {@code diff --git a/src/java.base/share/classes/java/lang/Character.java b/src/java.base/share/classes/java/lang/Character.java index a829d71e11367..84db550d7cc4d 100644 --- a/src/java.base/share/classes/java/lang/Character.java +++ b/src/java.base/share/classes/java/lang/Character.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,12 +43,12 @@ import static java.lang.constant.ConstantDescs.DEFAULT_NAME; /** - * The {@code Character} class wraps a value of the primitive - * type {@code char} in an object. An object of class - * {@code Character} contains a single field whose type is - * {@code char}. - *

      - * In addition, this class provides a large number of static methods for + * The {@code Character} class is the {@linkplain + * java.lang##wrapperClass wrapper class} for values of the primitive + * type {@code char}. An object of type {@code Character} contains a + * single field whose type is {@code char}. + * + *

      In addition, this class provides a large number of static methods for * determining a character's category (lowercase letter, digit, etc.) * and for converting characters from uppercase to lowercase and vice * versa. diff --git a/src/java.base/share/classes/java/lang/Double.java b/src/java.base/share/classes/java/lang/Double.java index e789a6777175e..68fff6a2fbdd2 100644 --- a/src/java.base/share/classes/java/lang/Double.java +++ b/src/java.base/share/classes/java/lang/Double.java @@ -36,10 +36,10 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; /** - * The {@code Double} class wraps a value of the primitive type - * {@code double} in an object. An object of type - * {@code Double} contains a single field whose type is - * {@code double}. + * The {@code Double} class is the {@linkplain + * java.lang##wrapperClass wrapper class} for values of the primitive + * type {@code double}. An object of type {@code Double} contains a + * single field whose type is {@code double}. * *

      In addition, this class provides several methods for converting a * {@code double} to a {@code String} and a diff --git a/src/java.base/share/classes/java/lang/Float.java b/src/java.base/share/classes/java/lang/Float.java index 02b6600777331..470eb71cf701f 100644 --- a/src/java.base/share/classes/java/lang/Float.java +++ b/src/java.base/share/classes/java/lang/Float.java @@ -36,10 +36,10 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; /** - * The {@code Float} class wraps a value of primitive type - * {@code float} in an object. An object of type - * {@code Float} contains a single field whose type is - * {@code float}. + * The {@code Float} class is the {@linkplain + * java.lang##wrapperClass wrapper class} for values of the primitive + * type {@code float}. An object of type {@code Float} contains a + * single field whose type is {@code float}. * *

      In addition, this class provides several methods for converting a * {@code float} to a {@code String} and a diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index fccdd697c7238..eab0a942d9a9a 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -45,9 +45,10 @@ import static java.lang.String.UTF16; /** - * The {@code Integer} class wraps a value of the primitive type - * {@code int} in an object. An object of type {@code Integer} - * contains a single field whose type is {@code int}. + * The {@code Integer} class is the {@linkplain + * java.lang##wrapperClass wrapper class} for values of the primitive + * type {@code int}. An object of type {@code Integer} contains a + * single field whose type is {@code int}. * *

      In addition, this class provides several methods for converting * an {@code int} to a {@code String} and a {@code String} to an diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index ff34da232f9ab..f86e1622b3836 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -45,8 +45,9 @@ import static java.lang.String.UTF16; /** - * The {@code Long} class wraps a value of the primitive type {@code - * long} in an object. An object of type {@code Long} contains a + * The {@code Long} class is the {@linkplain + * java.lang##wrapperClass wrapper class} for values of the primitive + * type {@code long}. An object of type {@code Long} contains a * single field whose type is {@code long}. * *

      In addition, this class provides several methods for converting diff --git a/src/java.base/share/classes/java/lang/Short.java b/src/java.base/share/classes/java/lang/Short.java index 6a148d1edac00..ec792de47e2ac 100644 --- a/src/java.base/share/classes/java/lang/Short.java +++ b/src/java.base/share/classes/java/lang/Short.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,8 +39,9 @@ import static java.lang.constant.ConstantDescs.DEFAULT_NAME; /** - * The {@code Short} class wraps a value of primitive type {@code - * short} in an object. An object of type {@code Short} contains a + * The {@code Short} class is the {@linkplain + * java.lang##wrapperClass wrapper class} for values of the primitive + * type {@code short}. An object of type {@code Short} contains a * single field whose type is {@code short}. * *

      In addition, this class provides several methods for converting diff --git a/src/java.base/share/classes/java/lang/package-info.java b/src/java.base/share/classes/java/lang/package-info.java index 882a610c1a08e..0484ecb29527d 100644 --- a/src/java.base/share/classes/java/lang/package-info.java +++ b/src/java.base/share/classes/java/lang/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,35 +25,42 @@ /** * Provides classes that are fundamental to the design of the Java - * programming language. The most important classes are {@code - * Object}, which is the root of the class hierarchy, and {@code + * programming language. The most important classes are {@link + * Object}, which is the root of the class hierarchy, and {@link * Class}, instances of which represent classes at run time. * *

      Frequently it is necessary to represent a value of primitive - * type as if it were an object. The wrapper classes {@code Boolean}, - * {@code Character}, {@code Integer}, {@code Long}, {@code Float}, - * and {@code Double} serve this purpose. An object of type {@code - * Double}, for example, contains a field whose type is double, - * representing that value in such a way that a reference to it can be - * stored in a variable of reference type. These classes also provide - * a number of methods for converting among primitive values, as well - * as supporting such standard methods as equals and hashCode. The - * {@code Void} class is a non-instantiable class that holds a - * reference to a {@code Class} object representing the type void. + * type as if it were an object.The {@index + * "wrapper classes"} {@link Boolean}, {@link Byte}, {@link + * Character}, {@link Short}, {@link Integer}, {@link Long}, {@link + * Float}, and {@link Double} serve this purpose. An object of type + * {@code Double}, for example, contains a field whose type is {@code + * double}, representing that value in such a way that a reference to + * it can be stored in a variable of reference type. As discussed in + * The Java Language Specification, the wrapper classes + * are involved in boxing (JLS {@jls 5.1.7}) and unboxing (JLS {@jls + * 5.1.8}) conversions. These classes provide a number of methods for + * converting among primitive values, as well as methods supporting + * such standard functionality as {@code equals} and {@code hashCode}. + * The {@link Void} class is a non-instantiable class that holds a + * reference to a {@code Class} object representing the type {@code + * void}. * - *

      The class {@code Math} provides commonly used mathematical - * functions such as sine, cosine, and square root. The classes {@code - * String}, {@code StringBuffer}, and {@code StringBuilder} similarly - * provide commonly used operations on character strings. + *

      The class {@link Math} provides commonly used mathematical + * functions such as {@linkplain Math#sin(double) sine}, {@linkplain + * Math#cos(double) cosine}, and {@linkplain Math#sqrt(double) square + * root}. The classes {@link String}, {@link StringBuffer}, and {@link + * StringBuilder} similarly provide commonly used operations on + * character strings. * - *

      Classes {@code ClassLoader}, {@code Process}, {@code - * ProcessBuilder}, {@code Runtime}, {@code SecurityManager}, and - * {@code System} provide "system operations" that manage the dynamic + *

      Classes {@link ClassLoader}, {@link Process}, {@link + * ProcessBuilder}, {@link Runtime}, {@link SecurityManager}, and + * {@link System} provide "system operations" that manage the dynamic * loading of classes, creation of external processes, host * environment inquiries such as the time of day, and enforcement of * security policies. * - *

      Class {@code Throwable} encompasses objects that may be thrown + *

      Class {@link Throwable} encompasses objects that may be thrown * by the {@code throw} statement. Subclasses of {@code Throwable} * represent errors and exceptions. * diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java index 232e15a84bd6a..ce83cda405862 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java @@ -205,8 +205,9 @@ public interface Types { * @return the type of an unboxed value of type {@code t} * * @throws IllegalArgumentException if the given type has no - * unboxing conversion. Only types for the wrapper classes - * have an unboxing conversion. + * unboxing conversion. Only types for the {@linkplain + * java.lang##wrapperClasses wrapper classes} have an + * unboxing conversion. * @jls 5.1.8 Unboxing Conversion */ PrimitiveType unboxedType(TypeMirror t); From a6b318863fa2775b6381977875b4f466af47beb8 Mon Sep 17 00:00:00 2001 From: Smita Kamath Date: Mon, 30 Sep 2024 17:00:13 +0000 Subject: [PATCH 066/188] 8337632: AES-GCM Algorithm optimization for x86_64 Reviewed-by: jbhateja, sviswanathan --- src/hotspot/cpu/x86/assembler_x86.cpp | 29 + src/hotspot/cpu/x86/assembler_x86.hpp | 3 + src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 21 +- .../cpu/x86/stubGenerator_x86_64_aes.cpp | 1217 ++++++++++------- .../cpu/x86/stubGenerator_x86_64_ghash.cpp | 7 +- .../crypto/provider/GaloisCounterMode.java | 2 +- .../bench/javax/crypto/full/AESGCMBench.java | 2 +- .../bench/javax/crypto/full/BenchBase.java | 2 +- 8 files changed, 778 insertions(+), 505 deletions(-) diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 07476ab342f6d..c1679cd111f5a 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -1919,6 +1919,11 @@ void Assembler::cmpb(Address dst, int imm8) { emit_int8(imm8); } +void Assembler::cmpb(Register dst, int imm8) { + prefix(dst); + emit_arith_b(0x80, 0xF8, dst, imm8); +} + void Assembler::cmpl(Address dst, int32_t imm32) { InstructionMark im(this); prefix(dst); @@ -9667,6 +9672,15 @@ void Assembler::vinserti64x4(XMMRegister dst, XMMRegister nds, XMMRegister src, emit_int24(0x3A, (0xC0 | encode), imm8 & 0x01); } +void Assembler::evinserti64x2(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8, int vector_len) { + assert(VM_Version::supports_avx512dq(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_is_evex_instruction(); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int24(0x38, (0xC0 | encode), imm8 & 0x03); +} + // vinsertf forms @@ -11731,6 +11745,21 @@ void Assembler::vbroadcastf128(XMMRegister dst, Address src, int vector_len) { emit_operand(dst, src, 0); } +void Assembler::evbroadcastf64x2(XMMRegister dst, Address src, int vector_len) { + assert(VM_Version::supports_avx512dq(), ""); + assert(vector_len == AVX_512bit || VM_Version::supports_avx512vl(), ""); + assert(dst != xnoreg, "sanity"); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_T2, /* input_size_in_bits */ EVEX_64bit); + attributes.set_is_evex_instruction(); + // swap src<->dst for encoding + vex_prefix(src, 0, dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x1A); + emit_operand(dst, src, 0); +} + + // gpr source broadcast forms // duplicate 1-byte integer data from src into programmed locations in dest : requires AVX512BW and AVX512VL diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 62700d1fa1bd5..eace7bb9cc169 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1239,6 +1239,7 @@ class Assembler : public AbstractAssembler { void cmpb(Address dst, int imm8); void cmpb(Address dst, Register reg); void cmpb(Register reg, Address dst); + void cmpb(Register reg, int imm8); void cmpl(Address dst, int32_t imm32); void cmpl(Register dst, int32_t imm32); @@ -2986,6 +2987,7 @@ class Assembler : public AbstractAssembler { void vinserti32x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); void vinserti32x4(XMMRegister dst, XMMRegister nds, Address src, uint8_t imm8); void vinserti64x4(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); + void evinserti64x2(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8, int vector_len); // vinsertf forms void vinsertf128(XMMRegister dst, XMMRegister nds, XMMRegister src, uint8_t imm8); @@ -3035,6 +3037,7 @@ class Assembler : public AbstractAssembler { void vbroadcastsd(XMMRegister dst, XMMRegister src, int vector_len); void vbroadcastsd(XMMRegister dst, Address src, int vector_len); void vbroadcastf128(XMMRegister dst, Address src, int vector_len); + void evbroadcastf64x2(XMMRegister dst, Address src, int vector_len); // gpr sourced byte/word/dword/qword replicate void evpbroadcastb(XMMRegister dst, Register src, int vector_len); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 0a81da4f7c957..71777fbfffea2 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -376,11 +376,22 @@ class StubGenerator: public StubCodeGenerator { void roundDec(XMMRegister key, int rnum); void lastroundDec(XMMRegister key, int rnum); void gfmul_avx512(XMMRegister ghash, XMMRegister hkey); - void generateHtbl_48_block_zmm(Register htbl, Register avx512_subkeyHtbl, Register rscratch); - void ghash16_encrypt16_parallel(Register key, Register subkeyHtbl, XMMRegister ctr_blockx, - XMMRegister aad_hashx, Register in, Register out, Register data, Register pos, bool reduction, - XMMRegister addmask, bool no_ghash_input, Register rounds, Register ghash_pos, - bool final_reduction, int index, XMMRegister counter_inc_mask); + void ghash16_encrypt_parallel16_avx512(Register in, Register out, Register ct, Register pos, Register avx512_subkeyHtbl, + Register CTR_CHECK, Register NROUNDS, Register key, XMMRegister CTR, XMMRegister GHASH, + XMMRegister ADDBE_4x4, XMMRegister ADDBE_1234, XMMRegister ADD_1234, XMMRegister SHUF_MASK, + bool hk_broadcast, bool is_hash_start, bool do_hash_reduction, bool do_hash_hxor, + bool no_ghash_in, int ghashin_offset, int aesout_offset, int hashkey_offset); + void generateHtbl_32_blocks_avx512(Register htbl, Register avx512_htbl); + void initial_blocks_16_avx512(Register in, Register out, Register ct, Register pos, Register key, Register avx512_subkeyHtbl, + Register CTR_CHECK, Register rounds, XMMRegister CTR, XMMRegister GHASH, XMMRegister ADDBE_4x4, + XMMRegister ADDBE_1234, XMMRegister ADD_1234, XMMRegister SHUF_MASK, int stack_offset); + void gcm_enc_dec_last_avx512(Register len, Register in, Register pos, XMMRegister HASH, XMMRegister SHUFM, Register subkeyHtbl, + int ghashin_offset, int hashkey_offset, bool start_ghash, bool do_reduction); + void ghash16_avx512(bool start_ghash, bool do_reduction, bool uload_shuffle, bool hk_broadcast, bool do_hxor, + Register in, Register pos, Register subkeyHtbl, XMMRegister HASH, XMMRegister SHUFM, int in_offset, + int in_disp, int displacement, int hashkey_offset); + void aesgcm_avx512(Register in, Register len, Register ct, Register out, Register key, + Register state, Register subkeyHtbl, Register avx512_subkeyHtbl, Register counter); // AVX2 AES-GCM related functions void initial_blocks_avx2(XMMRegister ctr, Register rounds, Register key, Register len, Register in, Register out, Register ct, XMMRegister aad_hashx, Register pos); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index 9744169498c8b..f14d368c376e1 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2019, 2023, Intel Corporation. All rights reserved. +* Copyright (c) 2019, 2024, Intel Corporation. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -172,6 +172,38 @@ static address ghash_polynomial_two_one_addr() { return (address)GHASH_POLYNOMIAL_TWO_ONE; } +// This mask is used for incrementing counter value +ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_ADDBE_4444[] = { + 0x0000000000000000ULL, 0x0400000000000000ULL, + 0x0000000000000000ULL, 0x0400000000000000ULL, + 0x0000000000000000ULL, 0x0400000000000000ULL, + 0x0000000000000000ULL, 0x0400000000000000ULL, +}; +static address counter_mask_addbe_4444_addr() { + return (address)COUNTER_MASK_ADDBE_4444; +} + +// This mask is used for incrementing counter value +ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_ADDBE_1234[] = { + 0x0000000000000000ULL, 0x0100000000000000ULL, + 0x0000000000000000ULL, 0x0200000000000000ULL, + 0x0000000000000000ULL, 0x0300000000000000ULL, + 0x0000000000000000ULL, 0x0400000000000000ULL, +}; +static address counter_mask_addbe_1234_addr() { + return (address)COUNTER_MASK_ADDBE_1234; +} + +// This mask is used for incrementing counter value +ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_ADD_1234[] = { + 0x0000000000000001ULL, 0x0000000000000000ULL, + 0x0000000000000002ULL, 0x0000000000000000ULL, + 0x0000000000000003ULL, 0x0000000000000000ULL, + 0x0000000000000004ULL, 0x0000000000000000ULL, +}; +static address counter_mask_add_1234_addr() { + return (address)COUNTER_MASK_ADD_1234; +} // AES intrinsic stubs @@ -209,10 +241,10 @@ void StubGenerator::generate_aes_stubs() { // len = rdx (c_rarg1) | rdi (c_rarg1) // ct = r8 (c_rarg2) | rdx (c_rarg2) // out = r9 (c_rarg3) | rcx (c_rarg3) -// key = r10 | r8 (c_rarg4) -// state = r13 | r9 (c_rarg5) -// subkeyHtbl = r14 | r11 -// counter = rsi | r12 +// key = rsi | r8 (c_rarg4) +// state = rdi | r9 (c_rarg5) +// subkeyHtbl = r10 | r10 +// counter = r11 | r11 // // Output: // rax - number of processed bytes @@ -230,31 +262,31 @@ address StubGenerator::generate_galoisCounterMode_AESCrypt() { const Register key = c_rarg4; const Register state = c_rarg5; const Address subkeyH_mem(rbp, 2 * wordSize); - const Register subkeyHtbl = r11; - const Register avx512_subkeyHtbl = r13; + const Register subkeyHtbl = r10; + const Register avx512_subkeyHtbl = r12; const Address counter_mem(rbp, 3 * wordSize); - const Register counter = r12; + const Register counter = r11; #else const Address key_mem(rbp, 6 * wordSize); - const Register key = r10; + const Register key = rsi; const Address state_mem(rbp, 7 * wordSize); - const Register state = r13; + const Register state = rdi; const Address subkeyH_mem(rbp, 8 * wordSize); - const Register subkeyHtbl = r14; + const Register subkeyHtbl = r10; const Register avx512_subkeyHtbl = r12; const Address counter_mem(rbp, 9 * wordSize); - const Register counter = rsi; + const Register counter = r11; #endif __ enter(); // Save state before entering routine - __ push(r12); - __ push(r13); - __ push(r14); - __ push(r15); - __ push(rbx); + __ push(r12);//holds pointer to avx512_subkeyHtbl + __ push(r14);//holds CTR_CHECK value to check for overflow + __ push(r15);//holds number of rounds + __ push(rbx);//scratch register #ifdef _WIN64 // on win64, fill len_reg from stack position __ push(rsi); + __ push(rdi); __ movptr(key, key_mem); __ movptr(state, state_mem); #endif @@ -262,24 +294,24 @@ address StubGenerator::generate_galoisCounterMode_AESCrypt() { __ movptr(counter, counter_mem); // Align stack __ andq(rsp, -64); - __ subptr(rsp, 96 * longSize); // Create space on the stack for htbl entries + __ subptr(rsp, 200 * longSize); // Create space on the stack for 64 htbl entries and 8 zmm AES entries __ movptr(avx512_subkeyHtbl, rsp); - aesgcm_encrypt(in, len, ct, out, key, state, subkeyHtbl, avx512_subkeyHtbl, counter); + aesgcm_avx512(in, len, ct, out, key, state, subkeyHtbl, avx512_subkeyHtbl, counter); __ vzeroupper(); // Restore state before leaving routine #ifdef _WIN64 __ lea(rsp, Address(rbp, -6 * wordSize)); + __ pop(rdi); __ pop(rsi); #else - __ lea(rsp, Address(rbp, -5 * wordSize)); + __ lea(rsp, Address(rbp, -4 * wordSize)); #endif __ pop(rbx); __ pop(r15); __ pop(r14); - __ pop(r13); __ pop(r12); __ leave(); // required for proper stackwalking of RuntimeStub frame @@ -2708,87 +2740,100 @@ void StubGenerator::gfmul_avx512(XMMRegister GH, XMMRegister HK) { __ vpternlogq(GH, 0x96, TMP1, TMP2, Assembler::AVX_512bit); } -void StubGenerator::generateHtbl_48_block_zmm(Register htbl, Register avx512_htbl, Register rscratch) { +// Holds 64 Htbl entries, 32 HKey and 32 HkKey (derived from HKey) +void StubGenerator::generateHtbl_32_blocks_avx512(Register htbl, Register avx512_htbl) { const XMMRegister HK = xmm6; - const XMMRegister ZT5 = xmm4; - const XMMRegister ZT7 = xmm7; - const XMMRegister ZT8 = xmm8; - - Label GFMUL_AVX512; + const XMMRegister ZT1 = xmm0, ZT2 = xmm1, ZT3 = xmm2, ZT4 = xmm3; + const XMMRegister ZT5 = xmm4, ZT6 = xmm5, ZT7 = xmm7, ZT8 = xmm8; + const XMMRegister ZT10 = xmm10, ZT11 = xmm11, ZT12 = xmm12; __ movdqu(HK, Address(htbl, 0)); - __ movdqu(xmm10, ExternalAddress(ghash_long_swap_mask_addr()), rscratch); - __ vpshufb(HK, HK, xmm10, Assembler::AVX_128bit); - - __ movdqu(xmm11, ExternalAddress(ghash_polynomial_addr()), rscratch); - __ movdqu(xmm12, ExternalAddress(ghash_polynomial_two_one_addr()), rscratch); + __ movdqu(ZT10, ExternalAddress(ghash_long_swap_mask_addr()), r15); + __ vpshufb(HK, HK, ZT10, Assembler::AVX_128bit); + __ movdqu(ZT11, ExternalAddress(ghash_polynomial_addr()), r15); + __ movdqu(ZT12, ExternalAddress(ghash_polynomial_two_one_addr()), r15); // Compute H ^ 2 from the input subkeyH - __ movdqu(xmm2, xmm6); - __ vpsllq(xmm6, xmm6, 1, Assembler::AVX_128bit); - __ vpsrlq(xmm2, xmm2, 63, Assembler::AVX_128bit); - __ movdqu(xmm1, xmm2); - __ vpslldq(xmm2, xmm2, 8, Assembler::AVX_128bit); - __ vpsrldq(xmm1, xmm1, 8, Assembler::AVX_128bit); - __ vpor(xmm6, xmm6, xmm2, Assembler::AVX_128bit); + __ movdqu(ZT3, HK); + __ vpsllq(HK, HK, 1, Assembler::AVX_128bit); + __ vpsrlq(ZT3, ZT3, 63, Assembler::AVX_128bit); + __ movdqu(ZT2, ZT3); + __ vpslldq(ZT3, ZT3, 8, Assembler::AVX_128bit); + __ vpsrldq(ZT2, ZT2, 8, Assembler::AVX_128bit); + __ vpor(HK, HK, ZT3, Assembler::AVX_128bit); + __ vpshufd(ZT3, ZT2, 0x24, Assembler::AVX_128bit); + __ vpcmpeqd(ZT3, ZT3, ZT12, Assembler::AVX_128bit); + __ vpand(ZT3, ZT3, ZT11, Assembler::AVX_128bit); + __ vpxor(HK, HK, ZT3, Assembler::AVX_128bit); + __ movdqu(Address(avx512_htbl, 16 * 31), HK); // H ^ 2 - __ vpshufd(xmm2, xmm1, 0x24, Assembler::AVX_128bit); - __ vpcmpeqd(xmm2, xmm2, xmm12, Assembler::AVX_128bit); - __ vpand(xmm2, xmm2, xmm11, Assembler::AVX_128bit); - __ vpxor(xmm6, xmm6, xmm2, Assembler::AVX_128bit); - __ movdqu(Address(avx512_htbl, 16 * 47), xmm6); // H ^ 2 - // Compute the remaining three powers of H using XMM registers and all following powers using ZMM __ movdqu(ZT5, HK); - __ vinserti32x4(ZT7, ZT7, HK, 3); + __ evinserti64x2(ZT7, ZT7, HK, 3, Assembler::AVX_512bit); + //calculate HashKey ^ 2 << 1 mod poly gfmul_avx512(ZT5, HK); - __ movdqu(Address(avx512_htbl, 16 * 46), ZT5); // H ^ 2 * 2 - __ vinserti32x4(ZT7, ZT7, ZT5, 2); + __ movdqu(Address(avx512_htbl, 16 * 30), ZT5); + __ evinserti64x2(ZT7, ZT7, ZT5, 2, Assembler::AVX_512bit); + //calculate HashKey ^ 3 << 1 mod poly gfmul_avx512(ZT5, HK); - __ movdqu(Address(avx512_htbl, 16 * 45), ZT5); // H ^ 2 * 3 - __ vinserti32x4(ZT7, ZT7, ZT5, 1); + __ movdqu(Address(avx512_htbl, 16 * 29), ZT5); + __ evinserti64x2(ZT7, ZT7, ZT5, 1, Assembler::AVX_512bit); + //calculate HashKey ^ 4 << 1 mod poly gfmul_avx512(ZT5, HK); - __ movdqu(Address(avx512_htbl, 16 * 44), ZT5); // H ^ 2 * 4 - __ vinserti32x4(ZT7, ZT7, ZT5, 0); - - __ evshufi64x2(ZT5, ZT5, ZT5, 0x00, Assembler::AVX_512bit); - __ evmovdquq(ZT8, ZT7, Assembler::AVX_512bit); - gfmul_avx512(ZT7, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 40), ZT7, Assembler::AVX_512bit); - __ evshufi64x2(ZT5, ZT7, ZT7, 0x00, Assembler::AVX_512bit); - gfmul_avx512(ZT8, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 36), ZT8, Assembler::AVX_512bit); + __ movdqu(Address(avx512_htbl, 16 * 28), ZT5); + __ evinserti64x2(ZT7, ZT7, ZT5, 0, Assembler::AVX_512bit); + // ZT5 amd ZT7 to be cleared(hash key) + //calculate HashKeyK = HashKey x POLY + __ evmovdquq(xmm11, ExternalAddress(ghash_polynomial_addr()), Assembler::AVX_512bit, r15); + __ evpclmulqdq(ZT1, ZT7, xmm11, 0x10, Assembler::AVX_512bit); + __ vpshufd(ZT2, ZT7, 78, Assembler::AVX_512bit); + __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit); + __ evmovdquq(Address(avx512_htbl, 16 * 60), ZT1, Assembler::AVX_512bit); + //**ZT1 amd ZT2 to be cleared(hash key) + + //switch to 4x128 - bit computations now + __ evshufi64x2(ZT5, ZT5, ZT5, 0x00, Assembler::AVX_512bit); //;; broadcast HashKey ^ 4 across all ZT5 + __ evmovdquq(ZT8, ZT7, Assembler::AVX_512bit);//; save HashKey ^ 4 to HashKey ^ 1 in ZT8 + //**ZT8 to be cleared(hash key) + + //calculate HashKey ^ 5 << 1 mod poly, HashKey ^ 6 << 1 mod poly, ... HashKey ^ 8 << 1 mod poly gfmul_avx512(ZT7, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 32), ZT7, Assembler::AVX_512bit); - gfmul_avx512(ZT8, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 28), ZT8, Assembler::AVX_512bit); - gfmul_avx512(ZT7, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 24), ZT7, Assembler::AVX_512bit); - gfmul_avx512(ZT8, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 20), ZT8, Assembler::AVX_512bit); - gfmul_avx512(ZT7, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 16), ZT7, Assembler::AVX_512bit); - gfmul_avx512(ZT8, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 12), ZT8, Assembler::AVX_512bit); - gfmul_avx512(ZT7, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 8), ZT7, Assembler::AVX_512bit); - gfmul_avx512(ZT8, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 4), ZT8, Assembler::AVX_512bit); - gfmul_avx512(ZT7, ZT5); - __ evmovdquq(Address(avx512_htbl, 16 * 0), ZT7, Assembler::AVX_512bit); - __ ret(0); -} - -#define vclmul_reduce(out, poly, hi128, lo128, tmp0, tmp1) \ -__ evpclmulqdq(tmp0, poly, lo128, 0x01, Assembler::AVX_512bit); \ -__ vpslldq(tmp0, tmp0, 8, Assembler::AVX_512bit); \ -__ evpxorq(tmp0, lo128, tmp0, Assembler::AVX_512bit); \ -__ evpclmulqdq(tmp1, poly, tmp0, 0x00, Assembler::AVX_512bit); \ -__ vpsrldq(tmp1, tmp1, 4, Assembler::AVX_512bit); \ -__ evpclmulqdq(out, poly, tmp0, 0x10, Assembler::AVX_512bit); \ -__ vpslldq(out, out, 4, Assembler::AVX_512bit); \ -__ vpternlogq(out, 0x96, tmp1, hi128, Assembler::AVX_512bit); \ + __ evmovdquq(Address(avx512_htbl, 16 * 24), ZT7, Assembler::AVX_512bit);//; HashKey ^ 8 to HashKey ^ 5 in ZT7 now + + //calculate HashKeyX = HashKey x POLY + __ evpclmulqdq(ZT1, ZT7, xmm11, 0x10, Assembler::AVX_512bit); + __ vpshufd(ZT2, ZT7, 78, Assembler::AVX_512bit); + __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit); + __ evmovdquq(Address(avx512_htbl, 16 * 56), ZT1, Assembler::AVX_512bit); + + __ evshufi64x2(ZT5, ZT7, ZT7, 0x00, Assembler::AVX_512bit);//;; broadcast HashKey ^ 8 across all ZT5 + + for (int i = 20, j = 52; i > 0;) { + gfmul_avx512(ZT8, ZT5); + __ evmovdquq(Address(avx512_htbl, 16 * i), ZT8, Assembler::AVX_512bit); + //calculate HashKeyK = HashKey x POLY + __ evpclmulqdq(ZT1, ZT8, xmm11, 0x10, Assembler::AVX_512bit); + __ vpshufd(ZT2, ZT8, 78, Assembler::AVX_512bit); + __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit); + __ evmovdquq(Address(avx512_htbl, 16 * j), ZT1, Assembler::AVX_512bit); + + i -= 4; + j -= 4; + //compute HashKey ^ (8 + n), HashKey ^ (7 + n), ... HashKey ^ (5 + n) + gfmul_avx512(ZT7, ZT5); + __ evmovdquq(Address(avx512_htbl, 16 * i), ZT7, Assembler::AVX_512bit); + + //calculate HashKeyK = HashKey x POLY + __ evpclmulqdq(ZT1, ZT7, xmm11, 0x10, Assembler::AVX_512bit); + __ vpshufd(ZT2, ZT7, 78, Assembler::AVX_512bit); + __ evpxorq(ZT1, ZT1, ZT2, Assembler::AVX_512bit); + __ evmovdquq(Address(avx512_htbl, 16 * j), ZT1, Assembler::AVX_512bit); + + i -= 4; + j -= 4; + } + } #define vhpxori4x128(reg, tmp) \ __ vextracti64x4(tmp, reg, 1); \ @@ -2820,21 +2865,17 @@ __ evmovdquq(dst2, Address(src, position, Address::times_1, 1 * 64), Assembler:: __ evmovdquq(dst3, Address(src, position, Address::times_1, 2 * 64), Assembler::AVX_512bit); \ __ evmovdquq(dst4, Address(src, position, Address::times_1, 3 * 64), Assembler::AVX_512bit); \ -#define carrylessMultiply(dst00, dst01, dst10, dst11, ghdata, hkey) \ -__ evpclmulqdq(dst00, ghdata, hkey, 0x00, Assembler::AVX_512bit); \ -__ evpclmulqdq(dst01, ghdata, hkey, 0x01, Assembler::AVX_512bit); \ -__ evpclmulqdq(dst10, ghdata, hkey, 0x10, Assembler::AVX_512bit); \ -__ evpclmulqdq(dst11, ghdata, hkey, 0x11, Assembler::AVX_512bit); \ - -#define shuffleExorRnd1Key(dst0, dst1, dst2, dst3, shufmask, rndkey) \ -__ vpshufb(dst0, dst0, shufmask, Assembler::AVX_512bit); \ -__ evpxorq(dst0, dst0, rndkey, Assembler::AVX_512bit); \ -__ vpshufb(dst1, dst1, shufmask, Assembler::AVX_512bit); \ -__ evpxorq(dst1, dst1, rndkey, Assembler::AVX_512bit); \ -__ vpshufb(dst2, dst2, shufmask, Assembler::AVX_512bit); \ -__ evpxorq(dst2, dst2, rndkey, Assembler::AVX_512bit); \ -__ vpshufb(dst3, dst3, shufmask, Assembler::AVX_512bit); \ -__ evpxorq(dst3, dst3, rndkey, Assembler::AVX_512bit); \ +#define carrylessMultiply(dst00, dst01, dst10, dst11, ghdata, hkey2, hkey1) \ +__ evpclmulqdq(dst00, ghdata, hkey2, 0x00, Assembler::AVX_512bit); \ +__ evpclmulqdq(dst01, ghdata, hkey2, 0x10, Assembler::AVX_512bit); \ +__ evpclmulqdq(dst10, ghdata, hkey1, 0x01, Assembler::AVX_512bit); \ +__ evpclmulqdq(dst11, ghdata, hkey1, 0x11, Assembler::AVX_512bit); \ + +#define shuffle(dst0, dst1, dst2, dst3, src0, src1, src2, src3, shufmask) \ +__ vpshufb(dst0, src0, shufmask, Assembler::AVX_512bit); \ +__ vpshufb(dst1, src1, shufmask, Assembler::AVX_512bit); \ +__ vpshufb(dst2, src2, shufmask, Assembler::AVX_512bit); \ +__ vpshufb(dst3, src3, shufmask, Assembler::AVX_512bit); \ #define xorBeforeStore(dst0, dst1, dst2, dst3, src0, src1, src2, src3) \ __ evpxorq(dst0, dst0, src0, Assembler::AVX_512bit); \ @@ -2848,211 +2889,462 @@ __ vpternlogq(dst1, 0x96, src12, src13, Assembler::AVX_512bit); \ __ vpternlogq(dst2, 0x96, src22, src23, Assembler::AVX_512bit); \ __ vpternlogq(dst3, 0x96, src32, src33, Assembler::AVX_512bit); \ -void StubGenerator::ghash16_encrypt16_parallel(Register key, Register subkeyHtbl, XMMRegister ctr_blockx, XMMRegister aad_hashx, - Register in, Register out, Register data, Register pos, bool first_time_reduction, XMMRegister addmask, bool ghash_input, Register rounds, - Register ghash_pos, bool final_reduction, int i, XMMRegister counter_inc_mask) { - Label AES_192, AES_256, LAST_AES_RND; +//schoolbook multiply of 16 blocks(8 x 16 bytes) +//it is assumed that data read is already shuffledand +void StubGenerator::ghash16_avx512(bool start_ghash, bool do_reduction, bool uload_shuffle, bool hk_broadcast, bool do_hxor, + Register in, Register pos, Register subkeyHtbl, XMMRegister HASH, XMMRegister SHUFM, int in_offset, + int in_disp, int displacement, int hashkey_offset) { const XMMRegister ZTMP0 = xmm0; const XMMRegister ZTMP1 = xmm3; const XMMRegister ZTMP2 = xmm4; const XMMRegister ZTMP3 = xmm5; + const XMMRegister ZTMP4 = xmm6; const XMMRegister ZTMP5 = xmm7; const XMMRegister ZTMP6 = xmm10; const XMMRegister ZTMP7 = xmm11; const XMMRegister ZTMP8 = xmm12; const XMMRegister ZTMP9 = xmm13; - const XMMRegister ZTMP10 = xmm15; - const XMMRegister ZTMP11 = xmm16; - const XMMRegister ZTMP12 = xmm17; + const XMMRegister ZTMPA = xmm26; + const XMMRegister ZTMPB = xmm23; + const XMMRegister GH = xmm24; + const XMMRegister GL = xmm25; + const int hkey_gap = 16 * 32; + + if (uload_shuffle) { + __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp), Assembler::AVX_512bit); + __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit); + } else { + __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp), Assembler::AVX_512bit); + } - const XMMRegister ZTMP13 = xmm19; - const XMMRegister ZTMP14 = xmm20; - const XMMRegister ZTMP15 = xmm21; - const XMMRegister ZTMP16 = xmm30; - const XMMRegister ZTMP17 = xmm31; - const XMMRegister ZTMP18 = xmm1; - const XMMRegister ZTMP19 = xmm2; - const XMMRegister ZTMP20 = xmm8; - const XMMRegister ZTMP21 = xmm22; - const XMMRegister ZTMP22 = xmm23; + if (start_ghash) { + __ evpxorq(ZTMP9, ZTMP9, HASH, Assembler::AVX_512bit); + } + if (hk_broadcast) { + __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 0 * 64), Assembler::AVX_512bit); + __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 0 * 64), Assembler::AVX_512bit); + } else { + __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 0 * 64), Assembler::AVX_512bit); + __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 0 * 64), Assembler::AVX_512bit); + } + + carrylessMultiply(ZTMP0, ZTMP1, ZTMP2, ZTMP3, ZTMP9, ZTMPA, ZTMP8); + + //ghash blocks 4 - 7 + if (uload_shuffle) { + __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 64), Assembler::AVX_512bit); + __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit); + } else { + __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 64), Assembler::AVX_512bit); + } + + if (hk_broadcast) { + __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 1 * 64), Assembler::AVX_512bit);; + __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 1 * 64), Assembler::AVX_512bit); + } else { + __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 1 * 64), Assembler::AVX_512bit); + __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 1 * 64), Assembler::AVX_512bit); + } + + carrylessMultiply(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP9, ZTMPA, ZTMP8); + + //update sums + if (start_ghash) { + __ evpxorq(GL, ZTMP0, ZTMP2, Assembler::AVX_512bit);//T2 = THL + TLL + __ evpxorq(GH, ZTMP1, ZTMP3, Assembler::AVX_512bit);//T1 = THH + TLH + } else { //mid, end, end_reduce + __ vpternlogq(GL, 0x96, ZTMP0, ZTMP2, Assembler::AVX_512bit);//T2 = THL + TLL + __ vpternlogq(GH, 0x96, ZTMP1, ZTMP3, Assembler::AVX_512bit);//T1 = THH + TLH + } + //ghash blocks 8 - 11 + if (uload_shuffle) { + __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 128), Assembler::AVX_512bit); + __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit); + } else { + __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 128), Assembler::AVX_512bit); + } + if (hk_broadcast) { + __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 2 * 64), Assembler::AVX_512bit); + __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 2 * 64), Assembler::AVX_512bit); + } else { + __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 2 * 64), Assembler::AVX_512bit); + __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 2 * 64), Assembler::AVX_512bit); + } + + carrylessMultiply(ZTMP0, ZTMP1, ZTMP2, ZTMP3, ZTMP9, ZTMPA, ZTMP8); + + //update sums + __ vpternlogq(GL, 0x96, ZTMP6, ZTMP4, Assembler::AVX_512bit);//T2 = THL + TLL + __ vpternlogq(GH, 0x96, ZTMP7, ZTMP5, Assembler::AVX_512bit);//T1 = THH + TLH + //ghash blocks 12 - 15 + if (uload_shuffle) { + __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 192), Assembler::AVX_512bit); + __ vpshufb(ZTMP9, ZTMP9, SHUFM, Assembler::AVX_512bit); + } else { + __ evmovdquq(ZTMP9, Address(subkeyHtbl, in_offset * 16 + in_disp + 192), Assembler::AVX_512bit); + } + + if (hk_broadcast) { + __ evbroadcastf64x2(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 3 * 64), Assembler::AVX_512bit); + __ evbroadcastf64x2(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 3 * 64), Assembler::AVX_512bit); + } else { + __ evmovdquq(ZTMP8, Address(subkeyHtbl, hashkey_offset + displacement + 3 * 64), Assembler::AVX_512bit); + __ evmovdquq(ZTMPA, Address(subkeyHtbl, hashkey_offset + displacement + hkey_gap + 3 * 64), Assembler::AVX_512bit); + } + carrylessMultiply(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP9, ZTMPA, ZTMP8); + + //update sums + xorGHASH(GL, GH, GL, GH, ZTMP0, ZTMP2, ZTMP1, ZTMP3, ZTMP6, ZTMP4, ZTMP7, ZTMP5); + + if (do_reduction) { + //new reduction + __ evmovdquq(ZTMPB, ExternalAddress(ghash_polynomial_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); + __ evpclmulqdq(HASH, GL, ZTMPB, 0x10, Assembler::AVX_512bit); + __ vpshufd(ZTMP0, GL, 78, Assembler::AVX_512bit); + __ vpternlogq(HASH, 0x96, GH, ZTMP0, Assembler::AVX_512bit); + if (do_hxor) { + vhpxori4x128(HASH, ZTMP0); + } + } +} - // Pre increment counters - __ vpaddd(ZTMP0, ctr_blockx, counter_inc_mask, Assembler::AVX_512bit); - __ vpaddd(ZTMP1, ZTMP0, counter_inc_mask, Assembler::AVX_512bit); - __ vpaddd(ZTMP2, ZTMP1, counter_inc_mask, Assembler::AVX_512bit); - __ vpaddd(ZTMP3, ZTMP2, counter_inc_mask, Assembler::AVX_512bit); - // Save counter value - __ evmovdquq(ctr_blockx, ZTMP3, Assembler::AVX_512bit); - - // Reuse ZTMP17 / ZTMP18 for loading AES Keys - // Pre-load AES round keys - ev_load_key(ZTMP17, key, 0, xmm29); - ev_load_key(ZTMP18, key, 1 * 16, xmm29); - - // ZTMP19 & ZTMP20 used for loading hash key - // Pre-load hash key - __ evmovdquq(ZTMP19, Address(subkeyHtbl, i * 64), Assembler::AVX_512bit); - __ evmovdquq(ZTMP20, Address(subkeyHtbl, ++i * 64), Assembler::AVX_512bit); - // Load data for computing ghash - __ evmovdquq(ZTMP21, Address(data, ghash_pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); - __ vpshufb(ZTMP21, ZTMP21, xmm24, Assembler::AVX_512bit); - - // Xor cipher block 0 with input ghash, if available - if (ghash_input) { - __ evpxorq(ZTMP21, ZTMP21, aad_hashx, Assembler::AVX_512bit); +//Stitched GHASH of 16 blocks(with reduction) with encryption of 0 blocks +void StubGenerator::gcm_enc_dec_last_avx512(Register len, Register in, Register pos, XMMRegister HASH, XMMRegister SHUFM, Register subkeyHtbl, + int ghashin_offset, int hashkey_offset, bool start_ghash, bool do_reduction) { + //there is 0 blocks to cipher so there are only 16 blocks for ghash and reduction + ghash16_avx512(start_ghash, do_reduction, false, false, true, in, pos, subkeyHtbl, HASH, SHUFM, ghashin_offset, 0, 0, hashkey_offset); +} + +//Main GCM macro stitching cipher with GHASH +//encrypts 16 blocks at a time +//ghash the 16 previously encrypted ciphertext blocks +void StubGenerator::ghash16_encrypt_parallel16_avx512(Register in, Register out, Register ct, Register pos, Register avx512_subkeyHtbl, + Register CTR_CHECK, Register NROUNDS, Register key, XMMRegister CTR_BE, XMMRegister GHASH_IN, + XMMRegister ADDBE_4x4, XMMRegister ADDBE_1234, XMMRegister ADD_1234, XMMRegister SHFMSK, + bool hk_broadcast, bool is_hash_start, bool do_hash_reduction, bool do_hash_hxor, + bool no_ghash_in, int ghashin_offset, int aesout_offset, int hashkey_offset) { + const XMMRegister B00_03 = xmm0; + const XMMRegister B04_07 = xmm3; + const XMMRegister B08_11 = xmm4; + const XMMRegister B12_15 = xmm5; + const XMMRegister THH1 = xmm6; + const XMMRegister THL1 = xmm7; + const XMMRegister TLH1 = xmm10; + const XMMRegister TLL1 = xmm11, THH2 = xmm12, THL2 = xmm13, TLH2 = xmm15; + const XMMRegister TLL2 = xmm16, THH3 = xmm17, THL3 = xmm19, TLH3 = xmm20; + const XMMRegister TLL3 = xmm21, DATA1 = xmm17, DATA2 = xmm19, DATA3 = xmm20, DATA4 = xmm21; + const XMMRegister AESKEY1 = xmm30, AESKEY2 = xmm31; + const XMMRegister GHKEY1 = xmm1, GHKEY2 = xmm18, GHDAT1 = xmm8, GHDAT2 = xmm22; + const XMMRegister ZT = xmm23, TO_REDUCE_L = xmm25, TO_REDUCE_H = xmm24; + const int hkey_gap = 16 * 32; + + Label blocks_overflow, blocks_ok, skip_shuffle, cont, aes_256, aes_192, last_aes_rnd; + + __ cmpb(CTR_CHECK, (256 - 16)); + __ jcc(Assembler::aboveEqual, blocks_overflow); + __ vpaddd(B00_03, CTR_BE, ADDBE_1234, Assembler::AVX_512bit); + __ vpaddd(B04_07, B00_03, ADDBE_4x4, Assembler::AVX_512bit); + __ vpaddd(B08_11, B04_07, ADDBE_4x4, Assembler::AVX_512bit); + __ vpaddd(B12_15, B08_11, ADDBE_4x4, Assembler::AVX_512bit); + __ jmp(blocks_ok); + __ bind(blocks_overflow); + __ vpshufb(CTR_BE, CTR_BE, SHFMSK, Assembler::AVX_512bit); + __ evmovdquq(B12_15, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); + __ vpaddd(B00_03, CTR_BE, ADD_1234, Assembler::AVX_512bit); + __ vpaddd(B04_07, B00_03, B12_15, Assembler::AVX_512bit); + __ vpaddd(B08_11, B04_07, B12_15, Assembler::AVX_512bit); + __ vpaddd(B12_15, B08_11, B12_15, Assembler::AVX_512bit); + shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHFMSK); + + __ bind(blocks_ok); + + //pre - load constants + ev_load_key(AESKEY1, key, 0, rbx); + if (!no_ghash_in) { + __ evpxorq(GHDAT1, GHASH_IN, Address(avx512_subkeyHtbl, 16 * ghashin_offset), Assembler::AVX_512bit); + } else { + __ evmovdquq(GHDAT1, Address(avx512_subkeyHtbl, 16 * ghashin_offset), Assembler::AVX_512bit); + } + + if (hk_broadcast) { + __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 0 * 64), Assembler::AVX_512bit); + __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 0 * 64), Assembler::AVX_512bit); + } else { + __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 0 * 64), Assembler::AVX_512bit); + __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 0 * 64), Assembler::AVX_512bit); + } + + //save counter for the next round + //increment counter overflow check register + __ evshufi64x2(CTR_BE, B12_15, B12_15, 255, Assembler::AVX_512bit); + __ addb(CTR_CHECK, 16); + + //pre - load constants + ev_load_key(AESKEY2, key, 1 * 16, rbx); + __ evmovdquq(GHDAT2, Address(avx512_subkeyHtbl, 16 * (ghashin_offset +4)), Assembler::AVX_512bit); + + //stitch AES rounds with GHASH + //AES round 0 + __ evpxorq(B00_03, B00_03, AESKEY1, Assembler::AVX_512bit); + __ evpxorq(B04_07, B04_07, AESKEY1, Assembler::AVX_512bit); + __ evpxorq(B08_11, B08_11, AESKEY1, Assembler::AVX_512bit); + __ evpxorq(B12_15, B12_15, AESKEY1, Assembler::AVX_512bit); + ev_load_key(AESKEY1, key, 2 * 16, rbx); + + //GHASH 4 blocks(15 to 12) + carrylessMultiply(TLL1, TLH1, THL1, THH1, GHDAT1, GHKEY2, GHKEY1); + + if (hk_broadcast) { + __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 1 * 64), Assembler::AVX_512bit); + __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 1 * 64), Assembler::AVX_512bit); + } else { + __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 1 * 64), Assembler::AVX_512bit); + __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 1 * 64), Assembler::AVX_512bit); + } + + __ evmovdquq(GHDAT1, Address(avx512_subkeyHtbl, 16 * (ghashin_offset + 8)), Assembler::AVX_512bit); + + //AES round 1 + roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); + + ev_load_key(AESKEY2, key, 3 * 16, rbx); + + //GHASH 4 blocks(11 to 8) + carrylessMultiply(TLL2, TLH2, THL2, THH2, GHDAT2, GHKEY2, GHKEY1); + + if (hk_broadcast) { + __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 2 * 64), Assembler::AVX_512bit); + __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 2 * 64), Assembler::AVX_512bit); + } else { + __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 2 * 64 ), Assembler::AVX_512bit); + __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 2 * 64), Assembler::AVX_512bit); } - // Load data for computing ghash - __ evmovdquq(ZTMP22, Address(data, ghash_pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); - __ vpshufb(ZTMP22, ZTMP22, xmm24, Assembler::AVX_512bit); - - // stitch AES rounds with GHASH - // AES round 0, xmm24 has shuffle mask - shuffleExorRnd1Key(ZTMP0, ZTMP1, ZTMP2, ZTMP3, xmm24, ZTMP17); - // Reuse ZTMP17 / ZTMP18 for loading remaining AES Keys - ev_load_key(ZTMP17, key, 2 * 16, xmm29); - // GHASH 4 blocks - carrylessMultiply(ZTMP6, ZTMP7, ZTMP8, ZTMP5, ZTMP21, ZTMP19); - // Load the next hkey and Ghash data - __ evmovdquq(ZTMP19, Address(subkeyHtbl, ++i * 64), Assembler::AVX_512bit); - __ evmovdquq(ZTMP21, Address(data, ghash_pos, Address::times_1, 2 * 64), Assembler::AVX_512bit); - __ vpshufb(ZTMP21, ZTMP21, xmm24, Assembler::AVX_512bit); - - // AES round 1 - roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP18, key, 3 * 16, xmm29); - - // GHASH 4 blocks(11 to 8) - carrylessMultiply(ZTMP10, ZTMP12, ZTMP11, ZTMP9, ZTMP22, ZTMP20); - // Load the next hkey and GDATA - __ evmovdquq(ZTMP20, Address(subkeyHtbl, ++i * 64), Assembler::AVX_512bit); - __ evmovdquq(ZTMP22, Address(data, ghash_pos, Address::times_1, 3 * 64), Assembler::AVX_512bit); - __ vpshufb(ZTMP22, ZTMP22, xmm24, Assembler::AVX_512bit); - - // AES round 2 - roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP17, key, 4 * 16, xmm29); - - // GHASH 4 blocks(7 to 4) - carrylessMultiply(ZTMP14, ZTMP16, ZTMP15, ZTMP13, ZTMP21, ZTMP19); - // AES rounds 3 - roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP18, key, 5 * 16, xmm29); - - // Gather(XOR) GHASH for 12 blocks - xorGHASH(ZTMP5, ZTMP6, ZTMP8, ZTMP7, ZTMP9, ZTMP13, ZTMP10, ZTMP14, ZTMP12, ZTMP16, ZTMP11, ZTMP15); - - // AES rounds 4 - roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP17, key, 6 * 16, xmm29); - - // load plain / cipher text(recycle registers) - loadData(in, pos, ZTMP13, ZTMP14, ZTMP15, ZTMP16); - - // AES rounds 5 - roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP18, key, 7 * 16, xmm29); - // GHASH 4 blocks(3 to 0) - carrylessMultiply(ZTMP10, ZTMP12, ZTMP11, ZTMP9, ZTMP22, ZTMP20); - - // AES round 6 - roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP17, key, 8 * 16, xmm29); - - // gather GHASH in ZTMP6(low) and ZTMP5(high) - if (first_time_reduction) { - __ vpternlogq(ZTMP7, 0x96, ZTMP8, ZTMP12, Assembler::AVX_512bit); - __ evpxorq(xmm25, ZTMP7, ZTMP11, Assembler::AVX_512bit); - __ evpxorq(xmm27, ZTMP5, ZTMP9, Assembler::AVX_512bit); - __ evpxorq(xmm26, ZTMP6, ZTMP10, Assembler::AVX_512bit); - } else if (!first_time_reduction && !final_reduction) { - xorGHASH(ZTMP7, xmm25, xmm27, xmm26, ZTMP8, ZTMP12, ZTMP7, ZTMP11, ZTMP5, ZTMP9, ZTMP6, ZTMP10); + __ evmovdquq(GHDAT2, Address(avx512_subkeyHtbl, 16 * (ghashin_offset + 12)), Assembler::AVX_512bit); + + //AES round 2 + roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); + ev_load_key(AESKEY1, key, 4 * 16, rbx); + + //GHASH 4 blocks(7 to 4) + carrylessMultiply(TLL3, TLH3, THL3, THH3, GHDAT1, GHKEY2, GHKEY1); + + if (hk_broadcast) { + __ evbroadcastf64x2(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 3 * 64), Assembler::AVX_512bit); + __ evbroadcastf64x2(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 3 * 64), Assembler::AVX_512bit); + } else { + __ evmovdquq(GHKEY1, Address(avx512_subkeyHtbl, hashkey_offset + 3 * 64), Assembler::AVX_512bit); + __ evmovdquq(GHKEY2, Address(avx512_subkeyHtbl, hashkey_offset + hkey_gap + 3 * 64), Assembler::AVX_512bit); } - if (final_reduction) { - // Phase one: Add mid products together - // Also load polynomial constant for reduction - __ vpternlogq(ZTMP7, 0x96, ZTMP8, ZTMP12, Assembler::AVX_512bit); - __ vpternlogq(ZTMP7, 0x96, xmm25, ZTMP11, Assembler::AVX_512bit); - __ vpsrldq(ZTMP11, ZTMP7, 8, Assembler::AVX_512bit); - __ vpslldq(ZTMP7, ZTMP7, 8, Assembler::AVX_512bit); - __ evmovdquq(ZTMP12, ExternalAddress(ghash_polynomial_reduction_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); + //AES rounds 3 + roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); + ev_load_key(AESKEY2, key, 5 * 16, rbx); + + //Gather(XOR) GHASH for 12 blocks + xorGHASH(TLL1, TLH1, THL1, THH1, TLL2, TLL3, TLH2, TLH3, THL2, THL3, THH2, THH3); + + //AES rounds 4 + roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); + ev_load_key(AESKEY1, key, 6 * 16, rbx); + + //load plain / cipher text(recycle GH3xx registers) + loadData(in, pos, DATA1, DATA2, DATA3, DATA4); + + //AES rounds 5 + roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); + ev_load_key(AESKEY2, key, 7 * 16, rbx); + + //GHASH 4 blocks(3 to 0) + carrylessMultiply(TLL2, TLH2, THL2, THH2, GHDAT2, GHKEY2, GHKEY1); + + //AES round 6 + roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); + ev_load_key(AESKEY1, key, 8 * 16, rbx); + + //gather GHASH in TO_REDUCE_H / L + if (is_hash_start) { + __ evpxorq(TO_REDUCE_L, TLL2, THL2, Assembler::AVX_512bit); + __ evpxorq(TO_REDUCE_H, THH2, TLH2, Assembler::AVX_512bit); + __ vpternlogq(TO_REDUCE_L, 0x96, TLL1, THL1, Assembler::AVX_512bit); + __ vpternlogq(TO_REDUCE_H, 0x96, THH1, TLH1, Assembler::AVX_512bit); + } else { + //not the first round so sums need to be updated + xorGHASH(TO_REDUCE_L, TO_REDUCE_H, TO_REDUCE_L, TO_REDUCE_H, TLL2, THL2, THH2, TLH2, TLL1, THL1, THH1, TLH1); } - // AES round 7 - roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP18, key, 9 * 16, xmm29); - if (final_reduction) { - __ vpternlogq(ZTMP5, 0x96, ZTMP9, ZTMP11, Assembler::AVX_512bit); - __ evpxorq(ZTMP5, ZTMP5, xmm27, Assembler::AVX_512bit); - __ vpternlogq(ZTMP6, 0x96, ZTMP10, ZTMP7, Assembler::AVX_512bit); - __ evpxorq(ZTMP6, ZTMP6, xmm26, Assembler::AVX_512bit); + + //AES round 7 + roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); + ev_load_key(AESKEY2, key, 9 * 16, rbx); + + //new reduction + if (do_hash_reduction) { + __ evmovdquq(ZT, ExternalAddress(ghash_polynomial_reduction_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); + __ evpclmulqdq(THH1, TO_REDUCE_L, ZT, 0x10, Assembler::AVX_512bit); + __ vpshufd(TO_REDUCE_L, TO_REDUCE_L, 78, Assembler::AVX_512bit); + __ vpternlogq(THH1, 0x96, TO_REDUCE_H, TO_REDUCE_L, Assembler::AVX_512bit); } - // AES round 8 - roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP17, key, 10 * 16, xmm29); - - // Horizontal xor of low and high 4*128 - if (final_reduction) { - vhpxori4x128(ZTMP5, ZTMP9); - vhpxori4x128(ZTMP6, ZTMP10); + + //AES round 8 + roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); + ev_load_key(AESKEY1, key, 10 * 16, rbx); + + //horizontalxor of 4 reduced hashes + if (do_hash_hxor) { + vhpxori4x128(THH1, TLL1); } - // AES round 9 - roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - // First phase of reduction - if (final_reduction) { - __ evpclmulqdq(ZTMP10, ZTMP12, ZTMP6, 0x01, Assembler::AVX_128bit); - __ vpslldq(ZTMP10, ZTMP10, 8, Assembler::AVX_128bit); - __ evpxorq(ZTMP10, ZTMP6, ZTMP10, Assembler::AVX_128bit); + + //AES round 9 + roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); + ev_load_key(AESKEY2, key, 11 * 16, rbx); + //AES rounds up to 11 (AES192) or 13 (AES256) + //AES128 is done + __ cmpl(NROUNDS, 52); + __ jcc(Assembler::less, last_aes_rnd); + __ bind(aes_192); + roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); + ev_load_key(AESKEY1, key, 12 * 16, rbx); + roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); + __ cmpl(NROUNDS, 60); + __ jcc(Assembler::less, last_aes_rnd); + __ bind(aes_256); + ev_load_key(AESKEY2, key, 13 * 16, rbx); + roundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); + ev_load_key(AESKEY1, key, 14 * 16, rbx); + roundEncode(AESKEY2, B00_03, B04_07, B08_11, B12_15); + + __ bind(last_aes_rnd); + //the last AES round + lastroundEncode(AESKEY1, B00_03, B04_07, B08_11, B12_15); + //AESKEY1and AESKEY2 contain AES round keys + + //XOR against plain / cipher text + xorBeforeStore(B00_03, B04_07, B08_11, B12_15, DATA1, DATA2, DATA3, DATA4); + + //store cipher / plain text + storeData(out, pos, B00_03, B04_07, B08_11, B12_15); + //**B00_03, B04_07, B08_011, B12_B15 may contain sensitive data + + //shuffle cipher text blocks for GHASH computation + __ cmpptr(ct, out); + __ jcc(Assembler::notEqual, skip_shuffle); + shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHFMSK); + __ jmp(cont); + __ bind(skip_shuffle); + shuffle(B00_03, B04_07, B08_11, B12_15, DATA1, DATA2, DATA3, DATA4, SHFMSK); + + //**B00_03, B04_07, B08_011, B12_B15 overwritten with shuffled cipher text + __ bind(cont); + //store shuffled cipher text for ghashing + __ evmovdquq(Address(avx512_subkeyHtbl, 16 * aesout_offset), B00_03, Assembler::AVX_512bit); + __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (aesout_offset + 4)), B04_07, Assembler::AVX_512bit); + __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (aesout_offset + 8)), B08_11, Assembler::AVX_512bit); + __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (aesout_offset + 12)), B12_15, Assembler::AVX_512bit); +} + + +//Encrypt / decrypt the initial 16 blocks +void StubGenerator::initial_blocks_16_avx512(Register in, Register out, Register ct, Register pos, Register key, Register avx512_subkeyHtbl, + Register CTR_CHECK, Register rounds, XMMRegister CTR, XMMRegister GHASH, XMMRegister ADDBE_4x4, + XMMRegister ADDBE_1234, XMMRegister ADD_1234, XMMRegister SHUF_MASK, int stack_offset) { + const XMMRegister B00_03 = xmm7; + const XMMRegister B04_07 = xmm10; + const XMMRegister B08_11 = xmm11; + const XMMRegister B12_15 = xmm12; + const XMMRegister T0 = xmm0; + const XMMRegister T1 = xmm3; + const XMMRegister T2 = xmm4; + const XMMRegister T3 = xmm5; + const XMMRegister T4 = xmm6; + const XMMRegister T5 = xmm30; + + Label next_16_overflow, next_16_ok, cont, skip_shuffle, aes_256, aes_192, last_aes_rnd; + //prepare counter blocks + __ cmpb(CTR_CHECK, (256 - 16)); + __ jcc(Assembler::aboveEqual, next_16_overflow); + __ vpaddd(B00_03, CTR, ADDBE_1234, Assembler::AVX_512bit); + __ vpaddd(B04_07, B00_03, ADDBE_4x4, Assembler::AVX_512bit); + __ vpaddd(B08_11, B04_07, ADDBE_4x4, Assembler::AVX_512bit); + __ vpaddd(B12_15, B08_11, ADDBE_4x4, Assembler::AVX_512bit); + __ jmp(next_16_ok); + __ bind(next_16_overflow); + __ vpshufb(CTR, CTR, SHUF_MASK, Assembler::AVX_512bit); + __ evmovdquq(B12_15, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, rbx); + __ vpaddd(B00_03, CTR, ADD_1234, Assembler::AVX_512bit); + __ vpaddd(B04_07, B00_03, B12_15, Assembler::AVX_512bit); + __ vpaddd(B08_11, B04_07, B12_15, Assembler::AVX_512bit); + __ vpaddd(B12_15, B08_11, B12_15, Assembler::AVX_512bit); + shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHUF_MASK); + __ bind(next_16_ok); + __ evshufi64x2(CTR, B12_15, B12_15, 255, Assembler::AVX_512bit); + __ addb(CTR_CHECK, 16); + + //load 16 blocks of data + loadData(in, pos, T0, T1, T2, T3); + + //move to AES encryption rounds + __ movdqu(T5, ExternalAddress(key_shuffle_mask_addr()), rbx /*rscratch*/); + ev_load_key(T4, key, 0, T5); + __ evpxorq(B00_03, B00_03, T4, Assembler::AVX_512bit); + __ evpxorq(B04_07, B04_07, T4, Assembler::AVX_512bit); + __ evpxorq(B08_11, B08_11, T4, Assembler::AVX_512bit); + __ evpxorq(B12_15, B12_15, T4, Assembler::AVX_512bit); + + for (int i = 1; i < 10; i++) { + ev_load_key(T4, key, i * 16, T5); + roundEncode(T4, B00_03, B04_07, B08_11, B12_15); } + + ev_load_key(T4, key, 10 * 16, T5); __ cmpl(rounds, 52); - __ jcc(Assembler::greaterEqual, AES_192); - __ jmp(LAST_AES_RND); - // AES rounds up to 11 (AES192) or 13 (AES256) - __ bind(AES_192); - roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP18, key, 11 * 16, xmm29); - roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP17, key, 12 * 16, xmm29); + __ jcc(Assembler::less, last_aes_rnd); + __ bind(aes_192); + roundEncode(T4, B00_03, B04_07, B08_11, B12_15); + ev_load_key(T4, key, 16 * 11, T5); + roundEncode(T4, B00_03, B04_07, B08_11, B12_15); + ev_load_key(T4, key, 16 * 12, T5); __ cmpl(rounds, 60); - __ jcc(Assembler::aboveEqual, AES_256); - __ jmp(LAST_AES_RND); - - __ bind(AES_256); - roundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP18, key, 13 * 16, xmm29); - roundEncode(ZTMP18, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - ev_load_key(ZTMP17, key, 14 * 16, xmm29); - - __ bind(LAST_AES_RND); - // Second phase of reduction - if (final_reduction) { - __ evpclmulqdq(ZTMP9, ZTMP12, ZTMP10, 0x00, Assembler::AVX_128bit); - __ vpsrldq(ZTMP9, ZTMP9, 4, Assembler::AVX_128bit); // Shift-R 1-DW to obtain 2-DWs shift-R - __ evpclmulqdq(ZTMP11, ZTMP12, ZTMP10, 0x10, Assembler::AVX_128bit); - __ vpslldq(ZTMP11, ZTMP11, 4, Assembler::AVX_128bit); // Shift-L 1-DW for result - // ZTMP5 = ZTMP5 X ZTMP11 X ZTMP9 - __ vpternlogq(ZTMP5, 0x96, ZTMP11, ZTMP9, Assembler::AVX_128bit); - } - // Last AES round - lastroundEncode(ZTMP17, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - // XOR against plain / cipher text - xorBeforeStore(ZTMP0, ZTMP1, ZTMP2, ZTMP3, ZTMP13, ZTMP14, ZTMP15, ZTMP16); - // store cipher / plain text - storeData(out, pos, ZTMP0, ZTMP1, ZTMP2, ZTMP3); + __ jcc(Assembler::less, last_aes_rnd); + __ bind(aes_256); + roundEncode(T4, B00_03, B04_07, B08_11, B12_15); + ev_load_key(T4, key, 16 * 13, T5); + roundEncode(T4, B00_03, B04_07, B08_11, B12_15); + ev_load_key(T4, key, 16 * 14, T5); + + __ bind(last_aes_rnd); + lastroundEncode(T4, B00_03, B04_07, B08_11, B12_15); + + //xor against text + xorBeforeStore(B00_03, B04_07, B08_11, B12_15, T0, T1, T2, T3); + + //store + storeData(out, pos, B00_03, B04_07, B08_11, B12_15); + + __ cmpptr(ct, out); + __ jcc(Assembler::equal, skip_shuffle); + //decryption - cipher text needs to go to GHASH phase + shuffle(B00_03, B04_07, B08_11, B12_15, T0, T1, T2, T3, SHUF_MASK); + __ jmp(cont); + __ bind(skip_shuffle); + shuffle(B00_03, B04_07, B08_11, B12_15, B00_03, B04_07, B08_11, B12_15, SHUF_MASK); + + //B00_03, B04_07, B08_11, B12_15 overwritten with shuffled cipher text + __ bind(cont); + __ evmovdquq(Address(avx512_subkeyHtbl, 16 * stack_offset), B00_03, Assembler::AVX_512bit); + __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (stack_offset + 4)), B04_07, Assembler::AVX_512bit); + __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (stack_offset + 8)), B08_11, Assembler::AVX_512bit); + __ evmovdquq(Address(avx512_subkeyHtbl, 16 * (stack_offset + 12)), B12_15, Assembler::AVX_512bit); } -void StubGenerator::aesgcm_encrypt(Register in, Register len, Register ct, Register out, Register key, - Register state, Register subkeyHtbl, Register avx512_subkeyHtbl, Register counter) { - Label ENC_DEC_DONE, GENERATE_HTBL_48_BLKS, AES_192, AES_256, STORE_CT, GHASH_LAST_32, - AES_32_BLOCKS, GHASH_AES_PARALLEL, LOOP, ACCUMULATE, GHASH_16_AES_16; - const XMMRegister CTR_BLOCKx = xmm9; +void StubGenerator::aesgcm_avx512(Register in, Register len, Register ct, Register out, Register key, Register state, + Register subkeyHtbl, Register avx512_subkeyHtbl, Register counter) { + Label ENC_DEC_DONE, MESG_BELOW_32_BLKS, NO_BIG_BLKS, ENCRYPT_BIG_BLKS_NO_HXOR, + ENCRYPT_BIG_NBLKS, ENCRYPT_16_BLKS, ENCRYPT_N_GHASH_32_N_BLKS, GHASH_DONE; + const XMMRegister CTR_BLOCKx = xmm2; const XMMRegister AAD_HASHx = xmm14; - const Register pos = rax; - const Register rounds = r15; - const Register ghash_pos = NOT_WIN64( r14) WIN64_ONLY( r11 ); const XMMRegister ZTMP0 = xmm0; - const XMMRegister ZTMP1 = xmm3; - const XMMRegister ZTMP2 = xmm4; - const XMMRegister ZTMP3 = xmm5; + const XMMRegister ZTMP1 = xmm3; //**sensitive + const XMMRegister ZTMP2 = xmm4; //**sensitive(small data) + const XMMRegister ZTMP3 = xmm5; //**sensitive(small data) const XMMRegister ZTMP4 = xmm6; const XMMRegister ZTMP5 = xmm7; const XMMRegister ZTMP6 = xmm10; @@ -3066,235 +3358,170 @@ void StubGenerator::aesgcm_encrypt(Register in, Register len, Register ct, Regis const XMMRegister ZTMP14 = xmm20; const XMMRegister ZTMP15 = xmm21; const XMMRegister ZTMP16 = xmm30; - const XMMRegister COUNTER_INC_MASK = xmm18; - - __ movl(pos, 0); // Total length processed - // Min data size processed = 768 bytes - __ cmpl(len, 768); - __ jcc(Assembler::less, ENC_DEC_DONE); + const XMMRegister ZTMP17 = xmm31; + const XMMRegister ZTMP18 = xmm1; + const XMMRegister ZTMP19 = xmm18; + const XMMRegister ZTMP20 = xmm8; + const XMMRegister ZTMP21 = xmm22; + const XMMRegister ZTMP22 = xmm23; + const XMMRegister ZTMP23 = xmm26; + const XMMRegister GH = xmm24; + const XMMRegister GL = xmm25; + const XMMRegister SHUF_MASK = xmm29; + const XMMRegister ADDBE_4x4 = xmm27; + const XMMRegister ADDBE_1234 = xmm28; + const XMMRegister ADD_1234 = xmm9; + const KRegister MASKREG = k1; + const Register pos = rax; + const Register rounds = r15; + const Register CTR_CHECK = r14; - // Generate 48 constants for htbl - __ call(GENERATE_HTBL_48_BLKS, relocInfo::none); - int index = 0; // Index for choosing subkeyHtbl entry - __ movl(ghash_pos, 0); // Pointer for ghash read and store operations + const int stack_offset = 64; + const int ghashin_offset = 64; + const int aesout_offset = 64; + const int hashkey_offset = 0; + const int hashkey_gap = 16 * 32; + const int HashKey_32 = 0; + const int HashKey_16 = 16 * 16; - // Move initial counter value and STATE value into variables + __ movl(pos, 0); + __ cmpl(len, 256); + __ jcc(Assembler::lessEqual, ENC_DEC_DONE); + + /* Structure of the Htbl is as follows: + * Where 0 - 31 we have 32 Hashkey's and 32-63 we have 32 HashKeyK (derived from HashKey) + * Rest 8 entries are for storing CTR values post AES rounds + * ---------------------------------------------------------------------------------------- + Hashkey32 -> 16 * 0 + Hashkey31 -> 16 * 1 + Hashkey30 -> 16 * 2 + ........ + Hashkey1 -> 16 * 31 + --------------------- + HaskeyK32 -> 16 * 32 + HashkeyK31 -> 16 * 33 + ......... + HashkeyK1 -> 16 * 63 + --------------------- + 1st set of AES Entries + B00_03 -> 16 * 64 + B04_07 -> 16 * 68 + B08_11 -> 16 * 72 + B12_15 -> 16 * 80 + --------------------- + 2nd set of AES Entries + B00_03 -> 16 * 84 + B04_07 -> 16 * 88 + B08_11 -> 16 * 92 + B12_15 -> 16 * 96 + ---------------------*/ + generateHtbl_32_blocks_avx512(subkeyHtbl, avx512_subkeyHtbl); + + //Move initial counter value and STATE value into variables __ movdqu(CTR_BLOCKx, Address(counter, 0)); __ movdqu(AAD_HASHx, Address(state, 0)); - // Load lswap mask for ghash + + //Load lswap mask for ghash __ movdqu(xmm24, ExternalAddress(ghash_long_swap_mask_addr()), rbx /*rscratch*/); - // Shuffle input state using lswap mask + //Shuffle input state using lswap mask __ vpshufb(AAD_HASHx, AAD_HASHx, xmm24, Assembler::AVX_128bit); // Compute #rounds for AES based on the length of the key array __ movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); - // Broadcast counter value to 512 bit register + __ evmovdquq(ADDBE_4x4, ExternalAddress(counter_mask_addbe_4444_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); + __ evmovdquq(ADDBE_1234, ExternalAddress(counter_mask_addbe_1234_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); + __ evmovdquq(SHUF_MASK, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); + __ evmovdquq(ADD_1234, ExternalAddress(counter_mask_add_1234_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); + + //Shuffle counter, subtract 1 from the pre-incremented counter value and broadcast counter value to 512 bit register + __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_128bit); + __ vpsubd(CTR_BLOCKx, CTR_BLOCKx, ADD_1234, Assembler::AVX_128bit); __ evshufi64x2(CTR_BLOCKx, CTR_BLOCKx, CTR_BLOCKx, 0, Assembler::AVX_512bit); - // Load counter shuffle mask - __ evmovdquq(xmm24, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); - // Shuffle counter - __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, xmm24, Assembler::AVX_512bit); - - // Load mask for incrementing counter - __ evmovdquq(COUNTER_INC_MASK, ExternalAddress(counter_mask_linc4_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); - // Pre-increment counter - __ vpaddd(ZTMP5, CTR_BLOCKx, ExternalAddress(counter_mask_linc0_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); - __ vpaddd(ZTMP6, ZTMP5, COUNTER_INC_MASK, Assembler::AVX_512bit); - __ vpaddd(ZTMP7, ZTMP6, COUNTER_INC_MASK, Assembler::AVX_512bit); - __ vpaddd(ZTMP8, ZTMP7, COUNTER_INC_MASK, Assembler::AVX_512bit); - - // Begin 32 blocks of AES processing - __ bind(AES_32_BLOCKS); - // Save incremented counter before overwriting it with AES data - __ evmovdquq(CTR_BLOCKx, ZTMP8, Assembler::AVX_512bit); - - // Move 256 bytes of data - loadData(in, pos, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - // Load key shuffle mask - __ movdqu(xmm29, ExternalAddress(key_shuffle_mask_addr()), rbx /*rscratch*/); - // Load 0th AES round key - ev_load_key(ZTMP4, key, 0, xmm29); - // AES-ROUND0, xmm24 has the shuffle mask - shuffleExorRnd1Key(ZTMP5, ZTMP6, ZTMP7, ZTMP8, xmm24, ZTMP4); - - for (int j = 1; j < 10; j++) { - ev_load_key(ZTMP4, key, j * 16, xmm29); - roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); - } - ev_load_key(ZTMP4, key, 10 * 16, xmm29); - // AES rounds up to 11 (AES192) or 13 (AES256) - __ cmpl(rounds, 52); - __ jcc(Assembler::greaterEqual, AES_192); - lastroundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); - __ jmp(STORE_CT); - - __ bind(AES_192); - roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); - ev_load_key(ZTMP4, key, 11 * 16, xmm29); - roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); - __ cmpl(rounds, 60); - __ jcc(Assembler::aboveEqual, AES_256); - ev_load_key(ZTMP4, key, 12 * 16, xmm29); - lastroundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); - __ jmp(STORE_CT); - - __ bind(AES_256); - ev_load_key(ZTMP4, key, 12 * 16, xmm29); - roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); - ev_load_key(ZTMP4, key, 13 * 16, xmm29); - roundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); - ev_load_key(ZTMP4, key, 14 * 16, xmm29); - // Last AES round - lastroundEncode(ZTMP4, ZTMP5, ZTMP6, ZTMP7, ZTMP8); - - __ bind(STORE_CT); - // Xor the encrypted key with PT to obtain CT - xorBeforeStore(ZTMP5, ZTMP6, ZTMP7, ZTMP8, ZTMP0, ZTMP1, ZTMP2, ZTMP3); - storeData(out, pos, ZTMP5, ZTMP6, ZTMP7, ZTMP8); - // 16 blocks encryption completed - __ addl(pos, 256); - __ cmpl(pos, 512); - __ jcc(Assembler::aboveEqual, GHASH_AES_PARALLEL); - __ vpaddd(ZTMP5, CTR_BLOCKx, COUNTER_INC_MASK, Assembler::AVX_512bit); - __ vpaddd(ZTMP6, ZTMP5, COUNTER_INC_MASK, Assembler::AVX_512bit); - __ vpaddd(ZTMP7, ZTMP6, COUNTER_INC_MASK, Assembler::AVX_512bit); - __ vpaddd(ZTMP8, ZTMP7, COUNTER_INC_MASK, Assembler::AVX_512bit); - __ jmp(AES_32_BLOCKS); - - __ bind(GHASH_AES_PARALLEL); - // Ghash16_encrypt16_parallel takes place in the order with three reduction values: - // 1) First time -> cipher xor input ghash - // 2) No reduction -> accumulate multiplication values - // 3) Final reduction post 48 blocks -> new ghash value is computed for the next round - // Reduction value = first time - ghash16_encrypt16_parallel(key, avx512_subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, true, xmm24, true, rounds, ghash_pos, false, index, COUNTER_INC_MASK); - __ addl(pos, 256); - __ addl(ghash_pos, 256); - index += 4; - - // At this point we have processed 768 bytes of AES and 256 bytes of GHASH. - // If the remaining length is less than 768, process remaining 512 bytes of ghash in GHASH_LAST_32 code - __ subl(len, 768); - __ cmpl(len, 768); - __ jcc(Assembler::less, GHASH_LAST_32); - - // AES 16 blocks and GHASH 16 blocks in parallel - // For multiples of 48 blocks we will do ghash16_encrypt16 interleaved multiple times - // Reduction value = no reduction means that the carryless multiplication values are accumulated for further calculations - // Each call uses 4 subkeyHtbl values, so increment the index by 4. - __ bind(GHASH_16_AES_16); - // Reduction value = no reduction - ghash16_encrypt16_parallel(key, avx512_subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, false, xmm24, false, rounds, ghash_pos, false, index, COUNTER_INC_MASK); - __ addl(pos, 256); - __ addl(ghash_pos, 256); - index += 4; - // Reduction value = final reduction means that the accumulated values have to be reduced as we have completed 48 blocks of ghash - ghash16_encrypt16_parallel(key, avx512_subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, false, xmm24, false, rounds, ghash_pos, true, index, COUNTER_INC_MASK); - __ addl(pos, 256); - __ addl(ghash_pos, 256); - // Calculated ghash value needs to be __ moved to AAD_HASHX so that we can restart the ghash16-aes16 pipeline - __ movdqu(AAD_HASHx, ZTMP5); - index = 0; // Reset subkeyHtbl index - - // Restart the pipeline - // Reduction value = first time - ghash16_encrypt16_parallel(key, avx512_subkeyHtbl, CTR_BLOCKx, AAD_HASHx, in, out, ct, pos, true, xmm24, true, rounds, ghash_pos, false, index, COUNTER_INC_MASK); - __ addl(pos, 256); - __ addl(ghash_pos, 256); - index += 4; - - __ subl(len, 768); - __ cmpl(len, 768); - __ jcc(Assembler::greaterEqual, GHASH_16_AES_16); - - // GHASH last 32 blocks processed here - // GHASH products accumulated in ZMM27, ZMM25 and ZMM26 during GHASH16-AES16 operation is used - __ bind(GHASH_LAST_32); - // Use rbx as a pointer to the htbl; For last 32 blocks of GHASH, use key# 4-11 entry in subkeyHtbl - __ movl(rbx, 256); - // Load cipher blocks - __ evmovdquq(ZTMP13, Address(ct, ghash_pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); - __ evmovdquq(ZTMP14, Address(ct, ghash_pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); - __ vpshufb(ZTMP13, ZTMP13, xmm24, Assembler::AVX_512bit); - __ vpshufb(ZTMP14, ZTMP14, xmm24, Assembler::AVX_512bit); - // Load ghash keys - __ evmovdquq(ZTMP15, Address(avx512_subkeyHtbl, rbx, Address::times_1, 0 * 64), Assembler::AVX_512bit); - __ evmovdquq(ZTMP16, Address(avx512_subkeyHtbl, rbx, Address::times_1, 1 * 64), Assembler::AVX_512bit); - - // Ghash blocks 0 - 3 - carrylessMultiply(ZTMP2, ZTMP3, ZTMP4, ZTMP1, ZTMP13, ZTMP15); - // Ghash blocks 4 - 7 - carrylessMultiply(ZTMP6, ZTMP7, ZTMP8, ZTMP5, ZTMP14, ZTMP16); - - __ vpternlogq(ZTMP1, 0x96, ZTMP5, xmm27, Assembler::AVX_512bit); // ZTMP1 = ZTMP1 + ZTMP5 + zmm27 - __ vpternlogq(ZTMP2, 0x96, ZTMP6, xmm26, Assembler::AVX_512bit); // ZTMP2 = ZTMP2 + ZTMP6 + zmm26 - __ vpternlogq(ZTMP3, 0x96, ZTMP7, xmm25, Assembler::AVX_512bit); // ZTMP3 = ZTMP3 + ZTMP7 + zmm25 - __ evpxorq(ZTMP4, ZTMP4, ZTMP8, Assembler::AVX_512bit); // ZTMP4 = ZTMP4 + ZTMP8 - - __ addl(ghash_pos, 128); - __ addl(rbx, 128); - - // Ghash remaining blocks - __ bind(LOOP); - __ cmpl(ghash_pos, pos); - __ jcc(Assembler::aboveEqual, ACCUMULATE); - // Load next cipher blocks and corresponding ghash keys - __ evmovdquq(ZTMP13, Address(ct, ghash_pos, Address::times_1, 0 * 64), Assembler::AVX_512bit); - __ evmovdquq(ZTMP14, Address(ct, ghash_pos, Address::times_1, 1 * 64), Assembler::AVX_512bit); - __ vpshufb(ZTMP13, ZTMP13, xmm24, Assembler::AVX_512bit); - __ vpshufb(ZTMP14, ZTMP14, xmm24, Assembler::AVX_512bit); - __ evmovdquq(ZTMP15, Address(avx512_subkeyHtbl, rbx, Address::times_1, 0 * 64), Assembler::AVX_512bit); - __ evmovdquq(ZTMP16, Address(avx512_subkeyHtbl, rbx, Address::times_1, 1 * 64), Assembler::AVX_512bit); - - // ghash blocks 0 - 3 - carrylessMultiply(ZTMP6, ZTMP7, ZTMP8, ZTMP5, ZTMP13, ZTMP15); - - // ghash blocks 4 - 7 - carrylessMultiply(ZTMP10, ZTMP11, ZTMP12, ZTMP9, ZTMP14, ZTMP16); - - // update sums - // ZTMP1 = ZTMP1 + ZTMP5 + ZTMP9 - // ZTMP2 = ZTMP2 + ZTMP6 + ZTMP10 - // ZTMP3 = ZTMP3 + ZTMP7 xor ZTMP11 - // ZTMP4 = ZTMP4 + ZTMP8 xor ZTMP12 - xorGHASH(ZTMP1, ZTMP2, ZTMP3, ZTMP4, ZTMP5, ZTMP9, ZTMP6, ZTMP10, ZTMP7, ZTMP11, ZTMP8, ZTMP12); - __ addl(ghash_pos, 128); - __ addl(rbx, 128); - __ jmp(LOOP); - // Integrate ZTMP3/ZTMP4 into ZTMP1 and ZTMP2 - __ bind(ACCUMULATE); - __ evpxorq(ZTMP3, ZTMP3, ZTMP4, Assembler::AVX_512bit); - __ vpsrldq(ZTMP7, ZTMP3, 8, Assembler::AVX_512bit); - __ vpslldq(ZTMP8, ZTMP3, 8, Assembler::AVX_512bit); - __ evpxorq(ZTMP1, ZTMP1, ZTMP7, Assembler::AVX_512bit); - __ evpxorq(ZTMP2, ZTMP2, ZTMP8, Assembler::AVX_512bit); - - // Add ZTMP1 and ZTMP2 128 - bit words horizontally - vhpxori4x128(ZTMP1, ZTMP11); - vhpxori4x128(ZTMP2, ZTMP12); - // Load reduction polynomial and compute final reduction - __ evmovdquq(ZTMP15, ExternalAddress(ghash_polynomial_reduction_addr()), Assembler::AVX_512bit, rbx /*rscratch*/); - vclmul_reduce(AAD_HASHx, ZTMP15, ZTMP1, ZTMP2, ZTMP3, ZTMP4); - - // Pre-increment counter for next operation - __ vpaddd(CTR_BLOCKx, CTR_BLOCKx, xmm18, Assembler::AVX_128bit); - // Shuffle counter and save the updated value - __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, xmm24, Assembler::AVX_512bit); + __ movdl(CTR_CHECK, CTR_BLOCKx); + __ andl(CTR_CHECK, 255); + + // Reshuffle counter + __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_512bit); + + initial_blocks_16_avx512(in, out, ct, pos, key, avx512_subkeyHtbl, CTR_CHECK, rounds, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, stack_offset); + __ addl(pos, 16 * 16); + __ cmpl(len, 32 * 16); + __ jcc(Assembler::below, MESG_BELOW_32_BLKS); + + initial_blocks_16_avx512(in, out, ct, pos, key, avx512_subkeyHtbl, CTR_CHECK, rounds, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, stack_offset + 16); + __ addl(pos, 16 * 16); + __ subl(len, 32 * 16); + + __ cmpl(len, 32 * 16); + __ jcc(Assembler::below, NO_BIG_BLKS); + + __ bind(ENCRYPT_BIG_BLKS_NO_HXOR); + __ cmpl(len, 2 * 32 * 16); + __ jcc(Assembler::below, ENCRYPT_BIG_NBLKS); + ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, + true, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32); + __ addl(pos, 16 * 16); + + ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, + true, false, true, false, true, ghashin_offset + 16, aesout_offset + 16, HashKey_16); + __ evmovdquq(AAD_HASHx, ZTMP4, Assembler::AVX_512bit); + __ addl(pos, 16 * 16); + __ subl(len, 32 * 16); + __ jmp(ENCRYPT_BIG_BLKS_NO_HXOR); + + __ bind(ENCRYPT_BIG_NBLKS); + ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, + false, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32); + __ addl(pos, 16 * 16); + ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, + false, false, true, true, true, ghashin_offset + 16, aesout_offset + 16, HashKey_16); + + __ movdqu(AAD_HASHx, ZTMP4); + __ addl(pos, 16 * 16); + __ subl(len, 32 * 16); + + __ bind(NO_BIG_BLKS); + __ cmpl(len, 16 * 16); + __ jcc(Assembler::aboveEqual, ENCRYPT_16_BLKS); + + __ bind(ENCRYPT_N_GHASH_32_N_BLKS); + ghash16_avx512(true, false, false, false, true, in, pos, avx512_subkeyHtbl, AAD_HASHx, SHUF_MASK, stack_offset, 0, 0, HashKey_32); + gcm_enc_dec_last_avx512(len, in, pos, AAD_HASHx, SHUF_MASK, avx512_subkeyHtbl, ghashin_offset + 16, HashKey_16, false, true); + __ jmp(GHASH_DONE); + + __ bind(ENCRYPT_16_BLKS); + ghash16_encrypt_parallel16_avx512(in, out, ct, pos, avx512_subkeyHtbl, CTR_CHECK, rounds, key, CTR_BLOCKx, AAD_HASHx, ADDBE_4x4, ADDBE_1234, ADD_1234, SHUF_MASK, + false, true, false, false, false, ghashin_offset, aesout_offset, HashKey_32); + + ghash16_avx512(false, true, false, false, true, in, pos, avx512_subkeyHtbl, AAD_HASHx, SHUF_MASK, stack_offset, 16 * 16, 0, HashKey_16); + + __ bind(MESG_BELOW_32_BLKS); + __ subl(len, 16 * 16); + __ addl(pos, 16 * 16); + gcm_enc_dec_last_avx512(len, in, pos, AAD_HASHx, SHUF_MASK, avx512_subkeyHtbl, ghashin_offset, HashKey_16, true, true); + + __ bind(GHASH_DONE); + //Pre-increment counter for next operation, make sure that counter value is incremented on the LSB + __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_128bit); + __ vpaddd(CTR_BLOCKx, CTR_BLOCKx, ADD_1234, Assembler::AVX_128bit); + __ vpshufb(CTR_BLOCKx, CTR_BLOCKx, SHUF_MASK, Assembler::AVX_128bit); __ movdqu(Address(counter, 0), CTR_BLOCKx); - // Load ghash lswap mask + //Load ghash lswap mask __ movdqu(xmm24, ExternalAddress(ghash_long_swap_mask_addr()), rbx /*rscratch*/); - // Shuffle ghash using lbswap_mask and store it + //Shuffle ghash using lbswap_mask and store it __ vpshufb(AAD_HASHx, AAD_HASHx, xmm24, Assembler::AVX_128bit); __ movdqu(Address(state, 0), AAD_HASHx); - __ jmp(ENC_DEC_DONE); - __ bind(GENERATE_HTBL_48_BLKS); - generateHtbl_48_block_zmm(subkeyHtbl, avx512_subkeyHtbl, rbx /*rscratch*/); + //Zero out sensitive data + __ evpxorq(ZTMP21, ZTMP21, ZTMP21, Assembler::AVX_512bit); + __ evpxorq(ZTMP0, ZTMP0, ZTMP0, Assembler::AVX_512bit); + __ evpxorq(ZTMP1, ZTMP1, ZTMP1, Assembler::AVX_512bit); + __ evpxorq(ZTMP2, ZTMP2, ZTMP2, Assembler::AVX_512bit); + __ evpxorq(ZTMP3, ZTMP3, ZTMP3, Assembler::AVX_512bit); __ bind(ENC_DEC_DONE); - __ movq(rax, pos); } //Implements data * hashkey mod (128, 127, 126, 121, 0) diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp index 2056fa057654e..5a9b084841376 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_ghash.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2019, 2021, Intel Corporation. All rights reserved. +* Copyright (c) 2019, 2024, Intel Corporation. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -57,7 +57,10 @@ address StubGenerator::ghash_byte_swap_mask_addr() { // Polynomial x^128+x^127+x^126+x^121+1 ATTRIBUTE_ALIGNED(16) static const uint64_t GHASH_POLYNOMIAL[] = { - 0x0000000000000001UL, 0xC200000000000000UL, + 0x0000000000000001ULL, 0xC200000000000000ULL, + 0x0000000000000001ULL, 0xC200000000000000ULL, + 0x0000000000000001ULL, 0xC200000000000000ULL, + 0x0000000000000001ULL, 0xC200000000000000ULL }; address StubGenerator::ghash_polynomial_addr() { return (address)GHASH_POLYNOMIAL; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index 44cfb76d1628e..478593dfac1ac 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -72,7 +72,7 @@ abstract class GaloisCounterMode extends CipherSpi { // data size when buffer is divided up to aid in intrinsics private static final int TRIGGERLEN = 65536; // 64k // x86-64 parallel intrinsic data size - private static final int PARALLEL_LEN = 7680; + private static final int PARALLEL_LEN = 512; // max data size for x86-64 intrinsic private static final int SPLIT_LEN = 1048576; // 1MB diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMBench.java b/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMBench.java index e46f50678ef81..8355e4aed728e 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMBench.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/AESGCMBench.java @@ -35,7 +35,7 @@ public class AESGCMBench extends BenchBase { - @Param({"128"}) + @Param({"128", "192", "256"}) int keyLength; public static final int IV_MODULO = 16; diff --git a/test/micro/org/openjdk/bench/javax/crypto/full/BenchBase.java b/test/micro/org/openjdk/bench/javax/crypto/full/BenchBase.java index 0c5df20d9cb64..94c8ef30ea553 100644 --- a/test/micro/org/openjdk/bench/javax/crypto/full/BenchBase.java +++ b/test/micro/org/openjdk/bench/javax/crypto/full/BenchBase.java @@ -45,7 +45,7 @@ public abstract class BenchBase extends CryptoBase { int keyLength = 256; // Default data sizes for full tests - @Param({"1024", "1500", "4096", "16384"}) + @Param({"128", "256", "512", "1024", "1500", "4096", "16384"}) int dataSize; static final int IV_BUFFER_SIZE = 36; From bfdeb33e6f1d4f9f0cc65925ea792be98b1f4d61 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Mon, 30 Sep 2024 18:45:40 +0000 Subject: [PATCH 067/188] 8340332: Open source mixed AWT tests - Set3 Reviewed-by: aivanov --- .../ContainerResizeMousePositionTest.java | 141 +++++++++++ .../awt/color/XAWTDifference/XAWTColors.jpg | Bin 0 -> 10774 bytes .../color/XAWTDifference/XAWTDifference.java | 223 ++++++++++++++++++ 3 files changed, 364 insertions(+) create mode 100644 test/jdk/java/awt/MouseInfo/ContainerResizeMousePositionTest.java create mode 100644 test/jdk/java/awt/color/XAWTDifference/XAWTColors.jpg create mode 100644 test/jdk/java/awt/color/XAWTDifference/XAWTDifference.java diff --git a/test/jdk/java/awt/MouseInfo/ContainerResizeMousePositionTest.java b/test/jdk/java/awt/MouseInfo/ContainerResizeMousePositionTest.java new file mode 100644 index 0000000000000..72aa4d93a5c71 --- /dev/null +++ b/test/jdk/java/awt/MouseInfo/ContainerResizeMousePositionTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/* + * @test + * @key headful + * @bug 4009555 + * @summary Unit test for a new method in Container class: getMousePosition(boolean) + * while Container resized. + */ + +public class ContainerResizeMousePositionTest { + private static Frame frame; + private static Button button; + private static Robot robot; + private static volatile Point frameLocation; + private static volatile Point newLoc; + private static boolean testSucceeded = false; + + private static final CountDownLatch eventCaught = new CountDownLatch(1); + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + EventQueue.invokeAndWait(() -> createAndShowUI()); + robot.waitForIdle(); + robot.delay(1000); + testUI(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + frame = new Frame("Testing getMousePosition() after resize"); + button = new Button("Button"); + frame.setLayout(new BorderLayout()); + frame.add(button); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void testUI() throws Exception { + EventQueue.invokeAndWait(() -> { + frameLocation = frame.getLocationOnScreen(); + newLoc = new Point(frame.getWidth() + 10, frame.getHeight() + 10); + }); + + robot.mouseMove(frameLocation.x + newLoc.x, frameLocation.y + newLoc.y); + EventQueue.invokeAndWait(() -> { + button.addComponentListener(new ResizeAdapter()); + frame.setSize(frame.getWidth() * 2, frame.getHeight() * 2); + frame.validate(); + }); + robot.waitForIdle(); + robot.delay(500); + + if (!eventCaught.await(2, TimeUnit.SECONDS)) { + throw new RuntimeException("componentResized Event isn't" + + " received within a timeout"); + } + + if (!testSucceeded) { + throw new RuntimeException("Container.getMousePosition(boolean)" + + " returned incorrect result while Container resized"); + } + } + + static class ResizeAdapter extends ComponentAdapter { + int testStageCounter = 0; + @Override + public void componentResized(ComponentEvent e) { + Point pTrue = frame.getMousePosition(true); + if (frame.getMousePosition(false) == null) { + testStageCounter++; + System.out.println(""" + TEST STAGE 1 PASSED: + Container.getMousePosition(false) + returned NULL over Child Component + during resize. + """); + } + if (pTrue != null) { + testStageCounter++; + System.out.println(""" + TEST STAGE 2 PASSED: + Container.getMousePosition(true) + returned NON-NULL over Child Component + during resize. + """); + } + if (pTrue != null && pTrue.x == newLoc.x && pTrue.y == newLoc.y) { + testStageCounter++; + System.out.println(""" + TEST STAGE 3 PASSED: + Container.getMousePosition(true) + returned correct result over Child Component + during resize. + """); + } + testSucceeded = testStageCounter == 3; + eventCaught.countDown(); + } + } +} diff --git a/test/jdk/java/awt/color/XAWTDifference/XAWTColors.jpg b/test/jdk/java/awt/color/XAWTDifference/XAWTColors.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f53b30407cc28676f9a91a9690c20b499f9ffbca GIT binary patch literal 10774 zcmch7XIN89*C+x~R1mvBC>E67dkYpoiU>#*q)3w%454>W5kbJCRH-5n=}ibl5_*Kt zkpPka8WV&-C?WK~-FV)6@B4k<{qz1fH_tQKd(Eu9X7--d*Ss_~(&aeDbBuw3fkW@k zZBqt@Bkvg)7~iom0zDV=psv7$33gM@jE#+L>c_oV0Oa=5w(`60nNXSx41x@Lw{MsQWiR3Hdh)s>t5&C;qHb6WmcUQ&TpN+im~?S` znt5gPV!Mbpn(KEWMXMD;n&KaFSnLaw2bwun5^Iym) z#TJa$x;UgUta;k(O^KO#?SzLvg~=K^wXZvZqR+#22{v=nq+Omy&nQCe$6}`oe$M!qT(v zK{uS|2F@sUEHwAP(oZ-`rV^kAC*v$YdW}xit<;mH;=wtLf$QInq1zAp$Y+A~9aDvv zJgfFr8>CA?yZ3y|QmL!&UL0J+ilX;NdCg_)ZtcTE!?UkH$-U(@Ol8%~wK3exx9Jla zOkH4*Ui|s0vGUlS>_DAwbn;w;?%yL_3|yXPJVA58dAi9j)!jrj(94$xUWXX5W#|s! z2vL|EZZ?~>(~-}{w6ppBukUP{Yn;(I{!;nYg36^?>-^?3O}G8p(?Bwj69Px>3}Ssy z^lmzVA+8hnW78!t+|l`Ot-d^EA)wj1l7*r05xFQYqBn$(i&$ET>hHB;@z+f-Dxv7BRw@DF*!P|1wq%vlR22h z-E0mjm2yPkDZV^5NeWBW?BbIP!Rb!4k9y)kSE{3Z+?>yaoh#lvidbx;f5dBkt$0QS-rKU8xQXzROX!`P{1dhzMni=Lu)~e{J;QA|hEqo_fjJ(O~5%Dhl z`)&$6b?<6IMypWM`yCq83!Z((wYZ~}o(ktaBbXJrr0=aOS6GxksO5XZO|Q5(Q4hT8 zXs(Ai?6Ra+HR%KbL1}hlfRwtidJqPAX{{#%Xj?z_few@2(KH z-}r}TTrFpwXy3XBd?xQhe)0ts;UR7<*VtC5gWyQom}R*|0!PX{!m5?Xm`9zFkx`A^ zg`iY@_-asg>7efst@eLcME}%%eX41i3w@6|XkE#EGbcOy6`D{s&L~{C6uCzbu&(T2 z0X9~@*tItEkl#=9-a#=p)|ID-remxtyLBETrYKLuNrPYT5CIUVDjMt5$kEBAHdjwO z(D`6ePrj6Uph4Z+hEXwiJf2MUg!OiHJ>SjXNU1-k#O3Qb72fG^NnWgDQ^>E)F#f3+d{^(|Yq zH!XPl!%dlHuu3P3s60=)1~s47)1wz47USTRfAa&BTMo^}bLF|MBhxv)L`=p(FO$x( z#&#A_)ks2icba{NwL_-S6^H%khg086CZC#HSbz>L-bet60B_?~%<(L2RcT=1Ze1>I zcGZJLLzli8DOQ9I{mK=v{rK0NXpYaC2Ht|dFpqXiHgCmEg14BOT~DwB67eso2|9S? zlqX7F|7KcL?<8L4IHdr)_|pd2j3cs$H=bA28A{^?COVzc&CdvBe?hjh)BG$A>TUODUT=FbRpz zb3F6v^uaATNI&tgDcZd68ksDC@sRgWaG`yS_7Nm1C%Mp4)L<(%f_~e89`Pt*I#`bh zUHhe1fN}cYkAwLwOD*tMa3m-t+FQ-SM|G)KXXX7xH1rignL}5_Xei7P6Ud{0ZlW2U z{b|sEI-oBfmwd&M^5wP?SIsFDbS&226R8KHKX=M2QL2ZhxS$&A=;{2pmX5x_*fY}h z6Kev;vf1EgdD+-Lw+4^>EwNO$Ly6_>tS{XOM*E6~=8Nz4FX7#rZwwAESB0k0udSSZ zo=+5mm)TVYgam#cs6hTDZ+PcCFWX9jGXLhRRgFcRPf>kf`_oEDs;NGAt#z$lFWBZ4 zai%+w9eOaipImk4X?I!kG(qO`<%nfPhK*VbSGNoCTDf@ zvBYkdLC_)AB}L=+8V#BhKsK$*(XnEw`h?YnF%NCj^9e2MmyLkzZ69ux=i9-;?70TEdK>GL%d<1_@E`IUo)Psf>wUWu?>-TcY+~M)0(V}~ldm>)B=kE1X zM_W|K0@KGg>5?cEN|3suRQTQ+5z}N*CXEvq2vU#O+kzIG#Uq!kVkWep&VXKFZJPrH z1O^I#Bl;S`*>@7dzxMyF;Tru>l{F#eAZr*>yRQ`yA zm#wi&L-u$S;175=kIp~&VGb}^l)0A}oL?g(1#ob_Im)CmEV(^WPjlP!;CT?#U1jb6kP3QOa!hC!x%|sK?P8!4E49NqF z%TG|&NY#t}3+&=G)2ot2)7(PUvm9r>EA#Qt?GZOz!`rVl**D4EmS(y>{XsYRXP;uG zA!*=)CtTNDzj!sMi~uhJW{TWeX)DW6!-s(~RFq;uTc6+}NDqpiwKs1|hG9y5}Ec9+3?# zVjUvYlDPW7T5`b~&o#JHy(v>4rk42m_`2-#RjNi-d6LmhQIsuA4kg%&bI8_JV{mY= z|5dkr=}-MICXT_4tP(k%F&cqR641%nfzFLZP`#`U*J533zx)MUA+E@9!gjHP``xl= z&hT#2h=LjI>6Vzpp_wBYxy)u5b$v>;9!%sx!|x`4Va$9UZ!NZQ@2&Kgg;L8vS}{mq z9Ag=7UTK+>EJh?v-q2Opr48)PnpmKM56)9hP;Q>*mAysZGKYf=*9Xn7CMYCbaS0|R zHKvg!P0W8Ze~xog266805(5FtLMYz3(K3mfv7`+Mdx2#i6)E^tcb`aQ3T#USo1INe zaHGkj9~4U5YAnpqSOX;|=;b*MHGkr5`0y@9A8xw*WwXd5C;(d-sKYlVuC$wwSHNad zrqZ!;5L;3qr?iLam%tT_qcaH&#BRS2!*?$9)1{(q-f1H81<1$Ma0U~8e_P9vh&^DA`X|vh&+j_0&?sJt<&hhZx4cSj zAh%qu72AnwzpTqFkX)18FMIyY_;cyAEMLnq23~7U&1ODk5nHTw+upH#7ReH+L`+<^ zn9<@-C2TGaZeWNX_iLuP{nrI4R?8nOlGJE)(q!8%fne#j3mYiak;1CoDpCmro7=UN z_^coou#e?K)_)Hd6m?Yd?}+pB3M1B8Jn9}?zkc1i^7xl^6gDjF_&*bV{P(bCY9|s8 zQ5qd<1p$7w%9MU_kF&3zUkdG=AYhHHcy>z|u4XNjYKE)}Ptl@goMoW`wb8y`ae$8W z-aN%CZrOyda63rhNDJg6Qg&8;Jl!TvPv@%P!@Z1F`vlr-Q{3X! zhUL1be9>$w9=46PiYQQ`4#jV?TBS=ak{M=_D?+(Fcy=)Gndw4T!UYO}N`)!O|B3Um zU}^gBmX;RN;=(z3``<`hwlaURe~HaSpS$VaLwd4BUJ# zlgE)gn)92*=-zOLmJ&?L?#qhh$vF4>N$B7L5;u#ayy$HnM%JgN>=|W&{h^(0o+pPB>&cR7|bPNHc!Js+yfwZ zNrR;6wP&DX7-IR&_RefjzZ@@@F0vcys9tnC-73cI)p$g#Z!lL>uc?fbgupAcmXg%>%6`QRYaqUs7cJEXr8Ng){5Qj zPQ?(1AOFhxU@IvG?<-nAo4%Xk)&%5V-c-LfEtcm`CaBYXb{*eb-QI4@l7=;Xv_Dtv zoc}uwgbsc)7oms2>YZ!@%pbRGzgJqO^n=*Da&tl1l<~*%Ystf}Ss^Gu^L3Xp{yL2& zFsmN&N)|y4)-)%gRU*Xe#!3DOD!KKu4|X&(G}IA|{|RggbAm_qoR-Z5R4EDV(giD# zUu@t-6RLVhfG>U`-7RuL^)RD@>=+)oS)L$5A zklvsv8B!hB5lQ-nA`}N2Xuz6kpG#cwis=0Iujux8&^)4pt}JO3vaaq3lT_t9{_-uq z#=VK`1S3}FSt_6x{!_R4KgFLK2sz5Y4tyVMX_SM_hhbr|KSR`KFNH&Q^T_+}OB_zt2m6m>1}CFF*CBm8G}Qw=tV0>h&z3S%W{BM#unD1Dg9+ zl?9K0sCrpo55SjGLgDcE79>)!$kx_YctC|g&rv=-w~^Hwa4OM+Rlp&;9v0tygk4od z1@N+%0X+?y8{Vw~lyx3Baznj~24#r%4h$R*FWbC#SDsU=y7BsDvmxVm-A9C_VO&MQ zvA)v;sEv&cg)r~8V3ciCM7d8{uiE}AHf6Xyf+H_Zmk#NUWXGtk8FJ zpKwp1*_>EE)v-F+UASCP=Ky&3nQkVMEnktzG6MJ`FssRSQx4rwZBlU^`ZQu_1n}E7q z|4K>aJ{e_p5dW2X@2PUXx+r2{wLzjIKH((g^rI($s|3yKink zww$|w;vG1Du|5pG)4yg-q(3$@2^`%mJt+peJOGCsnFF0yZ6FOS2fs@BO@N4Qv?&Be z3_6wJfw!{5cfozbY^CgJ<}G$AniVNoZmfJ`i{om`VmG9g>}h25hj`Q8@XUyU>BdU) zuWRNla!pbXx@w~?10m8zWJ%lE6>G_G%}XnL?t=F?*loYBZ$E3L7CBPIKEyIh-tYMF zWMW1N)tqMv&Y)LLdr_84L)^|v-_(|ZRw z5$A$9^oG__O=(6&YZS_t1#4nz)D`IQAIK|O`uw29aZxm|qG|S%$dJku)8347&8)(` z+Agboe0)YAf;uS3Lr`XTGyHGuC@zq>vCGXUT3aTGNpLcpur4@27f+ufLHE%(sB`~+ z0hx_m3G2EwI9@v)0wsf71b#!DUXkSqL^FRL3OC=3K#>v$`qdJi1on9~Ztg1h_(7(v zpEWx%#uK0n&WDNy(2~>I{>h`kkm&jCeg!LVOTq$w5f#TcO3m_&>i^|!+ea;=6tisp zy2T^LiprSN!{6ti^t|{se&Vapa(I-+y{!8U3a+HRV%ef6o`$W-0O9|q#!K)3UDzZ6 zjS&V-?z?=+qqShd@~Ge>eGb%TG{av8V z+6-87r7nI@TkDg`=GSj3qw0Z78#uwyNR%PvLuOfPsPjU$dv5cQP{`|fl>N2M;m&Ir zwUs=ITgP@6J^JSF=ugawE!LLG6fr&W8q5=lt&-t!LS(b?evk=x8q^~%NqTb9`lSkv z>6aeq%L2~+C;Z~5iw8w&)%4Z8U`ike(WxP&QFK-vJ-atr9WO))o>zg-s<6!Eao#!Y zpWOG{NU*B8iDfvj?UiP9D@9cC%s2zn>sQ@J{^RDg`|FppI=@>B4;zqlv1n8NhjQ!x z!?`70Naojw&+wPcEc_yy@e~N7J*KGs6T5|f;x9N-HRA=)_bePpWBfa-{`-A!WilBk zG?cOYe8hC*c<@j|k8`_!VQ@DKdef?(V{;QW`3lMG%f<|yXWCJTU@Mk^~S+C#jN%y*32c#7^TWEx)fJ?|=; zY25UA-Yk4?OXjkhqh`e3o%z=d?eYWVQ=-R*rHcIApOEW&Z?0oR_)eQebqkp)oq-!z zT=thUQN1cWo@np|a!nu6)Jb+N@Vj%{h&SB>Z|t5AO-T_aD}{L)!p7+ zc*9^xeD@)`qA_FQ2MB+#7@t2i-;dV?-feMoleo2|6~&*oFfebAk#Ny0HiORbMZYu z#j{Euz~nJjJ;Df#VZDY&Ob`km{GM;*L%&Jfg6iwyWpB?P^S~-Eq@8hue}Jgmm_O!b zBT`pedkgQ|C7xrtu(I;Hi5PFK`U|(5VydL1gohxemRwt88-VKS3^Ke_z~0Wz?&0Cj zrCDDZxU@t76|1_|u-fo3x4~QyxF0DgDXGRrpszk=`f^3ly*yE%i<6VH#!9O1cX>X7 zZEd+tg;hVjytOG)_+kAgn^Q+^)o#vXeIURlK*NL4Q^vpatITRm5S58 zjH|#CeEw#oPg!1K^Z_3I3leV+=a*loXFt7#f0{BNMFrp-0skq`OFE~!ei5+*V9g>E z#ND@6gwJ;+A415k-+uw0vp?kt0E<1mwBY*vGXURB(Y|3YKDvYYU$$h;nT`Oka2TEyls2H!(v`T^5g7l`F?8)uBVMv7g$g< z1tYP?^UmY_WSmhe8?6eL5 z@jj=4E}qMNBXQK%6yTt1*MV)dGPC0;aiB3m|QgKGW?klA6>cBm@TtUKLtS96c@0=WlQ;2Ee&vA;VLY35NwEUuoe-T+;@K z+p>)Qw|D?eqo$??)Q=d~zaztUEx^wap{E%b*mDlg0&D@rc_*awes(Y{C@6y_Dy~(z zL>{lCJzYi}Xp)W-2H86i^t^+;IkZ4zAE2yE8pig2ybu6#tp$}k1c8IC!N`5N=VN-7 zr!0402t+7@!Gj?ZudBS_-;`#;fcmXh+Scwk5AWmtpUd`F4qVZMcm1yQFN6~XTmohE_lYC!{xz*(=mr>@2SbjOv7ua zy)}bQkyDDsv79GQf`L>rxf128U-*PS+ma8+Z&__w)O< z6!4)E;>c8<$KNRe2UxtKqT*ujIfGUjbSWT|PLAH1(9#M+VM2~7=BUMu0%8%dO-w&A z&dN^_G*VMmK6LHnYz4%D5CSlqEm#2i z4%zbVvd*wM5|rsuS)&u*zsv5wY_9XPky8kD7zo~6F&YAQuFje1b5Ky`t>SH^fv9hj z-#HfFt**CLjPXQr206}d0%c~7(2Y*70-tTDh51p=GXVhs)5!2Cj-r%!P;Yhg2wn^L zx|Q}QgY*6+SVMeSQX5=v=32NnEroHa+kQv-SE+RV)pV$af zO_VTDspST`6u;CmmrehvoNb)O6f1z>CG}Ji78$B$okU#UAKz_{TPE%Yhgz(x5z0KO zva+(=WS&VyaTJ>3wScX?=M+~f?CkkI+`M!SnI(?#P)6vR3-n1}#NDk4Y5A(HJ-F>K z^WI|$n??{8^9_771pCH|UPBgoOw~zXAj-YI;&b&2k&d04vin~gG4`(JsruyHaIgGM zMdND9;VG41jt6E}$Lp z$)A`J^V?3STriwqXSGC3-CalKdgW)7s-6jGZ}a!}?+VwTN==dpWp=oSF~3!Ebo#3) z8>t^p`E-ZYdC(x4C+!rfywMAHi!{#F=*XZfC)U!f#!gg6`y!)Xe_`gG>r@}9{+hiy zSD{$O>eD?5oYpXFsg{8MDR_U|JZ8NwTlx;D5e+DDnVuR}#zerT*fh?ala3tpr3`rF zU_(wFI1J>BF3>!R0_WNn7qarTgDopPW~ME?H}^7~XyO_=RZAri)72mhe~|sfxzOhl zk4Tkz5G`semw!dMW-%&I7e%9QLxt&Zf$5CU2h^WRBVaVkTmjkPHT7 zQ0G9CH9UWbMjnUF9qjKeqjo83fuq^k*@dVi-XfrEKDCrCWnVw#P3Ii(d4ZxY`Pd`F zUIwL_mf#^5<^xaa7gX}~gh+7d+pE2yJrFz+c1_?vPbcC6ukz0CX|i68otYD4NyHeg zFT;KZGz0F^mFL{?`{A6HmX`POG=-jTqmdqp5D4T?CFOzOHzJXkx4&Kl6x7-Cp}~c$ zQ0vO0H|KBIVm+g+9^1MCG7Gw;!u{BmA{~cOVS#qtB-C^oOU_;F1xkQx&u`cc$i#_( zc+zEJeO1uL6~7d3IKC zr=vvpwKv=hG1VWUp!juoc(_2yQP)4`&=lJpz3Q%*lohJ#12~2x(zU;)9B?>X8S*t~ z1f2aFj0Y5`@0Er|-55X_N=ZqbY2@ezKElHBo=fzOm;0lD|0o-C#&sWA5OUobq%k*RfZd+0i6-_2S6v{)8Z8}PJ~A=+2H%R|)9xN_)4K^LM7bK!GsesDc#g6TD)&-FD|#r@4_Z;I!=TkSpU$ z5hL#_wa$j!41SAWE?o%Bk5DpgDlD^8N{?V&2)qI}IOcz5Fmxb#L`bOZ&^<8yG!@H+ z40twDei?q~j);Dm(s|j$G9k|Q)9M!9&~=`R)qhHh3dX=^s&`&JyBz$N>~_Yx2=s#7 z>G)sT1rXlH*oH<+pGLW7c+v^cmkG1&eJvrFoam`+?b*u>9G}Y@a;%X{e||14=Xsrn z^ESG=wDmn>Zm;Zu{^!}I|9;l#pMvXiXvY{@-#jSC;({N8qHgZ2&yP~)2Cuj_G&C3k ziL4t-6pGHE7J=dHRFFDnXfHmIn9US*vk8ez3c}(O;XvLCVCSPoN`u-%$_(1)6jS8> z+#Mwe^ae``zlSm$>jS4yZH;dNB(hXesP^X!|Ib|?4XX9%XV_;pcj13ktA~{ZC4h5T zWb+AI-~_{k3m2jVmI|O+jJ?FQKbgLS{sM5xISuV$We5LPvskJ9!7xvG9(a=|!|O`} zrHrp%g_}DF^}EUe1O#)8+=kPKlpV~8zA6CB2GITKs_*z1^g1ezcVxjv#m?Ry9K7b7 z=xKH}Pcz&%Qs0rvoGX|3wEKwrBp%O~j3(6;1KO!41n!Hb{{Vy&oh*>95C6^EArTMb z)LQ$y;QXaC>73s@X&SAr$-{c}Ws}h5wh`bpxW7q2U#27hIYZz}0zA!~j4pLP1cUbX zRFwGi^h(Db5XG4jncl4aT~5B=#9a5F9LPoL9u)j;1Xg)fKRxdD!bgBsa0uDIzC^S=P6gy5(E literal 0 HcmV?d00001 diff --git a/test/jdk/java/awt/color/XAWTDifference/XAWTDifference.java b/test/jdk/java/awt/color/XAWTDifference/XAWTDifference.java new file mode 100644 index 0000000000000..ef0f5aacf4479 --- /dev/null +++ b/test/jdk/java/awt/color/XAWTDifference/XAWTDifference.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.ImageIcon; +import javax.swing.JLabel; + +/* + * @test + * @bug 5092883 6513478 7154025 + * @requires (os.family == "linux") + * @summary REGRESSION: SystemColor class gives back wrong values under Linux + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual XAWTDifference + */ + +public class XAWTDifference { + + private static final String INSTRUCTIONS = """ + You would see a frame with title "XAWTDifference Test Frame". + + Test Frame (1) + + a) It has three columns in it. The 1st one with ordinary components. + The 2nd one with disabled components. + The 3rd one with uneditable components (only text components + are there). Verify that the difference between different states + is visible. + + Standard Frame (2) + + b) You would also see a frame named StandardFrame (2) + with a lot of components in it. Actually this is just a jpg-image + in a frame. Verify that every component in the frame (1) looks + similar to the same component in (2). + + They might differ in colors and be darker or brighter but + the whole picture should be the same. + + c) Also check the color of the MenuBar Items in the MenuBar and + the PopupMenu assigned to TextArea. + As you can't compare the colors of menu items with the picture + so just look if the are adequate enough. + """; + private static final int HGAP = 20; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(XAWTDifference::createAndShowUI) + .positionTestUI(XAWTDifference::positionMultiTestUI) + .build() + .awaitAndCheck(); + } + + private static Panel addComponentsIntoPanel(boolean enabled, boolean editable) { + TextField tf = new TextField("TextField"); + TextArea ta = new TextArea("TextArea", 10, 10); + + Choice levelChooser = new Choice(); + levelChooser.add("Item #1"); + levelChooser.add("Item #2"); + + Button b = new Button("BUTTON"); + Label label = new Label("LABEL"); + java.awt.List list = new java.awt.List(4, false); + list.add("one"); + list.add("two"); + list.add("three"); + + Checkbox chb = new Checkbox(); + Scrollbar sb = new Scrollbar(Scrollbar.HORIZONTAL); + ScrollPane sp = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS); + sp.add(new TextArea("this is a textarea in scrollpane")); + sp.setSize(200, 200); + Canvas canvas = new Canvas(); + canvas.setSize(100, 100); + + //add popup menu to Button + final PopupMenu pm = new PopupMenu(); + MenuItem i1 = new MenuItem("Item1"); + MenuItem i2 = new MenuItem("Item2"); + MenuItem i3 = new MenuItem("Item3"); + i3.setEnabled(false); + pm.add(i1); + pm.add(i2); + pm.add(i3); + canvas.add(pm); + + ta.add(pm); + ta.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent me) { + if (me.isPopupTrigger()) { + pm.show(me.getComponent(), me.getX(), me.getY()); + } + } + }); + + ArrayList componentList = new ArrayList<>(); + + componentList.add(tf); + componentList.add(ta); + if (editable){ + componentList.add(levelChooser); + componentList.add(b); + componentList.add(label); + componentList.add(list); + componentList.add(chb); + componentList.add(sb); + componentList.add(sp); + componentList.add(canvas); + } else { + tf.setEditable(false); + ta.setEditable(false); + } + + Panel panel = new Panel(); + panel.setLayout(new GridLayout(0, 1)); + for (Component c : componentList) { + if (!enabled) { + c.setEnabled(false); + } + panel.add(c); + } + return panel; + } + + private static List createAndShowUI() { + Frame testFrame = new Frame("XAWTDifference Test Frame"); + StandardFrame standardFrame = new StandardFrame("StandardFrame"); + standardFrame.pack(); + + testFrame.setLayout(new GridLayout(1, 3)); + testFrame.add(addComponentsIntoPanel(true, true)); + testFrame.add(addComponentsIntoPanel(false, true)); + testFrame.add(addComponentsIntoPanel(true, false)); + + MenuItem mi1 = new MenuItem("Item1"); + MenuItem mi2 = new MenuItem("Item2"); + MenuItem mi3 = new MenuItem("Disabled Item3"); + mi3.setEnabled(false); + + MenuBar mb = new MenuBar(); + Menu enabledMenu = new Menu("Enabled Menu"); + Menu disabledMenu = new Menu("Disabled Menu"); + disabledMenu.setEnabled(false); + mb.add(enabledMenu); + mb.add(disabledMenu); + enabledMenu.add(mi1); + enabledMenu.add(mi2); + enabledMenu.add(mi3); + + testFrame.setMenuBar(mb); + testFrame.setSize(standardFrame.getWidth(), standardFrame.getHeight()); + return List.of(testFrame, standardFrame); + } + + private static void positionMultiTestUI(List windows, + PassFailJFrame.InstructionUI instructionUI) { + int x = instructionUI.getLocation().x + instructionUI.getSize().width + HGAP; + for (Window w : windows) { + w.setLocation(x, instructionUI.getLocation().y); + x += w.getWidth() + HGAP; + } + } + + private static class StandardFrame extends Frame { + public StandardFrame(String name) { + super(name); + String testPath = System.getProperty("test.src", "."); + Panel panel = new Panel(); + panel.add(new JLabel(new ImageIcon(testPath + File.separator + "XAWTColors.jpg"))); + add(panel); + } + } +} From 31858fc4107a616aefd785cc06e932d1f03e2697 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 30 Sep 2024 22:06:23 +0000 Subject: [PATCH 068/188] 8340491: Thread stack-base assertion should report which thread has the un-set stack Reviewed-by: shade, kevinw, stefank --- src/hotspot/share/runtime/thread.cpp | 10 ++++++++++ src/hotspot/share/runtime/thread.hpp | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 7c01c8d4e16b3..5b871248c590b 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -145,6 +145,16 @@ Thread::Thread(MemTag mem_tag) { MACOS_AARCH64_ONLY(DEBUG_ONLY(_wx_init = false)); } +#ifdef ASSERT +address Thread::stack_base() const { + // Note: can't report Thread::name() here as that can require a ResourceMark which we + // can't use because this gets called too early in the thread initialization. + assert(_stack_base != nullptr, "Stack base not yet set for thread id:%d (0 if not set)", + osthread() != nullptr ? osthread()->thread_id() : 0); + return _stack_base; +} +#endif + void Thread::initialize_tlab() { if (UseTLAB) { tlab().initialize(); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 567a76d0eadea..d059a14a0f96d 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -532,7 +532,7 @@ class Thread: public ThreadShadow { public: // Stack overflow support - address stack_base() const { assert(_stack_base != nullptr,"Sanity check"); return _stack_base; } + address stack_base() const DEBUG_ONLY(;) NOT_DEBUG({ return _stack_base; }) void set_stack_base(address base) { _stack_base = base; } size_t stack_size() const { return _stack_size; } void set_stack_size(size_t size) { _stack_size = size; } From a32c3b43aaefdebf5be229f90d9cd26db1859b95 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Mon, 30 Sep 2024 22:09:39 +0000 Subject: [PATCH 069/188] 8340407: Open source a few more Component related tests Reviewed-by: prr --- .../ComponentLeakTest/ComponentLeakTest.java | 769 ++++++++++++++++++ .../ComponentSerializationTest.java | 354 ++++++++ .../MinMaxSizeDefensive/GetSizesTest.java | 113 +++ .../awt/Component/ZOrderTest/ZOrderTest.java | 159 ++++ 4 files changed, 1395 insertions(+) create mode 100644 test/jdk/java/awt/Component/ComponentLeakTest/ComponentLeakTest.java create mode 100644 test/jdk/java/awt/Component/ComponentSerializationTest/ComponentSerializationTest.java create mode 100644 test/jdk/java/awt/Component/MinMaxSizeDefensive/GetSizesTest.java create mode 100644 test/jdk/java/awt/Component/ZOrderTest/ZOrderTest.java diff --git a/test/jdk/java/awt/Component/ComponentLeakTest/ComponentLeakTest.java b/test/jdk/java/awt/Component/ComponentLeakTest/ComponentLeakTest.java new file mode 100644 index 0000000000000..2936880dde6c6 --- /dev/null +++ b/test/jdk/java/awt/Component/ComponentLeakTest/ComponentLeakTest.java @@ -0,0 +1,769 @@ +/* + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key headful + * @requires (os.family != "linux") + * @bug 4119609 4149812 4136116 4171960 4170095 4294016 4343272 + * @summary This test verifies that java.awt objects are being garbage + * collected correctly. That is, it ensures that unneeded + * references (such as JNI global refs or refs in static arrays) + * do not remain after the object is disposed. + * @run main/othervm ComponentLeakTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.CardLayout; +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.LayoutManager; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.util.Map; +import java.util.HashMap; + +public class ComponentLeakTest { + + public static void main(String[] args) { + final int iter = 5; + + for(int count = 0; count < iter; count++) { + MainFrame f = new MainFrame(); + MainWindow w = new MainWindow(f); + MainDialog d = new MainDialog(f); + TestFileDialog fd = new TestFileDialog(f, "TestFileDialog"); + fd.addNotify(); // fd.show() hangs + + fd.dispose(); + d.dispose(); + w.dispose(); + f.dispose(); + } + + // Test layout managers + Frame border = new Frame(); + border.setLayout(new BorderLayout()); + Frame card = new Frame(); + card.setLayout(new CardLayout()); + Frame flow = new Frame(); + flow.setLayout(new FlowLayout()); + Frame gridBag = new Frame(); + gridBag.setLayout(new GridBagLayout()); + Frame grid = new Frame(); + grid.setLayout(new GridLayout(1, 2)); + + for (int count = 0; count < iter; count++) { + border.add(new BorderTestButton("BorderTest"), + BorderLayout.WEST); + border.add(new BorderTestButton("BorderTest"), + BorderLayout.EAST); + card.add(new CardTestButton("CardTest"), "card0"); + card.add(new CardTestButton("CardTest"), "card1"); + flow.add(new FlowTestButton()); + flow.add(new FlowTestButton()); + gridBag.add(new GridBagTestButton(), new GridBagConstraints()); + gridBag.add(new GridBagTestButton(), new GridBagConstraints()); + grid.add(new GridTestButton()); + grid.add(new GridTestButton()); + + border.removeAll(); + card.removeAll(); + flow.removeAll(); + gridBag.removeAll(); + grid.removeAll(); + } + + gc(5); + try { + Thread.sleep(1000); + } catch (InterruptedException ie) { + } + + freeReferences(); + reportLeaks(); + System.err.println("Test passed."); + } + + public static void initWindow(Window w) { + w.setSize(600, 400); + w.setLayout(new FlowLayout()); + + // peered components + w.add(new TestButton("Button")); + w.add(new TestCanvas()); + w.add(new TestCheckbox("Checkbox", true)); + TestChoice choice = new TestChoice(); + choice.add("Choice 1"); + choice.add("Choice Two"); + w.add(choice); + w.add(new TestLabel("Label")); + TestList list = new TestList(); + list.add("List 1"); + list.add("List Two"); + w.add(list); + w.add(new TestScrollbar(Scrollbar.VERTICAL)); + w.add(new TestScrollbar(Scrollbar.HORIZONTAL)); + TestScrollPane scrollpane = new TestScrollPane(); + scrollpane.add(new TestButton("Button in a scrollpane")); + w.add(scrollpane); + w.add(new TestTextArea("TextArea", 3, 30)); + w.add(new TestTextField("TextField")); + + // nested components + TestPanel panel1 = new TestPanel(); + panel1.setLayout(new FlowLayout()); + panel1.setBackground(Color.red); + w.add(panel1); + + panel1.add(new TestButton("level 2")); + + Panel panel2 = new Panel(); + panel2.setLayout(new FlowLayout()); + panel2.setBackground(Color.green); + panel1.add(panel2); + + panel2.add(new TestButton("level 3")); + + w.add(new TestLightweight("Lightweight")); + } + + private static ReferenceQueue queue = new ReferenceQueue(); + private static Map refs = new HashMap(); + + public static void register(Object obj) { + PhantomReference ref = new PhantomReference(obj, queue); + refs.put(ref, obj.getClass().getName()); + } + + private static void gc() { + System.gc(); + try { + Thread.sleep(100); + } catch (InterruptedException ie) { + throw new RuntimeException("Test was interrupted"); + } + } + + private static void gc(int num) { + for (; num > 0; num--) { + gc(); + } + } + + public static void freeReferences() { + System.err.println("Total references: " + refs.size()); + boolean wasFreed = false; + do { + Object[] arr = new Object[2000]; + gc(5); + Reference ref = null; + wasFreed = false; + while ((ref = queue.poll()) != null) { + refs.remove(ref); + wasFreed = true; + gc(); + } + } while (wasFreed); + } + + public static void reportLeaks() { + for (Reference ref : refs.keySet()) { + System.err.println("Leaked " + refs.get(ref)); + } + + if (refs.size() > 0) { + throw new RuntimeException("Some references remained: " + refs.size()); + } + } +} + +class TestFrame extends Frame { + public TestFrame() { + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestFrame(String title) { + super(title); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestWindow extends Window { + public TestWindow(Frame owner) { + super(owner); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestWindow(Window owner) { + super(owner); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestDialogL extends Dialog { + public TestDialogL(Frame owner) { + super(owner); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestDialogL(Frame owner, boolean modal) { + super(owner, modal); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestDialogL(Frame owner, String title) { + super(owner, title); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestDialogL(Frame owner, String title, boolean modal) { + super(owner, title, modal); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestDialogL(Dialog owner) { + super(owner); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestDialogL(Dialog owner, String title) { + super(owner, title); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestDialogL(Dialog owner, String title, boolean modal) { + super(owner, title, modal); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestFileDialog extends FileDialog { + public TestFileDialog(Frame parent) { + super(parent); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestFileDialog(Frame parent, String title) { + super(parent, title); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestFileDialog(Frame parent, String title, int mode) { + super(parent, title, mode); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestButton extends Button { + public TestButton() { + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestButton(String title) { + super(title); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestCanvas extends Canvas { + int width = 100; + int height = 100; + + public TestCanvas() { + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestCanvas(GraphicsConfiguration config) { + super(config); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public void paint(Graphics g) { + g.setColor(Color.blue); + g.fillRoundRect(10, 10, 50, 50, 15, 30); + g.setColor(Color.red); + g.fillOval(70, 70, 25, 25); + } + + public Dimension getPreferredSize() { + return new Dimension(width, height); + } +} + +class TestCheckbox extends Checkbox { + public TestCheckbox() { + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestCheckbox(String label) { + super(label); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestCheckbox(String label, boolean state) { + super(label, state); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestCheckbox(String label, boolean state, CheckboxGroup group) { + super(label, state, group); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestCheckbox(String label, CheckboxGroup group, boolean state) { + super(label, group, state); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestChoice extends Choice { + public TestChoice() { + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestLabel extends Label { + public TestLabel() { + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestLabel(String text) { + super(text); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestLabel(String text, int align) { + super(text, align); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestList extends List { + public TestList() { + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestList(int rows) { + super(rows); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestList(int rows, boolean multipleMode) { + super(rows, multipleMode); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestScrollbar extends Scrollbar { + public TestScrollbar() { + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestScrollbar(int orientation) { + super(orientation); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestScrollbar(int orient, int val, int visible, int min, int max) { + super(orient, val, visible, min, max); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestScrollPane extends ScrollPane { + public TestScrollPane() { + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestScrollPane(int policy) { + super(policy); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestTextField extends TextField { + public TestTextField() { + ComponentLeakTest.register(this); + requestFocus(); + setDropTarget(new TestDropTarget(this)); + } + + public TestTextField(String text) { + super(text); + ComponentLeakTest.register(this); + requestFocus(); + setDropTarget(new TestDropTarget(this)); + } + + public TestTextField(int columns) { + super(columns); + ComponentLeakTest.register(this); + requestFocus(); + setDropTarget(new TestDropTarget(this)); + } + + public TestTextField(String text, int columns) { + super(text, columns); + ComponentLeakTest.register(this); + requestFocus(); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestTextArea extends TextArea { + public TestTextArea() { + ComponentLeakTest.register(this); + requestFocus(); + setDropTarget(new TestDropTarget(this)); + } + + public TestTextArea(String text) { + super(text); + ComponentLeakTest.register(this); + requestFocus(); + setDropTarget(new TestDropTarget(this)); + } + + public TestTextArea(int rows, int columns) { + super(rows, columns); + ComponentLeakTest.register(this); + requestFocus(); + setDropTarget(new TestDropTarget(this)); + } + + public TestTextArea(String text, int rows, int columns) { + super(text, rows, columns); + ComponentLeakTest.register(this); + requestFocus(); + setDropTarget(new TestDropTarget(this)); + } + + public TestTextArea(String text, int rows, int columns, int bars) { + super(text, rows, columns, bars); + ComponentLeakTest.register(this); + requestFocus(); + setDropTarget(new TestDropTarget(this)); + } +} + +class TestPanel extends Panel { + public TestPanel() { + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } + + public TestPanel(LayoutManager layout) { + super(layout); + ComponentLeakTest.register(this); + setDropTarget(new TestDropTarget(this)); + } +} +class TestMenu extends Menu { + public TestMenu() { + ComponentLeakTest.register(this); + } + + public TestMenu(String label) { + super(label); + ComponentLeakTest.register(this); + } + + public TestMenu(String label, boolean tearOff) { + super(label, tearOff); + ComponentLeakTest.register(this); + } +} + +class TestMenuItem extends MenuItem { + public TestMenuItem() { + ComponentLeakTest.register(this); + } + public TestMenuItem(String label) { + super(label); + ComponentLeakTest.register(this); + } + + public TestMenuItem(String label, MenuShortcut s) { + super(label, s); + ComponentLeakTest.register(this); + } +} + +class TestMenuBar extends MenuBar { + public TestMenuBar() { + ComponentLeakTest.register(this); + } +} + +class TestPopupMenu extends PopupMenu { + public TestPopupMenu() { + ComponentLeakTest.register(this); + } + + public TestPopupMenu(String label) { + super(label); + ComponentLeakTest.register(this); + } +} + +class TestCheckboxMenuItem extends CheckboxMenuItem { + public TestCheckboxMenuItem() { + ComponentLeakTest.register(this); + } + + public TestCheckboxMenuItem(String label) { + super(label); + ComponentLeakTest.register(this); + } + + public TestCheckboxMenuItem(String label, boolean state) { + super(label, state); + ComponentLeakTest.register(this); + } +} + +class BorderTestButton extends Button { + public BorderTestButton() { + ComponentLeakTest.register(this); + } + + public BorderTestButton(String title) { + super(title); + ComponentLeakTest.register(this); + } +} + +class CardTestButton extends Button { + public CardTestButton() { + ComponentLeakTest.register(this); + } + + public CardTestButton(String title) { + super(title); + ComponentLeakTest.register(this); + } +} + +class FlowTestButton extends Button { + public FlowTestButton() { + ComponentLeakTest.register(this); + } + + public FlowTestButton(String title) { + super(title); + ComponentLeakTest.register(this); + } +} + +class GridBagTestButton extends Button { + public GridBagTestButton() { + ComponentLeakTest.register(this); + } + + public GridBagTestButton(String title) { + super(title); + ComponentLeakTest.register(this); + } +} + +class GridTestButton extends Button { + public GridTestButton() { + ComponentLeakTest.register(this); + } + + public GridTestButton(String title) { + super(title); + ComponentLeakTest.register(this); + } +} + +class TestLightweight extends Component { + String label; + int width = 100; + int height = 30; + + public TestLightweight(String label) { + this.label = label; + ComponentLeakTest.register(this); + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(Color.orange); + g.fillRect(0, 0, d.width, d.height); + g.setColor(Color.black); + int x = 5; + int y = (d.height - 5); + g.drawString(label, x, y); + } + + public Dimension getPreferredSize() { + return new Dimension(width,height); + } +} + +class TestDropTarget extends DropTarget { + public TestDropTarget(Component comp) { + super(comp, new DropTargetListener() { + public void dragEnter(DropTargetDragEvent dtde) {} + public void dragOver(DropTargetDragEvent dtde) {} + public void dropActionChanged(DropTargetDragEvent dtde) {} + public void dragExit(DropTargetEvent dte) {} + public void drop(DropTargetDropEvent dtde) {} + }); + ComponentLeakTest.register(this); + } +} + +class MainWindow extends TestWindow { + public MainWindow(Frame f) { + super(f); + ComponentLeakTest.initWindow(this); + setVisible(true); + + TestPopupMenu popup = new TestPopupMenu("hi"); + add(popup); + popup.show(this, 5, 5); + } +} + +class MainDialog extends TestDialogL { + public MainDialog(Frame f) { + super(f, "MainDialog", false); + ComponentLeakTest.initWindow(this); + setVisible(true); + + TestPopupMenu popup = new TestPopupMenu("hi"); + add(popup); + popup.show(this, 5, 5); + } +} + +class MainFrame extends TestFrame { + public MainFrame(){ + super("Component Leak Test MainFrame"); + + ComponentLeakTest.initWindow(this); + + TestMenu menu = new TestMenu("Print"); + TestMenu menu2 = new TestMenu("File"); + TestMenu menu3 = new TestMenu("Edit"); + TestMenu menu4 = new TestMenu("ReallyReallyReallyReallyReallyReallyReallyReally" + + "ReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLong"); + menu2.setFont(new Font("SansSerif", Font.BOLD, 20)); + menu2.setEnabled(false); + menu3.setFont(new Font("Monospaced", Font.ITALIC, 18)); + menu3.setEnabled(false); + menu4.setEnabled(false); + TestMenuItem itemPrinter = new TestMenuItem("foobar"); + TestMenuItem itemScreen = new TestMenuItem("baz"); + TestCheckboxMenuItem itemCheck = new TestCheckboxMenuItem("yep"); + menu.add(itemPrinter); + menu.add(itemScreen); + menu.add(itemCheck); + TestMenuBar menuBar = new TestMenuBar(); + menuBar.add( menu ); + menuBar.add( menu2 ); + menuBar.add( menu3 ); + menuBar.add( menu4 ); + setMenuBar(menuBar); + + setVisible(true); + + TestPopupMenu popup = new TestPopupMenu("hi"); + add(popup); + popup.show(this, 5, 5); + } +} diff --git a/test/jdk/java/awt/Component/ComponentSerializationTest/ComponentSerializationTest.java b/test/jdk/java/awt/Component/ComponentSerializationTest/ComponentSerializationTest.java new file mode 100644 index 0000000000000..ddf7efffdbdfc --- /dev/null +++ b/test/jdk/java/awt/Component/ComponentSerializationTest/ComponentSerializationTest.java @@ -0,0 +1,354 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4146452 + * @summary Tests serialization of peered and lightweight Components. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ComponentSerializationTest + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import javax.swing.JPanel; + +public class ComponentSerializationTest extends JPanel { + private MainFrame mf; + private MainWindow mw; + private MainDialog md; + private MainFileDialog mfd; + private static final String INSTRUCTIONS = """ + A Frame, a Window, and a Dialog should appear. From the Frame's + "Serialize" menu, select "Serialize!". Another Frame, Window, and + Dialog should appear exactly on top of the existing ones. The state + and functionality of the two sets of Windows should be identical. If + any errors or exceptions appear in the log area, or if the second set of + Windows is different from the first, the test fails. Otherwise, the + test passes. + """; + + private static final ArrayList toDispose = new ArrayList<>(); + + public ComponentSerializationTest() { + mf = new MainFrame(); + toDispose.add(mf); + mw = new MainWindow(mf); + toDispose.add(mw); + md = new MainDialog(mf); + toDispose.add(md); + mfd = new MainFileDialog(mf); + toDispose.add(mfd); + } + + public static void main(String[] argc) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Component Serialization Test") + .splitUI(ComponentSerializationTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + for (Window w : toDispose) { + if (w != null) { + EventQueue.invokeAndWait(w::dispose); + } + } + } + + private void initWindow(Window w) { + w.setSize(600, 400); + w.setLayout(new FlowLayout()); + + // peered components + w.add(new Button("Button")); + w.add(new TestCanvas()); + w.add(new Checkbox("Checkbox", true)); + Choice choice = new Choice(); + choice.add("Choice 1"); + choice.add("Choice Two"); + w.add(choice); + w.add(new Label("Label")); + List list = new List(); + list.add("List 1"); + list.add("List Two"); + w.add(list); + w.add(new Scrollbar(Scrollbar.VERTICAL)); + w.add(new Scrollbar(Scrollbar.HORIZONTAL)); + ScrollPane scrollpane = new ScrollPane(); + scrollpane.add(new Button("Button in a scrollpane")); + w.add(scrollpane); + w.add(new TextArea("TextArea", 3, 30)); + w.add(new TextField("TextField")); + + // nested components + Panel panel1 = new Panel(); + panel1.setLayout(new FlowLayout()); + panel1.setBackground(Color.red); + w.add(panel1); + + panel1.add(new Button("level 2")); + + Panel panel2 = new Panel(); + panel2.setLayout(new FlowLayout()); + panel2.setBackground(Color.green); + panel1.add(panel2); + + panel2.add(new Button("level 3")); + + // lightweight components + w.add(new LWButton("LWbutton") ); + + // overlapping components + w.add(new ZOrderPanel()); + } + + class MainWindow extends Window { + public MainWindow(Frame f) { + super(f); + initWindow(this); + setLocation(650, 0); + setVisible(true); + } + } + + class MainDialog extends Dialog { + public MainDialog(Frame f) { + super(f, "MainDialog", false); + initWindow(this); + setLocation(0, 450); + setVisible(true); + } + } + + class MainFileDialog extends FileDialog { + public MainFileDialog(Frame f) { + super(f, "MainFileDialog", FileDialog.SAVE); + setLocation(650, 450); + addNotify(); + } + } + + class MainFrame extends Frame { + public MainFrame() { + super("ComponentSerializationTest"); + initWindow(this); + + Menu menu = new Menu("Serialize"); + Menu menu2 = new Menu("File"); + Menu menu3 = new Menu("Edit"); + Menu menu4 = new Menu("ReallyReallyReallyReallyReallyReallyReallyReally" + + "ReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLong"); + menu2.setFont(new Font("SansSerif", Font.BOLD, 20)); + menu2.setEnabled(false); + menu3.setFont(new Font("Monospaced", Font.ITALIC, 18)); + menu3.setEnabled(false); + menu4.setEnabled(false); + MenuItem itemSerialize = new MenuItem("Serialize!"); + CheckboxMenuItem itemCheck = new CheckboxMenuItem("Check me"); + menu.add(itemSerialize); + menu.add(itemCheck); + MenuBar menuBar = new MenuBar(); + menuBar.add(menu); + menuBar.add(menu2); + menuBar.add(menu3); + menuBar.add(menu4); + setMenuBar(menuBar); + + itemSerialize.addActionListener(new ActionSerialize()); + + setLocation(0, 0); + setVisible(true); + } + } + + class ActionSerialize implements ActionListener { + public void actionPerformed(ActionEvent ev) { + Frame f2 = null; + Window w2 = null; + Dialog d2 = null; + FileDialog fd2 = null; + + try { + FileOutputStream fos = new FileOutputStream("tmp"); + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(mf); + oos.writeObject(mw); + oos.writeObject(md); + oos.writeObject(mfd); + oos.flush(); + + FileInputStream fis = new FileInputStream("tmp"); + ObjectInputStream ois = new ObjectInputStream(fis); + f2 = (Frame)ois.readObject(); + w2 = (Window)ois.readObject(); + d2 = (Dialog)ois.readObject(); + fd2= (FileDialog)ois.readObject(); + } catch (Exception e) { + PassFailJFrame.log(e.getMessage()); + } + + if (f2 == null || w2 == null || d2 == null || fd2 == null) { + PassFailJFrame.log("ERROR: one of the components was not deserialized."); + PassFailJFrame.log("frame = " + f2); + PassFailJFrame.log("window = " + w2); + PassFailJFrame.log("dialog = " + d2); + PassFailJFrame.log("file dalog = " + fd2); + } + + if (f2 != null) { + toDispose.add(f2); + f2.setVisible(true); + } + if (w2 != null) { + toDispose.add(w2); + w2.setVisible(true); + } + if (d2 != null) { + toDispose.add(d2); + d2.setVisible(true); + } + if (fd2 != null) { + toDispose.add(fd2); + fd2.addNotify(); + } + } + } + + class LWButton extends Component { + String label; + int width = 100; + int height = 30; + + public LWButton(String label) { + super(); + this.label = label; + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(Color.orange); + g.fillRect(0, 0, d.width, d.height); + g.setColor(Color.black); + int x = 5; + int y = (d.height - 5); + g.drawString(label, x, y); + } + + public Dimension getPreferredSize() { + return new Dimension(width, height); + } + } + + class TestCanvas extends Canvas { + int width = 100; + int height = 100; + + public void paint(Graphics g) { + g.setColor(Color.blue); + g.fillRoundRect(10, 10, 50, 50, 15, 30); + g.setColor(Color.red); + g.fillOval(70, 70, 25, 25); + } + public Dimension getPreferredSize() { + return new Dimension(width, height); + } + } + + class ZOrderPanel extends Panel { + public ZOrderPanel() { + setLayout(null); + + Component first, second, third, fourth; + + show(); + first = makeBox("Second", Color.blue, -1); + second = makeBox("First", Color.yellow, 0); + fourth = makeBox("Fourth", Color.red, 2); + third = makeBox("Third", Color.green, 3); + remove(third); + add(third, 2); + validate(); + add(new LWButton("LWButton"), 0); + } + + public Dimension preferredSize() { + return new Dimension(260, 80); + } + + public void layout() { + int i, n; + Insets ins = insets(); + n = countComponents(); + for (i = n - 1; i >= 0; i--) { + Component p = getComponent(i); + p.reshape(ins.left + 40 * i, ins.top + 5 * i, 60, 60); + } + } + + public Component makeBox(String s, Color c, int index) { + Label l = new Label(s); + l.setBackground(c); + l.setAlignment(Label.RIGHT); + add(l, index); + validate(); + return l; + } + } +} diff --git a/test/jdk/java/awt/Component/MinMaxSizeDefensive/GetSizesTest.java b/test/jdk/java/awt/Component/MinMaxSizeDefensive/GetSizesTest.java new file mode 100644 index 0000000000000..2b4954879380a --- /dev/null +++ b/test/jdk/java/awt/Component/MinMaxSizeDefensive/GetSizesTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 4783989 + @summary get(Preferred|Minimum|Maximum)Size() must not return a reference. + The object copy of Dimension class needed. + @key headful + @run main GetSizesTest +*/ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; + +public class GetSizesTest extends Frame { + Button b; + + public static void main(final String[] args) throws InterruptedException, + InvocationTargetException { + GetSizesTest app = new GetSizesTest(); + EventQueue.invokeAndWait(() -> { + try { + app.init(); + app.start(); + } finally { + app.dispose(); + } + }); + } + + public void init() { + b = new Button("button"); + add(b); + } + + public void start () { + setSize(200, 200); + setLocationRelativeTo(null); + setVisible(true); + validate(); + + System.out.println("Test set for Container (Frame)."); + + Dimension dimPref = getPreferredSize(); + dimPref.setSize(101, 101); + if (getPreferredSize().equals(new Dimension(101, 101))) { + throw new RuntimeException("Test Failed for: " + dimPref); + } + System.out.println("getPreferredSize() Passed."); + + Dimension dimMin = getMinimumSize(); + dimMin.setSize(101, 101); + if (getMinimumSize().equals(new Dimension(101, 101))) { + throw new RuntimeException("Test Failed for: " + dimMin); + } + System.out.println("getMinimumSize() Passed."); + + Dimension dimMax = getMaximumSize(); + dimMax.setSize(101, 101); + if (getMaximumSize().equals(new Dimension(101, 101))) { + throw new RuntimeException("Test Failed for: " + dimMax); + } + System.out.println("getMaximumSize() Passed."); + + System.out.println("Test set for Component (Button)."); + + dimPref = b.getPreferredSize(); + dimPref.setSize(33, 33); + if (b.getPreferredSize().equals(new Dimension(33, 33))) { + throw new RuntimeException("Test Failed for: " + dimPref); + } + System.out.println("getPreferredSize() Passed."); + + dimMin = b.getMinimumSize(); + dimMin.setSize(33, 33); + if (b.getMinimumSize().equals(new Dimension(33, 33))) { + throw new RuntimeException("Test Failed for: " + dimMin); + } + System.out.println("getMinimumSize() Passed."); + + dimMax = b.getMaximumSize(); + dimMax.setSize(33, 33); + if (b.getMaximumSize().equals(new Dimension(33, 33))) { + throw new RuntimeException("Test Failed for: " + dimMax); + } + System.out.println("getMaximumSize() Passed."); + System.out.println("GetSizesTest Succeeded."); + } +} diff --git a/test/jdk/java/awt/Component/ZOrderTest/ZOrderTest.java b/test/jdk/java/awt/Component/ZOrderTest/ZOrderTest.java new file mode 100644 index 0000000000000..15003f753a6fe --- /dev/null +++ b/test/jdk/java/awt/Component/ZOrderTest/ZOrderTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4059430 + * @summary Test for component z-ordering consistency + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ZOrderTest + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Insets; +import java.awt.Label; +import java.awt.Panel; +import java.lang.reflect.InvocationTargetException; +import java.util.List; + +public class ZOrderTest { + public final static String INSTRUCTIONS = """ + The ZOrderTest creates two frames. + - Frame 1 has components added to an intermediate panel + - Frame 2 has components added directly to the frame itself + Verify that the components are in the correct z-order. Lower numbered + components should overlap higher numbered ones (e.g. component zero should + appear on top of component one). + Both frames should have the same component ordering, and this ordering should + be the same on all supported operating systems. + """; + + public static void main(String [] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Component ZOrder Test") + .testUI(ZOrderTest::makeFrames) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } + + private static List makeFrames() { + Frame frame, frame2; + + // test adding components to panel on a frame + frame = new Frame("ZOrderTest(1) for 4059430"); + frame.pack(); + frame.show(); + Panel panel = new ZOrderPanel(); + frame.setBounds(0, 0, 500, 350); + frame.setLayout(new GridLayout()); + frame.add(panel); + doTest(panel); + + // test adding components directly to frame + frame2 = new ZOrderTestFrame("ZOrderTest(2) for 4059430"); + frame2.pack(); + frame2.show(); + frame2.setBounds(80, 80, 500, 350); + doTest(frame2); + + return List.of(frame, frame2); + } + + /* + * This tests various boundary conditions with z-ordering + * - inserting at the top of the z-order + * - inserting at the bottom of the z-order + * - inserting in the middle of the z-order + */ + private static void doTest(Container cont) { + Component compZero, compOne, compTwo, compThree, compFour; + + compZero = makeBox(cont, "Comp One", Color.blue, -1); + // insert on top + compOne = makeBox(cont, "Comp Zero", Color.yellow, 0); + // put at the back + compThree = makeBox(cont, "Comp Three", Color.red, 2); + // insert in last position + compTwo = makeBox(cont, "Comp Two", Color.green, 3); + // swap compTwo and compThree to correct positions + cont.remove(compTwo); + cont.add(compTwo, 2); + // one more test of adding to the end + compFour = makeBox(cont, "Comp Four", Color.magenta, -1); + // re-validate so components cascade into proper place + cont.validate(); + } + + private static Component makeBox(Container cont, String s, Color c, int index) { + Label l = new Label(s); + l.setBackground(c); + l.setAlignment(Label.RIGHT); + if (index == -1) { + cont.add(l); // semantically equivalent to -1, but why not test this too + } else { + cont.add(l, index); + } + cont.validate(); + return l; + } + + /** + * Cascades components across the container so + * that they overlap, demonstrating their z-ordering + */ + static void doCascadeLayout(Container cont) { + int i, n; + Insets ins = cont.insets(); + n = cont.countComponents(); + for (i = n - 1; i >= 0; i--) { + Component comp = cont.getComponent(i); + comp.reshape(ins.left + 75 * i, ins.top + 30 * i, 100, 100); + } + } +} + +class ZOrderPanel extends Panel { + public void layout() { + ZOrderTest.doCascadeLayout(this); + } +} + +class ZOrderTestFrame extends Frame +{ + public ZOrderTestFrame(String title) { + super(title); + } + + public void layout() { + ZOrderTest.doCascadeLayout(this); + } +} From b11066b56b69b2c526539e712cef47723098597f Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Tue, 1 Oct 2024 02:47:40 +0000 Subject: [PATCH 070/188] 8340719: Open source AWT List tests Reviewed-by: prr --- test/jdk/ProblemList.txt | 1 + .../HandlingKeyEventIfMousePressedTest.java | 167 ++++++++++++++++++ .../java/awt/List/ListActionEventTest.java | 93 ++++++++++ .../MultiSelectionListHorizScrollbar.java | 80 +++++++++ .../jdk/java/awt/List/RepaintAfterResize.java | 73 ++++++++ 5 files changed, 414 insertions(+) create mode 100644 test/jdk/java/awt/List/HandlingKeyEventIfMousePressedTest.java create mode 100644 test/jdk/java/awt/List/ListActionEventTest.java create mode 100644 test/jdk/java/awt/List/MultiSelectionListHorizScrollbar.java create mode 100644 test/jdk/java/awt/List/RepaintAfterResize.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 8060792a51f9a..f02272977aa17 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -797,3 +797,4 @@ java/awt/Frame/SizeMinimizedTest.java 8305915 linux-x64 java/awt/PopupMenu/PopupHangTest.java 8340022 windows-all java/awt/Focus/MinimizeNonfocusableWindowTest.java 8024487 windows-all java/awt/Focus/InactiveFocusRace.java 8023263 linux-all +java/awt/List/HandlingKeyEventIfMousePressedTest.java 6848358 macosx-all,windows-all diff --git a/test/jdk/java/awt/List/HandlingKeyEventIfMousePressedTest.java b/test/jdk/java/awt/List/HandlingKeyEventIfMousePressedTest.java new file mode 100644 index 0000000000000..e5c89c1df126d --- /dev/null +++ b/test/jdk/java/awt/List/HandlingKeyEventIfMousePressedTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6293432 + * @summary Key events ('SPACE', 'UP', 'DOWN') aren't blocked + * if mouse is kept in 'PRESSED' state for List + * @key headful + * @run main HandlingKeyEventIfMousePressedTest + */ + +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; + +public class HandlingKeyEventIfMousePressedTest { + + static Frame frame; + static List list; + static volatile Point loc; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> createUI()); + robot.waitForIdle(); + robot.delay(1000); + EventQueue.invokeAndWait(() -> { + loc = list.getLocationOnScreen(); + }); + robot.mouseMove(loc.x + 10, loc.y + 10); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + + // key pressing when the mouse is kept in the 'pressed' state + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + + int selectedIndex = list.getSelectedIndex(); + if (selectedIndex != 0) { + throw new RuntimeException("Test failed: list.getCurrentItem = " + selectedIndex); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createUI() { + frame = new Frame("HandlingKeyEventIfMousePressedTest"); + list = new List(10, false); + + list.add("111"); + list.add("222"); + list.add("333"); + list.add("444"); + frame.add(list); + + addListeners(); + + frame.setLayout(new FlowLayout()); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + // added in order to have more information in failed case + private static void addListeners() { + + list.addMouseMotionListener( + new MouseMotionAdapter() { + @Override + public void mouseDragged(MouseEvent me) { + System.out.println(me); + } + + @Override + public void mouseMoved(MouseEvent me) { + System.out.println(me); + } + }); + + list.addMouseListener( + new MouseAdapter(){ + public void mousePressed(MouseEvent me) { + System.out.println(me); + } + public void mouseClicked(MouseEvent me) { + System.out.println(me); + } + public void mouseEntered(MouseEvent me) { + System.out.println(me); + } + public void mouseExited(MouseEvent me) { + System.out.println(me); + } + public void mouseReleased(MouseEvent me) { + System.out.println(me); + } + }); + + list.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent ae) { + System.out.println(ae); + } + }); + + list.addItemListener( + new ItemListener() { + public void itemStateChanged(ItemEvent ie) { + System.out.println(ie); + } + }); + + list.addFocusListener( + new FocusAdapter() { + public void focusGained(FocusEvent fe) { + System.out.println(fe); + } + public void focusLost(FocusEvent fe) { + System.out.println(fe); + } + }); + } +} diff --git a/test/jdk/java/awt/List/ListActionEventTest.java b/test/jdk/java/awt/List/ListActionEventTest.java new file mode 100644 index 0000000000000..2cd8d04a39dc6 --- /dev/null +++ b/test/jdk/java/awt/List/ListActionEventTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4089604 + * @summary Enter key doesn't fire List actionPerformed as specified + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ListActionEventTest +*/ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.List; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +public class ListActionEventTest { + + private static final String INSTRUCTIONS = """ + A frame will be shown. + 1. Click any item in the list (say item 1) in the frame + 2. A message 'ItemSelected' is displayed on the message window. + 3. Press the return key on the selected item. + 4. If the text 'ActionPerformed' is displayed on the message window, + then press PASS else press FAIL."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ListActionEventTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ListActionEventTest::createTestUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("ListActionEventTest frame"); + + Panel pnl1 = new Panel(); + frame.add(pnl1); + pnl1.setLayout(new BorderLayout()); + + List list = new List(); + for (int i = 0; i < 5; i++) { + list.addItem("Item " + i); + } + pnl1.add(list); + + list.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ev) { + PassFailJFrame.log("ActionPerformed"); + } + }); + + list.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(ItemEvent ev) { + PassFailJFrame.log("ItemSelected"); + } + }); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/List/MultiSelectionListHorizScrollbar.java b/test/jdk/java/awt/List/MultiSelectionListHorizScrollbar.java new file mode 100644 index 0000000000000..289cd0c2daca9 --- /dev/null +++ b/test/jdk/java/awt/List/MultiSelectionListHorizScrollbar.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4102881 + * @summary Ensure multiple selection Lists have horizontal scrollbars when necessary + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiSelectionListHorizScrollbar +*/ + +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.List; + +public class MultiSelectionListHorizScrollbar { + + private static final String INSTRUCTIONS = """ + Resize the frame so that the lists are not wide enough + to fully display the lines of text they contain. + Once the lists are in this state, press pass + if both lists display an horizontal scrollbar. Otherwise press fail."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("MultiSelectionListHorizScrollbar Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MultiSelectionListHorizScrollbar::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("MultiSelectionListHorizScrollbar Frame"); + List singleList = new List(3); + List multiList = new List(3, true); + + frame.setLayout(new GridLayout(1, 2)); + frame.add(singleList); + frame.add(multiList); + + singleList.addItem("This is the 1st item in the list! Does it scroll horizontally??"); + singleList.addItem("This is the 2nd item in the list! Does it scroll horizontally??"); + singleList.addItem("This is the 4th item in the list! Does it scroll horizontally??"); + singleList.addItem("This is the 5th item in the list! Does it scroll horizontally??"); + singleList.addItem("This is the 6th item in the list! Does it scroll horizontally??"); + + multiList.addItem("This is the 1st item in the list! Does it scroll horizontally??"); + multiList.addItem("This is the 2nd item in the list! Does it scroll horizontally??"); + multiList.addItem("This is the 4th item in the list! Does it scroll horizontally??"); + multiList.addItem("This is the 5th item in the list! Does it scroll horizontally??"); + multiList.addItem("This is the 6th item in the list! Does it scroll horizontally??"); + + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/List/RepaintAfterResize.java b/test/jdk/java/awt/List/RepaintAfterResize.java new file mode 100644 index 0000000000000..12bb584aefa88 --- /dev/null +++ b/test/jdk/java/awt/List/RepaintAfterResize.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6308295 + * @summary XAWTduplicate list item is displayed + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RepaintAfterResize +*/ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; + +public class RepaintAfterResize { + + private static final String INSTRUCTIONS = """ + 1) A Frame appears with a list + 2) Resize somehow the frame using mouse + 3) Move down the vertical scrollbar of the list + 4) If you see that two selected items are displayed then the test failed. + Otherwise, the test passed."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("RepaintAfterResize Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(RepaintAfterResize::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("RepaintAfterResize Frame"); + List list = new List(4, false); + + frame.setLayout (new FlowLayout ()); + list.setBounds(100, 100, 100, 100); + for (int i = 0 ; i < 7 ; i++) { + list.add(" " + i); + } + frame.add(list); + list.select(3); + + frame.setSize(100, 100); + return frame; + + } +} From 988f13a3875a6d29d7de07c5e97fcd6e7f9a31ff Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 1 Oct 2024 04:32:55 +0000 Subject: [PATCH 071/188] 8340354: Open source AWT desktop properties and print related tests Reviewed-by: prr --- .../awt/DesktopProperties/FontSmoothing.java | 93 ++++ .../ThreeDBackgroundColor.java | 100 ++++ .../awt/PrintJob/PrintCompatibilityTest.java | 446 ++++++++++++++++ .../java/awt/PrintJob/PrintComponentTest.java | 486 ++++++++++++++++++ .../awt/PrintJob/ScaledImagePrintingTest.java | 102 ++++ 5 files changed, 1227 insertions(+) create mode 100644 test/jdk/java/awt/DesktopProperties/FontSmoothing.java create mode 100644 test/jdk/java/awt/DesktopProperties/ThreeDBackgroundColor.java create mode 100644 test/jdk/java/awt/PrintJob/PrintCompatibilityTest.java create mode 100644 test/jdk/java/awt/PrintJob/PrintComponentTest.java create mode 100644 test/jdk/java/awt/PrintJob/ScaledImagePrintingTest.java diff --git a/test/jdk/java/awt/DesktopProperties/FontSmoothing.java b/test/jdk/java/awt/DesktopProperties/FontSmoothing.java new file mode 100644 index 0000000000000..d3879d4893ff2 --- /dev/null +++ b/test/jdk/java/awt/DesktopProperties/FontSmoothing.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.Toolkit; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +/* + * @test + * @bug 4808569 + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary add desktop property for the Windows XP or later font smoothing settings + * @run main/manual FontSmoothing + */ + +public class FontSmoothing { + + private static final String PROP_NAME = "win.text.fontSmoothingType"; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test should be run on Windows XP or later. + + On Windows 11: + 1. Open Run dialog by typing 'run' in search bar. + 2. Type 'cttune' and press Ok. + 3. Uncheck the "Turn On ClearType" checkbox and follow next instructions on screen. + 4. Repeat Step 1-2. + 5. Check the "Turn On ClearType" checkbox and follow next instructions on screen. + 6. Take a look at the output window to determine if the test passed or failed. + """; + + PassFailJFrame.builder() + .title("FontSmoothing Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testTimeOut(5) + .testUI(FontSmoothing::createUI) + .logArea(8) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("FontSmoothing Test"); + f.setSize(50, 50); + + Object value = Toolkit.getDefaultToolkit().getDesktopProperty(PROP_NAME); + PassFailJFrame.log("toolkit.getDesktopProperty: " + PROP_NAME + " = " + value + "\n"); + + Toolkit.getDefaultToolkit().addPropertyChangeListener(PROP_NAME, new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + PassFailJFrame.log("PropertyChangeEvent: " + e.getPropertyName() + + "\n old value=" + e.getOldValue() + + "\n new value=" + e.getNewValue()); + + Integer value = (Integer) Toolkit.getDefaultToolkit().getDesktopProperty(PROP_NAME); + PassFailJFrame.log("toolkit.getDesktopProperty:" + PROP_NAME + "=" + value); + + if (value.equals((Integer) e.getNewValue())) { + PassFailJFrame.log("test PASSED"); + } else { + PassFailJFrame.log("test FAILED"); + } + } + }); + return f; + } +} diff --git a/test/jdk/java/awt/DesktopProperties/ThreeDBackgroundColor.java b/test/jdk/java/awt/DesktopProperties/ThreeDBackgroundColor.java new file mode 100644 index 0000000000000..26792e79a92d1 --- /dev/null +++ b/test/jdk/java/awt/DesktopProperties/ThreeDBackgroundColor.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Frame; +import java.awt.Toolkit; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +/* + * @test + * @bug 4368193 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @requires (os.family == "windows") + * @summary Toolkit's getDesktopProperty returns stale values on Microsoft Windows + * @run main/manual ThreeDBackgroundColor + */ + +public class ThreeDBackgroundColor { + + private static final String PROP_NAME = "win.3d.backgroundColor"; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + On Windows 10: + 1. Open Windows Settings, in the search bar type + 'high contrast', in the list of suggestions choose option + 'Turn high contrast on or off' + 2. In the High contrast control panel click on the on/off switch + to initialize High contrast mode + 3. Wait for the High contrast mode to finish initialization + 4. Click on the same switch again to turn off High contrast mode + + On Windows 11: + 1. Open Windows settings, in the search bar type + 'Contrast Theme'. + 2. Select any value from 'Contrast themes' dropdown menu and press 'Apply'. + 3. Wait for the High contrast mode to finish initialization + 4. Select 'None' from 'Contrast themes' dropdown menu to revert the changes. + + Take a look at the output window to determine if the test passed or failed."""; + + PassFailJFrame.builder() + .title("ThreeDBackgroundColor Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testTimeOut(5) + .testUI(ThreeDBackgroundColor::createUI) + .logArea(8) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("ThreeDBackgroundColor Test"); + f.setSize(50, 50); + + Object value = Toolkit.getDefaultToolkit().getDesktopProperty(PROP_NAME); + PassFailJFrame.log("toolkit.getDesktopProperty:" + PROP_NAME + "=" + value); + + Toolkit.getDefaultToolkit().addPropertyChangeListener(PROP_NAME, new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent e) { + PassFailJFrame.log("PropertyChangeEvent: " + e.getPropertyName() + + "\n old value=" + e.getOldValue() + + "\n new value=" + e.getNewValue()); + + Color value = (Color) Toolkit.getDefaultToolkit().getDesktopProperty(PROP_NAME); + PassFailJFrame.log("toolkit.getDesktopProperty:" + PROP_NAME + "=" + value); + if (value.equals((Color) e.getNewValue())) { + PassFailJFrame.log("test PASSED"); + } else { + PassFailJFrame.log("test FAILED"); + } + } + }); + return f; + } +} diff --git a/test/jdk/java/awt/PrintJob/PrintCompatibilityTest.java b/test/jdk/java/awt/PrintJob/PrintCompatibilityTest.java new file mode 100644 index 0000000000000..a2433f455470e --- /dev/null +++ b/test/jdk/java/awt/PrintJob/PrintCompatibilityTest.java @@ -0,0 +1,446 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.JobAttributes; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.PageAttributes; +import java.awt.Panel; +import java.awt.PrintJob; +import java.awt.Scrollbar; +import java.awt.ScrollPane; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.JobAttributes.DialogType; +import java.awt.PageAttributes.OriginType; + +import java.util.Enumeration; +import java.util.Properties; + +/* + * @test + * @bug 4247583 + * @key printer + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Tests that the old Properties API still works + * @run main/manual PrintCompatibilityTest + */ + +public class PrintCompatibilityTest { + + public static void main(String[] args) throws Exception { + + String INSTRUCTIONS = """ + A frame window will appear. + Choose 'Print to Printer...' from the 'Print' menu. Make sure that you print + to a printer, not a file. Examine the output and verify that the frame and all + the components in it get printed properly. + + Known problems: + * The text in the second row of the menubar is not indented correctly. + + You can also use the 'Print to Screen...' command for a quick manual check that + printing works, but this is only for debugging purposes."""; + + PassFailJFrame.builder() + .title("PrintComponentTest Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(60) + .testTimeOut(10) + .testUI(new MainFrame()) + .logArea(8) + .build() + .awaitAndCheck(); + } +} + +class MainFrame extends Frame { + private LWContainer lwc; + + public MainFrame() { + super("PrintCompatibilityTest"); + + setSize(800, 400); + setLayout(new FlowLayout()); + + // peered components + Button button = new Button("Button"); + button.setFont(new Font("Dialog", Font.PLAIN, 12)); + add(button); + add(new TestCanvas()); + Checkbox cbox = new Checkbox("Checkbox", true); + cbox.setFont(new Font("DialogInput", Font.PLAIN, 12)); + add(cbox); + Choice choice = new Choice(); + choice.add("Choice 1"); + choice.add("Choice Two"); + choice.setFont(new Font("Monospaced", Font.PLAIN, 12)); + add(choice); + Label label = new Label("Label"); + label.setFont(new Font("Serif", Font.PLAIN, 12)); + add(label); + List list = new List(); + list.add("List 1"); + list.add("List Two"); + list.setFont(new Font("SansSerif", Font.PLAIN, 12)); + add(list); + add(new Scrollbar(Scrollbar.VERTICAL) ); + add(new Scrollbar(Scrollbar.HORIZONTAL) ); + ScrollPane scrollpane = new ScrollPane(); + Button spButton = new Button("Button in a scrollpane"); + spButton.setFont(new Font("Monospaced", Font.PLAIN, 12)); + scrollpane.add(spButton); + add(scrollpane); + TextArea textarea = new TextArea("TextArea", 3, 30); + textarea.setFont(new Font("Dialog", Font.ITALIC, 10)); + add(textarea); + TextField textfield = new TextField("TextField"); + textfield.setFont(new Font("DialogInput", Font.ITALIC, 10)); + add(textfield); + + // nested components + Panel panel1 = new Panel(); + panel1.setLayout(new FlowLayout()); + panel1.setBackground(Color.red); + this.add(panel1); + + Button p1Button = new Button("level 2"); + p1Button.setFont(new Font("Monospaced", Font.ITALIC, 10)); + panel1.add(p1Button); + + Panel panel2 = new Panel(); + panel2.setLayout(new FlowLayout()); + panel2.setBackground(Color.green); + panel1.add(panel2); + + Button p2Button = new Button("level 3"); + p2Button.setFont(new Font("Serif", Font.ITALIC, 10)); + panel2.add(p2Button); + + + // lightweight components + LWButton lwbutton = new LWButton("LWbutton"); + lwbutton.setFont(new Font("SansSerif", Font.ITALIC, 10)); + add(lwbutton); + + lwc = new LWContainer("LWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainer"); + lwc.setFont(new Font("Monospaced", Font.ITALIC, 10)); + add(lwc); + Button lwcButton1 = new Button("HW Button 1"); + Button lwcButton2 = new Button("HW Button 2"); + LWButton lwcButton3 = new LWButton("LW Button"); + lwcButton1.setFont(new Font("Dialog", Font.BOLD, 14)); + lwcButton2.setFont(new Font("DialogInput", Font.BOLD, 14)); + lwcButton3.setFont(new Font("Monospaced", Font.BOLD, 14)); + lwc.add(lwcButton1); + lwc.add(lwcButton2); + lwc.add(lwcButton3); + + // overlapping components + add(new ZOrderPanel()); + + /////////////////////// + + Menu menu = new Menu("Print"); + Menu menu2 = new Menu("File"); + Menu menu3 = new Menu("Edit"); + Menu menu4 = new Menu("ReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLong"); + menu2.setFont(new Font("SansSerif", Font.BOLD, 20)); + menu2.setEnabled(false); + menu3.setFont(new Font("Monospaced", Font.ITALIC, 18)); + menu3.setEnabled(false); + menu4.setEnabled(false); + MenuItem itemPrinter = new MenuItem("Print to Printer..."); + MenuItem itemScreen = new MenuItem("Print to Screen..."); + menu.add(itemPrinter); + menu.add(itemScreen); + MenuBar menuBar = new MenuBar(); + menuBar.add( menu ); + menuBar.add( menu2 ); + menuBar.add( menu3 ); + menuBar.add( menu4 ); + setMenuBar(menuBar); + + itemPrinter.addActionListener( new ActionPrint() ); + itemScreen.addActionListener( new ActionPrintToScreen() ); + setVisible(true); + } + + static void printProps(Properties props) + { + Enumeration propNames = props.propertyNames(); + while (propNames.hasMoreElements()) { + String propName = (String)propNames.nextElement(); + PassFailJFrame.log( propName + " = " + props.getProperty(propName)); + } + } + + class ActionPrint implements ActionListener { + private final int ITERATIONS = 1; + private Properties props = new Properties(); + + public void actionPerformed(ActionEvent ev) { + PassFailJFrame.log("About to show print dialog..."); + printProps(props); + PrintJob pj = getToolkit().getPrintJob( + MainFrame.this, "Print test!", props); + if (pj == null) { + return; + } + Dimension d = pj.getPageDimension(); + PassFailJFrame.log("About to print..."); + PassFailJFrame.log("Dimensions: " + d); + printProps(props); + + // For xor mode set, there is a printing issue with number of copies to be print. + // So, ITERATIONS are changed to 1 from 3. + // So, for now the XOR related code is commented out. + + //boolean xor = false; + + for (int i = 0; i < ITERATIONS; i++) { + Graphics g = pj.getGraphics(); + g.setColor(Color.red); + //if (xor) { + // g.setXORMode(Color.blue); + //} + g.translate(13, 13); + printAll(g); + g.dispose(); + //xor = (xor) ? false : true; + } + + // For xor mode set, LWC components don't get printed. + // So, for now the code is commented out and separate bug + // (JDK-8340495) is filed to handle it. + + // one more page so that we can test printing a lightweight + // at the top of the hierarchy (BugId 4212564) + //Graphics g = pj.getGraphics(); + //g.setColor(Color.red); + //g.translate(13, 13); + //lwc.printAll(g); + //g.dispose(); + // end 4212564 + + pj.end(); + } + } + + class ActionPrintToScreen implements ActionListener { + public void actionPerformed(ActionEvent ev) { + PrintFrame printFrame = new PrintFrame(MainFrame.this); + printFrame.show(); + Graphics g = printFrame.getGraphics(); + g.setColor(Color.red); + printAll(g); + g.dispose(); + } + } + + // Frame window that displays results of printing + // main window to a screen Graphics-- useful for + // quick testing of printing + class PrintFrame extends Frame + { + private Component printComponent; + public PrintFrame( Component c ) + { + super("Print to Screen"); + printComponent = c ; + addWindowListener( new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + setVisible(false); + dispose(); + } + } + ); + setSize(printComponent.getSize()); + setResizable(false); + } + + public void paint( Graphics g ) { + printComponent.printAll(g); + } + } + + class LWButton extends Component { + String label; + int width = 100; + int height = 30; + + public LWButton(String label) { + super(); + this.label = label; + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(Color.orange); + g.setFont(getFont()); + g.fillRect(0, 0, d.width, d.height); + g.setColor(Color.black); + int x = 5; + int y = (d.height - 5); + g.drawString(label, x, y); + } + + public Dimension getPreferredSize() + { + return new Dimension(width, height); + } + } + + class LWContainer extends Container { + String label; + int width = 300; + int height = 100; + + public LWContainer(String label) { + super(); + this.label = label; + setLayout(new FlowLayout()); + } + + public void paint(Graphics g) { + super.paint(g); + Dimension d = getSize(); + g.setColor(Color.green); + g.setFont(getFont()); + g.drawLine(0, 0, d.width - 1, 0); + g.drawLine(d.width - 1, 0, d.width - 1, d.height - 1); + g.drawLine(d.width - 1, d.height - 1, 0, d.height - 1); + g.drawLine(0, d.height - 1, 0, 0); + g.setColor(Color.black); + int x = 5; + int y = (d.height - 5); + g.drawString(label, x, y); + } + + public Dimension getPreferredSize() + { + return new Dimension(width, height); + } + } + + class TestCanvas extends Canvas { + int width = 100; + int height = 100; + + public void paint(Graphics g) { + g.setColor(Color.blue); + g.fillRoundRect(10, 10, 50, 50, 15, 30); + g.setColor(Color.red); + g.fillOval(70, 70, 25, 25); + } + public Dimension getPreferredSize() { + return new Dimension(width, height); + } + } + + class ZOrderPanel extends Panel + { + ZOrderPanel() + { + setLayout(null); + + Component first, second, third, fourth; + + setVisible(true); + // add first component + first = makeBox("Second", Color.blue, + new Font("Serif", Font.BOLD, 14), + -1); + // insert on top + second = makeBox("First", Color.yellow, + new Font("SansSerif", Font.BOLD, 14), + 0); + // put at the back + fourth = makeBox("Fourth", Color.red, + new Font("Monospaced", Font.BOLD, 14), + 2); + // insert in last position + third = makeBox("Third", Color.green, + new Font("Dialog", Font.PLAIN, 12), + 3); + // swap third and fourth to correct positions + remove(third); + add(third, 2); + // re-validate so third and fourth peers change position + validate(); + // now make things really interesting with a lightweight + // component at the top of the z-order, that should print + // _below_ the native guys to match the screen... + add(new LWButton("LWButton"), 0); + } + + public Dimension preferredSize() + { + return new Dimension(260, 80); + } + + public void layout() + { + int i, n; + Insets ins = getInsets(); + n = getComponentCount(); + for (i = n-1; i >= 0; i--) { + Component p = getComponent(i); + p.setBounds(ins.left + 40 * i, ins.top + 5 * i, 60, 60); + } + } + + public Component makeBox(String s, Color c, Font f, int index) + { + Label l = new Label(s); + l.setBackground(c); + l.setAlignment(Label.RIGHT); + l.setFont(f); + add(l, index); + validate(); + return l; + } + } +} diff --git a/test/jdk/java/awt/PrintJob/PrintComponentTest.java b/test/jdk/java/awt/PrintJob/PrintComponentTest.java new file mode 100644 index 0000000000000..d568c5a427977 --- /dev/null +++ b/test/jdk/java/awt/PrintJob/PrintComponentTest.java @@ -0,0 +1,486 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.JobAttributes; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.PageAttributes; +import java.awt.Panel; +import java.awt.PrintJob; +import java.awt.Scrollbar; +import java.awt.ScrollPane; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.JobAttributes.DialogType; +import java.awt.PageAttributes.OriginType; + + +/* + * @test + * @bug 4111262 4035285 4038900 4046147 4049680 4084038 4100004 4105875 + * @bug 4117502 4037486 4068433 4128031 4151161 4151707 4155884 4212564 + * @bug 4025626 4029565 4034365 4036068 4040622 4061890 4067405 4086256 + * @bug 4113827 4116722 4121984 4145350 4146510 4172659 4179886 4218471 + * @bug 4219657 4227128 4242308 4245917 4265746 + * @key printer + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Test printing of lightweight (and heavyweight) components + * @run main/manual PrintComponentTest + */ + +public class PrintComponentTest { + public static void main(String[] args) throws Exception { + + String INSTRUCTIONS = """ + A frame window will appear. + Choose 'Print to Printer...' from the 'Print' menu. Examine the output + and verify that the frame and all the components in it get printed properly. + + Print using both 'Portrait' and 'Landscape' orientation. + Verify that the paper dimensions printed to standard error + are exactly inverted. + (That is, if the output for 'Portrait' is + "Dimensions: java.awt.Dimension[width=612,height=792]" then the output + for 'Landscape' should be "Dimensions: java.awt.Dimension[width=792, height=612].) + + Now, attempt to print a second time. When the print dialog box appears, + however, cancel the print request. + Verify that _no_ output is sent to standard error. + + You should attempt to print with both the native and common print dialogs, + as well as with no dialog. + Note that on Linux the native and common print dialogs are identical. + + On Windows, the common print dialog communicates with the printer to + determine supported paper sizes and duplex capability. + Verify that these constraints are properly enforced in the common dialog + for the target printer. + + Known problems: + * The text in the second row of the menubar is not indented + correctly. + + You can also use the 'Print to Screen...' command for a quick manual + check that printing works, but this is only for debugging purposes."""; + + PassFailJFrame.builder() + .title("PrintComponentTest Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(60) + .testTimeOut(10) + .testUI(new MainFrame()) + .logArea(8) + .build() + .awaitAndCheck(); + } +} + +class MainFrame extends Frame { + private LWContainer lwc; + + public MainFrame() { + super("PrintComponentTest"); + + setSize(800, 400); + setLayout(new FlowLayout()); + + // peered components + Button button = new Button("Button"); + button.setFont(new Font("Dialog", Font.PLAIN, 12)); + add(button); + add(new TestCanvas()); + Checkbox cbox = new Checkbox("Checkbox", true); + cbox.setFont(new Font("DialogInput", Font.PLAIN, 12)); + add(cbox); + Choice choice = new Choice(); + choice.add("Choice 1"); + choice.add("Choice Two"); + choice.setFont(new Font("Monospaced", Font.PLAIN, 12)); + add(choice); + Label label = new Label("Label"); + label.setFont(new Font("Serif", Font.PLAIN, 12)); + add(label); + List list = new List(); + list.add("List 1"); + list.add("List Two"); + list.setFont(new Font("SansSerif", Font.PLAIN, 12)); + add(list); + add(new Scrollbar(Scrollbar.VERTICAL) ); + add(new Scrollbar(Scrollbar.HORIZONTAL) ); + ScrollPane scrollpane = new ScrollPane(); + Button spButton = new Button("Button in a scrollpane"); + spButton.setFont(new Font("Monospaced", Font.PLAIN, 12)); + scrollpane.add(spButton); + add(scrollpane); + TextArea textarea = new TextArea("TextArea", 3, 30); + textarea.setFont(new Font("Dialog", Font.ITALIC, 10)); + add(textarea); + TextField textfield = new TextField("TextField"); + textfield.setFont(new Font("DialogInput", Font.ITALIC, 10)); + add(textfield); + + // nested components + Panel panel1 = new Panel(); + panel1.setLayout(new FlowLayout()); + panel1.setBackground(Color.red); + this.add(panel1); + + Button p1Button = new Button("level 2"); + p1Button.setFont(new Font("Monospaced", Font.ITALIC, 10)); + panel1.add(p1Button); + + Panel panel2 = new Panel(); + panel2.setLayout(new FlowLayout()); + panel2.setBackground(Color.green); + panel1.add(panel2); + + Button p2Button = new Button("level 3"); + p2Button.setFont(new Font("Serif", Font.ITALIC, 10)); + panel2.add(p2Button); + + + // lightweight components + LWButton lwbutton = new LWButton("LWbutton"); + lwbutton.setFont(new Font("SansSerif", Font.ITALIC, 10)); + add(lwbutton); + + lwc = new LWContainer("LWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainerLWContainer"); + lwc.setFont(new Font("Monospaced", Font.ITALIC, 10)); + add(lwc); + Button lwcButton1 = new Button("HW Button 1"); + Button lwcButton2 = new Button("HW Button 2"); + LWButton lwcButton3 = new LWButton("LW Button"); + lwcButton1.setFont(new Font("Dialog", Font.BOLD, 14)); + lwcButton2.setFont(new Font("DialogInput", Font.BOLD, 14)); + lwcButton3.setFont(new Font("Monospaced", Font.BOLD, 14)); + lwc.add(lwcButton1); + lwc.add(lwcButton2); + lwc.add(lwcButton3); + + // overlapping components + add(new ZOrderPanel()); + + /////////////////////// + + Menu menu = new Menu("Print"); + Menu menu2 = new Menu("File"); + Menu menu3 = new Menu("Edit"); + Menu menu4 = new Menu("ReallyReallyReallyReallyReallyReallyReallyReally" + + "ReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReally" + + "ReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyReallyLong"); + menu2.setFont(new Font("SansSerif", Font.BOLD, 20)); + menu2.setEnabled(false); + menu3.setFont(new Font("Monospaced", Font.ITALIC, 18)); + menu3.setEnabled(false); + menu4.setEnabled(false); + MenuItem itemJFC = + new MenuItem("Print to Printer with Cross-Platform Dialog..."); + itemJFC.setActionCommand("common"); + MenuItem itemNative = + new MenuItem("Print to Printer with Native Dialog..."); + itemNative.setActionCommand("native"); + MenuItem itemBackground = + new MenuItem("Print to Printer in Background"); + itemBackground.setActionCommand("none"); + MenuItem itemScreen = new MenuItem("Print to Screen..."); + menu.add(itemJFC); + menu.add(itemNative); + menu.add(itemBackground); + menu.add(itemScreen); + MenuBar menuBar = new MenuBar(); + menuBar.add( menu ); + menuBar.add( menu2 ); + menuBar.add( menu3 ); + menuBar.add( menu4 ); + setMenuBar(menuBar); + + ActionPrint actionPrint = new ActionPrint(); + + itemJFC.addActionListener( actionPrint ); + itemNative.addActionListener( actionPrint ); + itemBackground.addActionListener( actionPrint ); + itemScreen.addActionListener( new ActionPrintToScreen() ); + } + + class ActionPrint implements ActionListener { + private final int ITERATIONS = 1; + private PageAttributes pageAttributes = new PageAttributes(); + private JobAttributes jobAttributes = new JobAttributes(); + + public void actionPerformed(ActionEvent ev) { + DialogType dialog; + if (ev.getActionCommand().equals("common")) { + dialog = DialogType.COMMON; + } else if (ev.getActionCommand().equals("native")) { + dialog = DialogType.NATIVE; + } else { + dialog = DialogType.NONE; + } + jobAttributes.setDialog(dialog); + pageAttributes.setOrigin(OriginType.PRINTABLE); + System.err.println(jobAttributes); + System.err.println(pageAttributes); + + PassFailJFrame.log("About to show print dialog..."); + + PrintJob pj = getToolkit().getPrintJob( + MainFrame.this, "Print test!", jobAttributes, pageAttributes); + if (pj == null) { + return; + } + Dimension d = pj.getPageDimension(); + PassFailJFrame.log("About to print..."); + PassFailJFrame.log("Dimensions: " + d); + System.err.println(jobAttributes); + System.err.println(pageAttributes); + + // For xor mode set, there is a printing issue with number of copies to be print. + // So, ITERATIONS are changed to 1 from 3. + // So, for now the XOR related code is commented out. + + //boolean xor = false; + + for (int i = 0; i < ITERATIONS; i++) { + Graphics g = pj.getGraphics(); + g.setColor(Color.red); + //if (xor) { + // g.setXORMode(Color.blue); + //} + printAll(g); + g.dispose(); + //xor = (xor) ? false : true; + } + + // For xor mode set, LWC components don't get printed. + // So, for now the code is commented out and separate bug + // (JDK-8340495) is filed to handle it. + + // one more page so that we can test printing a lightweight + // at the top of the hierarchy (BugId 4212564) + //Graphics g = pj.getGraphics(); + //g.setColor(Color.red); + //lwc.printAll(g); + //g.dispose(); + // end 4212564 + + pj.end(); + } + } + + class ActionPrintToScreen implements ActionListener { + public void actionPerformed(ActionEvent ev) { + PrintFrame printFrame = new PrintFrame(MainFrame.this); + printFrame.show(); + Graphics g = printFrame.getGraphics(); + g.setColor(Color.red); + printAll(g); + g.dispose(); + } + } + + // Frame window that displays results of printing + // main window to a screen Graphics-- useful for + // quick testing of printing + class PrintFrame extends Frame + { + private Component printComponent; + public PrintFrame( Component c ) + { + super("Print to Screen"); + printComponent = c ; + addWindowListener( new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + setVisible(false); + dispose(); + } + } + ); + setSize(printComponent.getSize()); + setResizable(false); + } + + public void paint( Graphics g ) { + printComponent.printAll(g); + } + } + + class LWButton extends Component { + String label; + int width = 100; + int height = 30; + + public LWButton(String label) { + super(); + this.label = label; + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(Color.orange); + g.setFont(getFont()); + g.fillRect(0, 0, d.width, d.height); + g.setColor(Color.black); + int x = 5; + int y = (d.height - 5); + g.drawString(label, x, y); + } + + public Dimension getPreferredSize() + { + return new Dimension(width, height); + } + } + + class LWContainer extends Container { + String label; + int width = 300; + int height = 100; + + public LWContainer(String label) { + super(); + this.label = label; + setLayout(new FlowLayout()); + } + + public void paint(Graphics g) { + super.paint(g); + Dimension d = getSize(); + g.setColor(Color.green); + g.setFont(getFont()); + g.drawLine(0, 0, d.width - 1, 0); + g.drawLine(d.width - 1, 0, d.width - 1, d.height - 1); + g.drawLine(d.width - 1, d.height - 1, 0, d.height - 1); + g.drawLine(0, d.height - 1, 0, 0); + g.setColor(Color.black); + int x = 5; + int y = (d.height - 5); + g.drawString(label, x, y); + } + + public Dimension getPreferredSize() + { + return new Dimension(width, height); + } + } + + class TestCanvas extends Canvas { + int width = 100; + int height = 100; + + public void paint(Graphics g) { + g.setColor(Color.blue); + g.fillRoundRect(10, 10, 50, 50, 15, 30); + g.setColor(Color.red); + g.fillOval(70, 70, 25, 25); + } + public Dimension getPreferredSize() { + return new Dimension(width, height); + } + } + + class ZOrderPanel extends Panel + { + ZOrderPanel() + { + setLayout(null); + + Component first, second, third, fourth; + + setVisible(true); + // add first component + first = makeBox("Second", Color.blue, + new Font("Serif", Font.BOLD, 14), + -1); + // insert on top + second = makeBox("First", Color.yellow, + new Font("SansSerif", Font.BOLD, 14), + 0); + // put at the back + fourth = makeBox("Fourth", Color.red, + new Font("Monospaced", Font.BOLD, 14), + 2); + // insert in last position + third = makeBox("Third", Color.green, + new Font("Dialog", Font.PLAIN, 12), + 3); + // swap third and fourth to correct positions + remove(third); + add(third, 2); + // re-validate so third and fourth peers change position + validate(); + // now make things really interesting with a lightweight + // component at the top of the z-order, that should print + // _below_ the native guys to match the screen... + add(new LWButton("LWButton"), 0); + } + + public Dimension preferredSize() + { + return new Dimension(260, 80); + } + + public void layout() + { + int i, n; + Insets ins = getInsets(); + n = getComponentCount(); + for (i = n-1; i >= 0; i--) { + Component p = getComponent(i); + p.setBounds(ins.left + 40 * i, ins.top + 5 * i, 60, 60); + } + } + + public Component makeBox(String s, Color c, Font f, int index) + { + Label l = new Label(s); + l.setBackground(c); + l.setAlignment(Label.RIGHT); + l.setFont(f); + add(l, index); + validate(); + return l; + } + } +} diff --git a/test/jdk/java/awt/PrintJob/ScaledImagePrintingTest.java b/test/jdk/java/awt/PrintJob/ScaledImagePrintingTest.java new file mode 100644 index 0000000000000..838c9210e308b --- /dev/null +++ b/test/jdk/java/awt/PrintJob/ScaledImagePrintingTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.PrintJob; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4257962 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary tests that scaled images are printed at resolution greater than 72dpi + * @run main/manual ScaledImagePrintingTest + */ + +public class ScaledImagePrintingTest { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Press 'Print' button from the test UI. + + The test will bring up a print dialog. Select a printer and proceed. + Verify that the output is a series of a horizontal lines in a + rectangular box in the center of the page. + + If output is as mentioned above, press Pass else Fail."""; + + PassFailJFrame.builder() + .title("ScaledImagePrintingTest Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testTimeOut(5) + .testUI(ScaledImagePrintingTest::createUI) + .logArea(8) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame("ResolutionTest"); + Button b = new Button("Print"); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + PrintJob pj = frame.getToolkit().getPrintJob(frame, "ResolutionTest", null); + PassFailJFrame.log("Printing code started."); + if (pj != null) { + Graphics g = pj.getGraphics(); + g.setColor(Color.black); + int w = 200; + int h = 200; + Image image = frame.createImage(w, h); + Graphics imageGraphics = image.getGraphics(); + Dimension d = pj.getPageDimension(); + imageGraphics.setColor(Color.black); + for (int i = 0; i < h; i += 20) { + imageGraphics.drawLine(0, i, w, i); + } + g.translate(d.width / 2, d.height / 2); + g.drawImage(image, -w / 8, -h / 8, w / 4, h / 4, frame); + g.setColor(Color.black); + g.drawRect(-w / 4, -h / 4, w / 2, h / 2); + imageGraphics.dispose(); + g.dispose(); + pj.end(); + } + PassFailJFrame.log("Printing code finished."); + } + }); + frame.add(b); + frame.setSize(50, 50); + return frame; + } +} From 9bd478593cc92a716151d1373f3426f1d92143bb Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Tue, 1 Oct 2024 04:40:16 +0000 Subject: [PATCH 072/188] 8340437: Open source few more AWT Frame related tests Reviewed-by: prr, kizune --- .../awt/Frame/DisabledParentOfToplevel.java | 99 ++++ test/jdk/java/awt/Frame/FrameVisualTest.java | 117 +++++ test/jdk/java/awt/Frame/IMStatusBar.java | 70 +++ test/jdk/java/awt/Frame/MultiScreenTest.java | 485 ++++++++++++++++++ 4 files changed, 771 insertions(+) create mode 100644 test/jdk/java/awt/Frame/DisabledParentOfToplevel.java create mode 100644 test/jdk/java/awt/Frame/FrameVisualTest.java create mode 100644 test/jdk/java/awt/Frame/IMStatusBar.java create mode 100644 test/jdk/java/awt/Frame/MultiScreenTest.java diff --git a/test/jdk/java/awt/Frame/DisabledParentOfToplevel.java b/test/jdk/java/awt/Frame/DisabledParentOfToplevel.java new file mode 100644 index 0000000000000..878809749d35a --- /dev/null +++ b/test/jdk/java/awt/Frame/DisabledParentOfToplevel.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Window; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 5062118 + * @key headful + * @summary Disabling of a parent should not disable Window. + * @run main DisabledParentOfToplevel + */ + +public class DisabledParentOfToplevel { + private static Button okBtn; + private static Window ww; + private static Frame parentFrame; + private static volatile Point p; + private static volatile Dimension d; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> { + createAndShowUI(); + }); + robot.delay(1000); + EventQueue.invokeAndWait(() -> { + p = okBtn.getLocationOnScreen(); + d = okBtn.getSize(); + }); + robot.mouseMove(p.x + d.width / 2, p.x + d.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(500); + if (ww.isVisible()) { + throw new RuntimeException("Window is visible but should be hidden: failure."); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (parentFrame != null) { + parentFrame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + parentFrame = new Frame("parentFrame"); + parentFrame.setSize(100, 100); + parentFrame.setEnabled(false); + ww = new Window(parentFrame); + ww.setLayout(new BorderLayout()); + okBtn = new Button("Click to Close Me"); + ww.add(okBtn); + ww.setSize(250, 250); + ww.setLocation(110, 110); + okBtn.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent me) { + System.out.println("Pressed: close"); + ww.setVisible(false); + } + }); + parentFrame.setVisible(true); + ww.setVisible(true); + okBtn.requestFocus(); + } +} diff --git a/test/jdk/java/awt/Frame/FrameVisualTest.java b/test/jdk/java/awt/Frame/FrameVisualTest.java new file mode 100644 index 0000000000000..767eb0a18965c --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameVisualTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; + +/* + * @test + * @bug 4328588 + * @key headful + * @summary Non-default visual on top-level Frame should work + * @run main FrameVisualTest + */ + +public class FrameVisualTest { + private static GraphicsConfiguration[] gcs; + private static volatile Frame[] frames; + private static volatile int index; + + private static Frame f; + private static Robot robot; + private static volatile Point p; + private static volatile Dimension d; + private static final int TOLERANCE = 5; + + public static void main(String[] args) throws Exception { + gcs = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getConfigurations(); + robot = new Robot(); + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> { + createAndShowUI(); + }); + robot.delay(1000); + System.out.println("frames.length: "+frames.length); + for (index = 0; index < frames.length; index++) { + EventQueue.invokeAndWait(() -> { + p = frames[index].getLocation(); + d = frames[index].getSize(); + }); + Rectangle rect = new Rectangle(p, d); + BufferedImage img = robot.createScreenCapture(rect); + if (chkImgBackgroundColor(img)) { + try { + ImageIO.write(img, "png", new File("Frame_" + index + ".png")); + } catch (IOException ignored) {} + throw new RuntimeException("Frame visual test failed with non-white background color"); + } + } + } finally { + for (index = 0; index < frames.length; index++) { + EventQueue.invokeAndWait(() -> { + if (frames[index] != null) { + frames[index].dispose(); + } + }); + } + } + } + + private static void createAndShowUI() { + frames = new Frame[gcs.length]; + for (int i = 0; i < frames.length; i++) { + frames[i] = new Frame("Frame w/ gc " + i, gcs[i]); + frames[i].setSize(100, 100); + frames[i].setUndecorated(true); + frames[i].setBackground(Color.WHITE); + frames[i].setVisible(true); + } + } + + private static boolean chkImgBackgroundColor(BufferedImage img) { + + // scan for mid-line and if it is non-white color then return true. + for (int x = 1; x < img.getWidth() - 1; ++x) { + Color c = new Color(img.getRGB(x, img.getHeight() / 2)); + if ((c.getRed() - Color.WHITE.getRed()) > TOLERANCE && + (c.getGreen() - Color.WHITE.getGreen()) > TOLERANCE && + (c.getBlue() - Color.WHITE.getBlue()) > TOLERANCE) { + return true; + } + } + return false; + } +} + diff --git a/test/jdk/java/awt/Frame/IMStatusBar.java b/test/jdk/java/awt/Frame/IMStatusBar.java new file mode 100644 index 0000000000000..7e882d01c707c --- /dev/null +++ b/test/jdk/java/awt/Frame/IMStatusBar.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Panel; +import java.awt.TextField; + +/* + * @test + * @bug 4113040 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Checks that IMStatusBar does not affect Frame layout + * @run main/manual/othervm -Duser.language=ja -Duser.country=JP IMStatusBar + */ + +public class IMStatusBar { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + If the window appears the right size, but then resizes so that the + status field overlaps the bottom label, press Fail; otherwise press Pass. + """; + + PassFailJFrame.builder() + .title("IMStatusBar Instruction") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(IMStatusBar::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame(); + Panel centerPanel = new Panel(); + f.setSize(200, 200); + f.setLayout(new BorderLayout()); + f.add(new Label("Top"), BorderLayout.NORTH); + f.add(centerPanel, BorderLayout.CENTER); + f.add(new Label("Bottom"), BorderLayout.SOUTH); + centerPanel.setLayout(new BorderLayout()); + centerPanel.add(new TextField("Middle"), BorderLayout.CENTER); + centerPanel.validate(); + return f; + } +} diff --git a/test/jdk/java/awt/Frame/MultiScreenTest.java b/test/jdk/java/awt/Frame/MultiScreenTest.java new file mode 100644 index 0000000000000..845f601138b74 --- /dev/null +++ b/test/jdk/java/awt/Frame/MultiScreenTest.java @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Label; +import java.awt.LayoutManager; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.TextField; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import java.awt.image.ColorModel; +import java.awt.image.MemoryImageSource; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JFrame; + +import jtreg.SkippedException; + +/* + * @test + * @bug 4312921 + * @key multimon + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame + * @summary Tests that no garbage is painted on primary screen with DGA + * @run main/manual MultiScreenTest + */ + +public class MultiScreenTest { + static GraphicsEnvironment ge; + static GraphicsDevice[] gs; + + public static void main(String[] args) throws Exception { + ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + gs = ge.getScreenDevices(); + if (gs.length < 2) { + throw new SkippedException("You have only one monitor in your system - test passed"); + } + MultiScreenTest obj = new MultiScreenTest(); + String INSTRUCTIONS = + "This test is to be run only on multiscreen machine. " + + "You have " + gs.length + " monitors in your system.\n" + + "Actively drag the DitherTest frames on the secondary screen and " + + "if you see garbage appearing on your primary screen " + + "test failed otherwise it passed.";; + + PassFailJFrame.builder() + .title("MultiScreenTest Instruction") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(obj::init) + .build() + .awaitAndCheck(); + } + + public List init() { + List list = new ArrayList<>(); + for (int j = 0; j < gs.length; j++) { + GraphicsConfiguration[] gc = gs[j].getConfigurations(); + if (gc.length > 0) { + for (int i = 0; i < gc.length / 2; i++) { + JFrame f = new JFrame(gc[i]); //test JFrame( gc ) + GCCanvas c = new GCCanvas(gc[i]);//test canvas( gc ) + Rectangle gcBounds = gc[i].getBounds(); //test getBounds() + int xoffs = gcBounds.x; + int yoffs = gcBounds.y; + + f.getContentPane().add(c); + f.setTitle("Screen# " + Integer.toString(j) + ", GC#" + Integer.toString(i)); + f.setSize(300, 200); + f.setLocation(400 + xoffs, (i * 150) + yoffs);//test displaying in right location + list.add(f); + + Frame ditherfs = new Frame("DitherTest GC#" + Integer.toString(i), gc[i]); + ditherfs.setLayout(new BorderLayout()); //showDitherTest + DitherTest ditherTest = new DitherTest(gc[i]); + ditherfs.add("Center", ditherTest); + ditherfs.setBounds(300, 200, 300, 200); + ditherfs.setLocation(750 + xoffs, (i * 50) + yoffs); + ditherfs.pack(); + ditherfs.show(); + ditherTest.start(); + } + } + } + return list; + } +} + +class GCCanvas extends Canvas { + + GraphicsConfiguration gc; + Rectangle bounds; + Graphics g = this.getGraphics(); + Dimension size = getSize(); + + public GCCanvas(GraphicsConfiguration gc) { + super(gc); + this.gc = gc; + bounds = gc.getBounds(); + } + + public void paint( Graphics _g ) { + + Graphics2D g = (Graphics2D) _g; + + g.drawRect(0, 0, size.width-1, size.height-1); + g.setColor(Color.lightGray); + g.draw3DRect(1, 1, size.width-3, size.height-3, true); + + g.setColor(Color.red); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + + g.drawString("HELLO!", 110, 10); + + g.setColor(Color.blue); + g.drawString("ScreenSize="+Integer.toString(bounds.width)+"X"+ + Integer.toString(bounds.height), 10, 20); + g.setColor(Color.green); + g.drawString(gc.toString(), 10, 30); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); + + g.setColor(Color.orange); + g.fillRect(40, 20, 50, 50); + + g.setColor(Color.red); + g.drawRect(100, 20, 30, 30); + + g.setColor(Color.gray); + g.drawLine(220, 20, 280, 40); + + g.setColor(Color.cyan); + g.fillArc(150, 30, 30, 30, 0, 200); + } + + public Dimension getPreferredSize(){ + return new Dimension(300, 200); + } +} + +class DitherCanvas extends Canvas { + Image img; + static String calcString = "Calculating..."; + + GraphicsConfiguration mGC; + + public DitherCanvas(GraphicsConfiguration gc) { + super(gc); + mGC = gc; + } + + public GraphicsConfiguration getGraphicsConfig() { + return mGC; + } + + public void paint(Graphics g) { + int w = getSize().width; + int h = getSize().height; + if (img == null) { + super.paint(g); + g.setColor(Color.black); + FontMetrics fm = g.getFontMetrics(); + int x = (w - fm.stringWidth(calcString)) / 2; + int y = h / 2; + g.drawString(calcString, x, y); + } else { + g.drawImage(img, 0, 0, w, h, this); + } + } + + public void update(Graphics g) { + paint(g); + } + + public Dimension getMinimumSize() { + return new Dimension(20, 20); + } + + public Dimension getPreferredSize() { + return new Dimension(200, 200); + } + + public Image getImage() { + return img; + } + + public void setImage(Image img) { + this.img = img; + paint(getGraphics()); + } +} + +class DitherTest extends Panel implements Runnable { + final static int NOOP = 0; + final static int RED = 1; + final static int GREEN = 2; + final static int BLUE = 3; + final static int ALPHA = 4; + final static int SATURATION = 5; + + Thread runner; + + DitherControls XControls; + DitherControls YControls; + DitherCanvas canvas; + + public DitherTest(GraphicsConfiguration gc) { + String xspec, yspec; + int xvals[] = new int[2]; + int yvals[] = new int[2]; + + xspec = "red"; + yspec = "blue"; + int xmethod = colormethod(xspec, xvals); + int ymethod = colormethod(yspec, yvals); + + setLayout(new BorderLayout()); + XControls = new DitherControls(this, xvals[0], xvals[1], + xmethod, false); + YControls = new DitherControls(this, yvals[0], yvals[1], + ymethod, true); + YControls.addRenderButton(); + add("North", XControls); + add("South", YControls); + add("Center", canvas = new DitherCanvas(gc)); + } + + public void start() { + runner = new Thread(this); + runner.start(); + } + + int colormethod(String s, int vals[]) { + int method = NOOP; + + if (s == null) { + s = ""; + } + + String lower = s.toLowerCase(); + int len = 0; + if (lower.startsWith("red")) { + method = RED; + lower = lower.substring(3); + } else if (lower.startsWith("green")) { + method = GREEN; + lower = lower.substring(5); + } else if (lower.startsWith("blue")) { + method = BLUE; + lower = lower.substring(4); + } else if (lower.startsWith("alpha")) { + method = ALPHA; + lower = lower.substring(4); + } else if (lower.startsWith("saturation")) { + method = SATURATION; + lower = lower.substring(10); + } + + if (method == NOOP) { + vals[0] = 0; + vals[1] = 0; + return method; + } + + int begval = 0; + int endval = 255; + + try { + int dash = lower.indexOf('-'); + if (dash < 0) { + begval = endval = Integer.parseInt(lower); + } else { + begval = Integer.parseInt(lower.substring(0, dash)); + endval = Integer.parseInt(lower.substring(dash + 1)); + } + } catch (Exception e) { + } + + if (begval < 0) { + begval = 0; + } + if (endval < 0) { + endval = 0; + } + if (begval > 255) { + begval = 255; + } + if (endval > 255) { + endval = 255; + } + + vals[0] = begval; + vals[1] = endval; + + return method; + } + + void applymethod(int c[], int method, int step, int total, int vals[]) { + if (method == NOOP) + return; + int val = ((total < 2) + ? vals[0] + : vals[0] + ((vals[1] - vals[0]) * step / (total - 1))); + switch (method) { + case RED: + c[0] = val; + break; + case GREEN: + c[1] = val; + break; + case BLUE: + c[2] = val; + break; + case ALPHA: + c[3] = val; + break; + case SATURATION: + int max = Math.max(Math.max(c[0], c[1]), c[2]); + int min = max * (255 - val) / 255; + if (c[0] == 0) { + c[0] = min; + } + if (c[1] == 0) { + c[1] = min; + } + if (c[2] == 0) { + c[2] = min; + } + break; + } + } + + public void run() { + canvas.setImage(null); // Wipe previous image + Image img = calculateImage(); + synchronized (this) { + if (img != null && runner == Thread.currentThread()) { + canvas.setImage(img); + } + } + } + + /** + * Calculates and returns the image. Halts the calculation and returns + * null if stopped during the calculation. + */ + Image calculateImage() { + Thread me = Thread.currentThread(); + + int width = canvas.getSize().width; + int height = canvas.getSize().height; + int xvals[] = new int[2]; + int yvals[] = new int[2]; + int xmethod = XControls.getParams(xvals); + int ymethod = YControls.getParams(yvals); + int pixels[] = new int[width * height]; + int c[] = new int[4]; + int index = 0; + + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + c[0] = c[1] = c[2] = 0; + c[3] = 255; + if (xmethod < ymethod) { + applymethod(c, xmethod, i, width, xvals); + applymethod(c, ymethod, j, height, yvals); + } else { + applymethod(c, ymethod, j, height, yvals); + applymethod(c, xmethod, i, width, xvals); + } + pixels[index++] = ((c[3] << 24) | + (c[0] << 16) | + (c[1] << 8) | + (c[2] << 0)); + + } + // Poll once per row to see if we've been told to stop. + if (runner != me) { + return null; + } + } + + return createImage(new MemoryImageSource(width, height, + ColorModel.getRGBdefault(), pixels, 0, width)); + } + + public String getInfo() { + return "An interactive demonstration of dithering."; + } + + public String[][] getParameterInfo() { + String[][] info = { + {"xaxis", "{RED, GREEN, BLUE, PINK, ORANGE, MAGENTA, CYAN, WHITE, YELLOW, GRAY, DARKGRAY}", + "The color of the Y axis. Default is RED."}, + {"yaxis", "{RED, GREEN, BLUE, PINK, ORANGE, MAGENTA, CYAN, WHITE, YELLOW, GRAY, DARKGRAY}", + "The color of the X axis. Default is BLUE."} + }; + return info; + } +} + +class DitherControls extends Panel implements ActionListener { + TextField start; + TextField end; + Button button; + Choice choice; + DitherTest dt; + + static LayoutManager dcLayout = new FlowLayout(FlowLayout.CENTER, 10, 5); + + public DitherControls(DitherTest app, int s, int e, int type, + boolean vertical) { + dt = app; + setLayout(dcLayout); + add(new Label(vertical ? "Vertical" : "Horizontal")); + add(choice = new Choice()); + choice.addItem("Noop"); + choice.addItem("Red"); + choice.addItem("Green"); + choice.addItem("Blue"); + choice.addItem("Alpha"); + choice.addItem("Saturation"); + choice.select(type); + add(start = new TextField(Integer.toString(s), 4)); + add(end = new TextField(Integer.toString(e), 4)); + } + + public void addRenderButton() { + add(button = new Button("New Image")); + button.addActionListener(this); + } + + public int getParams(int vals[]) { + vals[0] = Integer.parseInt(start.getText()); + vals[1] = Integer.parseInt(end.getText()); + return choice.getSelectedIndex(); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == button) { + dt.start(); + } + } +} From 1b46fea59cf8f53b23e5c16a604b4decc8c7dbbe Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 1 Oct 2024 07:15:42 +0000 Subject: [PATCH 073/188] 8341024: [test] build/AbsPathsInImage.java fails with OOM when using ubsan-enabled binaries Reviewed-by: erikj --- test/jdk/build/AbsPathsInImage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/build/AbsPathsInImage.java b/test/jdk/build/AbsPathsInImage.java index 712f990507d19..229094a0920e3 100644 --- a/test/jdk/build/AbsPathsInImage.java +++ b/test/jdk/build/AbsPathsInImage.java @@ -40,7 +40,7 @@ * @bug 8226346 * @summary Check all output files for absolute path fragments * @requires !vm.debug - * @run main AbsPathsInImage + * @run main/othervm -Xmx900m AbsPathsInImage */ public class AbsPathsInImage { From ad5ffccffa89359dac6ad44b9e43242e5bf3e398 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 1 Oct 2024 08:02:56 +0000 Subject: [PATCH 074/188] 8341168: Cleanup dead code after JDK-8322630 Reviewed-by: stefank, tschatzl, mli, shade --- src/hotspot/share/code/compiledIC.cpp | 2 +- .../share/compiler/compilerDefinitions.cpp | 5 ----- src/hotspot/share/runtime/globals.hpp | 3 --- src/hotspot/share/runtime/mutexLocker.cpp | 4 +--- src/hotspot/share/runtime/mutexLocker.hpp | 1 - src/hotspot/share/runtime/thread.cpp | 1 - src/hotspot/share/runtime/thread.hpp | 15 --------------- src/hotspot/share/runtime/vmOperation.hpp | 1 - src/hotspot/share/runtime/vmOperations.hpp | 6 ------ .../classes/sun/jvm/hotspot/code/StubQueue.java | 4 ++-- 10 files changed, 4 insertions(+), 38 deletions(-) diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index f142e306a6b02..684aee509ee53 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -293,7 +293,7 @@ bool CompiledIC::is_monomorphic() const { } bool CompiledIC::is_megamorphic() const { - return VtableStubs::entry_point(destination()) != nullptr;; + return VtableStubs::entry_point(destination()) != nullptr; } bool CompiledIC::is_speculated_klass(Klass* receiver_klass) { diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index ee0c73254f180..7b091d8ade50c 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -497,11 +497,6 @@ bool CompilerConfig::check_args_consistency(bool status) { "Invalid NonNMethodCodeHeapSize=%dK. Must be at least %uK.\n", NonNMethodCodeHeapSize/K, min_code_cache_size/K); status = false; - } else if (InlineCacheBufferSize > NonNMethodCodeHeapSize / 2) { - jio_fprintf(defaultStream::error_stream(), - "Invalid InlineCacheBufferSize=" SIZE_FORMAT "K. Must be less than or equal to " SIZE_FORMAT "K.\n", - InlineCacheBufferSize/K, NonNMethodCodeHeapSize/2/K); - status = false; } #ifdef _LP64 diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 8dafc9a508d99..2bcc26043cd96 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -289,9 +289,6 @@ const int ObjectAlignmentInBytes = 8; product(bool, UseInlineCaches, true, \ "Use Inline Caches for virtual calls ") \ \ - product(size_t, InlineCacheBufferSize, 10*K, EXPERIMENTAL, \ - "InlineCacheBuffer size") \ - \ product(bool, InlineArrayCopy, true, DIAGNOSTIC, \ "Inline arraycopy native that is known to be part of " \ "base library DLL") \ diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index f033f42624987..a0ba783c36408 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -45,7 +45,6 @@ Mutex* SharedDictionary_lock = nullptr; Monitor* ClassInitError_lock = nullptr; Mutex* Module_lock = nullptr; Mutex* CompiledIC_lock = nullptr; -Mutex* InlineCacheBuffer_lock = nullptr; Mutex* VMStatistic_lock = nullptr; Mutex* JmethodIdCreation_lock = nullptr; Mutex* JfieldIdCreation_lock = nullptr; @@ -262,7 +261,7 @@ void mutex_init() { MUTEX_DEFN(JfieldIdCreation_lock , PaddedMutex , safepoint); - MUTEX_DEFN(CompiledIC_lock , PaddedMutex , nosafepoint); // locks VtableStubs_lock, InlineCacheBuffer_lock + MUTEX_DEFN(CompiledIC_lock , PaddedMutex , nosafepoint); // locks VtableStubs_lock MUTEX_DEFN(MethodCompileQueue_lock , PaddedMonitor, safepoint); MUTEX_DEFN(CompileStatistics_lock , PaddedMutex , safepoint); MUTEX_DEFN(DirectivesStack_lock , PaddedMutex , nosafepoint); @@ -319,7 +318,6 @@ void mutex_init() { #endif // These locks have relative rankings, and inherit safepoint checking attributes from that rank. - MUTEX_DEFL(InlineCacheBuffer_lock , PaddedMutex , CompiledIC_lock); MUTEX_DEFL(VtableStubs_lock , PaddedMutex , CompiledIC_lock); // Also holds DumpTimeTable_lock MUTEX_DEFL(CodeCache_lock , PaddedMonitor, VtableStubs_lock); MUTEX_DEFL(NMethodState_lock , PaddedMutex , CodeCache_lock); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 160e6c97db07f..3da859585019b 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -40,7 +40,6 @@ extern Mutex* SharedDictionary_lock; // a lock on the CDS shared dic extern Monitor* ClassInitError_lock; // a lock on the class initialization error table extern Mutex* Module_lock; // a lock on module and package related data structures extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access -extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the InlineCacheBuffer extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 5b871248c590b..df6a660a0aa21 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -83,7 +83,6 @@ Thread::Thread(MemTag mem_tag) { set_handle_area(new (mem_tag) HandleArea(mem_tag, nullptr)); set_metadata_handles(new (mtClass) GrowableArray(30, mtClass)); set_last_handle_mark(nullptr); - DEBUG_ONLY(_missed_ic_stub_refill_verifier = nullptr); // Initial value of zero ==> never claimed. _threads_do_token = 0; diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index d059a14a0f96d..45c39eae151d2 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -46,7 +46,6 @@ class CompilerThread; class HandleArea; class HandleMark; -class ICRefillVerifier; class JvmtiRawMonitor; class NMethodClosure; class Metadata; @@ -242,20 +241,6 @@ class Thread: public ThreadShadow { public: void set_last_handle_mark(HandleMark* mark) { _last_handle_mark = mark; } HandleMark* last_handle_mark() const { return _last_handle_mark; } - private: - -#ifdef ASSERT - ICRefillVerifier* _missed_ic_stub_refill_verifier; - - public: - ICRefillVerifier* missed_ic_stub_refill_verifier() { - return _missed_ic_stub_refill_verifier; - } - - void set_missed_ic_stub_refill_verifier(ICRefillVerifier* verifier) { - _missed_ic_stub_refill_verifier = verifier; - } -#endif // ASSERT private: // Used by SkipGCALot class. diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index 532a9231b70e8..eede52f00d566 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -109,7 +109,6 @@ template(PrintCompileQueue) \ template(PrintClassHierarchy) \ template(PrintClasses) \ - template(ICBufferFull) \ template(PrintMetadata) \ template(GTestExecuteAtSafepoint) \ template(GTestStopSafepoint) \ diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index 5ccf689eaf3d9..ea7f62df37db8 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -60,12 +60,6 @@ class VM_ForceSafepoint: public VM_EmptyOperation { VMOp_Type type() const { return VMOp_ForceSafepoint; } }; -// empty vm op, when forcing a safepoint due to inline cache buffers being full -class VM_ICBufferFull: public VM_EmptyOperation { - public: - VMOp_Type type() const { return VMOp_ICBufferFull; } -}; - class VM_ClearICs: public VM_Operation { private: bool _preserve_static_stubs; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/StubQueue.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/StubQueue.java index d59971b33ecf0..8d06a257e626d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/StubQueue.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/StubQueue.java @@ -52,8 +52,8 @@ public class StubQueue extends VMObject { private static CIntegerField queueEndField; private static CIntegerField numberOfStubsField; - // The type of the contained stubs (i.e., InterpreterCodelet, - // ICStub). Must be a subclass of type Stub. + // The type of the contained stubs (i.e., InterpreterCodelet). + // Must be a subclass of type Stub. private Class stubType; static { From 2dc3b1a71ffe71bc08ec967bb6b24ccf803037f3 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Tue, 1 Oct 2024 10:27:07 +0000 Subject: [PATCH 075/188] 8341201: Broken link in AbstractAnnotationValueVisitor7 due to extra quotation mark Reviewed-by: iris, darcy --- .../javax/lang/model/util/AbstractAnnotationValueVisitor7.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor7.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor7.java index 0ca2bb1376621..dbdeb3a950644 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor7.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitor7.java @@ -37,7 +37,7 @@ * @param the return type of this visitor's methods * @param

      the type of the additional parameter to this visitor's methods. * - * @see AbstractAnnotationValueVisitor6##note_for_subclasses" + * @see AbstractAnnotationValueVisitor6##note_for_subclasses * Compatibility note for subclasses * @see AbstractAnnotationValueVisitor6 * @see AbstractAnnotationValueVisitor8 From f7c7958f001b3242eb485efd25bbcf9e1be75d85 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Tue, 1 Oct 2024 11:33:11 +0000 Subject: [PATCH 076/188] 8340420: ZGC: Should call `vm_shutdown_during_initialization` if initialization fails Reviewed-by: stefank, mli --- .../bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp | 4 +- .../gc/z/zPhysicalMemoryBacking_linux.cpp | 30 ++++----- src/hotspot/share/gc/z/zCollectedHeap.cpp | 6 +- src/hotspot/share/gc/z/zCollectedHeap.hpp | 2 +- src/hotspot/share/gc/z/zHeap.cpp | 3 +- src/hotspot/share/gc/z/zInitialize.cpp | 61 ++++++++++++++++++- src/hotspot/share/gc/z/zInitialize.hpp | 31 ++++++++-- .../share/gc/z/zMarkStackAllocator.cpp | 4 +- src/hotspot/share/gc/z/zVirtualMemory.cpp | 3 +- 9 files changed, 117 insertions(+), 27 deletions(-) diff --git a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp index 29825a9eab291..2e56c092a79b5 100644 --- a/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp +++ b/src/hotspot/os/bsd/gc/z/zPhysicalMemoryBacking_bsd.cpp @@ -22,10 +22,10 @@ */ #include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" #include "gc/z/zAddress.inline.hpp" #include "gc/z/zErrno.hpp" #include "gc/z/zGlobals.hpp" +#include "gc/z/zInitialize.hpp" #include "gc/z/zLargePages.inline.hpp" #include "gc/z/zPhysicalMemory.inline.hpp" #include "gc/z/zPhysicalMemoryBacking_bsd.hpp" @@ -82,7 +82,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) _base = (uintptr_t)os::reserve_memory(max_capacity); if (_base == 0) { // Failed - log_error_pd(gc)("Failed to reserve address space for backing memory"); + ZInitialize::error("Failed to reserve address space for backing memory"); return; } diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index f967fee930579..b648876ac602c 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -27,6 +27,7 @@ #include "gc/z/zArray.inline.hpp" #include "gc/z/zErrno.hpp" #include "gc/z/zGlobals.hpp" +#include "gc/z/zInitialize.hpp" #include "gc/z/zLargePages.inline.hpp" #include "gc/z/zMountPoint_linux.hpp" #include "gc/z/zNUMA.inline.hpp" @@ -129,6 +130,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) // Create backing file _fd = create_fd(ZFILENAME_HEAP); if (_fd == -1) { + ZInitialize::error("Failed to create heap backing file"); return; } @@ -136,7 +138,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) while (ftruncate(_fd, max_capacity) == -1) { if (errno != EINTR) { ZErrno err; - log_error_p(gc)("Failed to truncate backing file (%s)", err.to_string()); + ZInitialize::error("Failed to truncate backing file (%s)", err.to_string()); return; } } @@ -145,7 +147,7 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) struct statfs buf; if (fstatfs(_fd, &buf) == -1) { ZErrno err; - log_error_p(gc)("Failed to determine filesystem type for backing file (%s)", err.to_string()); + ZInitialize::error("Failed to determine filesystem type for backing file (%s)", err.to_string()); return; } @@ -158,39 +160,39 @@ ZPhysicalMemoryBacking::ZPhysicalMemoryBacking(size_t max_capacity) // Make sure the filesystem type matches requested large page type if (ZLargePages::is_transparent() && !is_tmpfs()) { - log_error_p(gc)("-XX:+UseTransparentHugePages can only be enabled when using a %s filesystem", - ZFILESYSTEM_TMPFS); + ZInitialize::error("-XX:+UseTransparentHugePages can only be enabled when using a %s filesystem", + ZFILESYSTEM_TMPFS); return; } if (ZLargePages::is_transparent() && !tmpfs_supports_transparent_huge_pages()) { - log_error_p(gc)("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel", - ZFILESYSTEM_TMPFS); + ZInitialize::error("-XX:+UseTransparentHugePages on a %s filesystem not supported by kernel", + ZFILESYSTEM_TMPFS); return; } if (ZLargePages::is_explicit() && !is_hugetlbfs()) { - log_error_p(gc)("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled " - "when using a %s filesystem", ZFILESYSTEM_HUGETLBFS); + ZInitialize::error("-XX:+UseLargePages (without -XX:+UseTransparentHugePages) can only be enabled " + "when using a %s filesystem", ZFILESYSTEM_HUGETLBFS); return; } if (!ZLargePages::is_explicit() && is_hugetlbfs()) { - log_error_p(gc)("-XX:+UseLargePages must be enabled when using a %s filesystem", - ZFILESYSTEM_HUGETLBFS); + ZInitialize::error("-XX:+UseLargePages must be enabled when using a %s filesystem", + ZFILESYSTEM_HUGETLBFS); return; } // Make sure the filesystem block size is compatible if (ZGranuleSize % _block_size != 0) { - log_error_p(gc)("Filesystem backing the heap has incompatible block size (" SIZE_FORMAT ")", - _block_size); + ZInitialize::error("Filesystem backing the heap has incompatible block size (" SIZE_FORMAT ")", + _block_size); return; } if (is_hugetlbfs() && _block_size != ZGranuleSize) { - log_error_p(gc)("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")", - ZFILESYSTEM_HUGETLBFS, _block_size, ZGranuleSize); + ZInitialize::error("%s filesystem has unexpected block size " SIZE_FORMAT " (expected " SIZE_FORMAT ")", + ZFILESYSTEM_HUGETLBFS, _block_size, ZGranuleSize); return; } diff --git a/src/hotspot/share/gc/z/zCollectedHeap.cpp b/src/hotspot/share/gc/z/zCollectedHeap.cpp index ccfa7af6b7d72..8afefd5a7cc1c 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.cpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp @@ -49,6 +49,7 @@ #include "memory/universe.hpp" #include "oops/stackChunkOop.hpp" #include "runtime/continuationJavaClasses.hpp" +#include "runtime/java.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/stackWatermarkSet.hpp" #include "services/memoryUsage.hpp" @@ -60,7 +61,7 @@ ZCollectedHeap* ZCollectedHeap::heap() { ZCollectedHeap::ZCollectedHeap() : _barrier_set(), - _initialize(&_barrier_set), + _initializer(&_barrier_set), _heap(), _driver_minor(new ZDriverMinor()), _driver_major(new ZDriverMajor()), @@ -78,11 +79,14 @@ const char* ZCollectedHeap::name() const { jint ZCollectedHeap::initialize() { if (!_heap.is_initialized()) { + vm_shutdown_during_initialization(ZInitialize::error_message()); return JNI_ENOMEM; } Universe::set_verify_data(~(ZAddressHeapBase - 1) | 0x7, ZAddressHeapBase); + ZInitialize::finish(); + return JNI_OK; } diff --git a/src/hotspot/share/gc/z/zCollectedHeap.hpp b/src/hotspot/share/gc/z/zCollectedHeap.hpp index 528bacd8df82b..434204e16b80d 100644 --- a/src/hotspot/share/gc/z/zCollectedHeap.hpp +++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp @@ -43,7 +43,7 @@ class ZCollectedHeap : public CollectedHeap { private: ZBarrierSet _barrier_set; - ZInitialize _initialize; + ZInitializer _initializer; ZHeap _heap; ZDriverMinor* _driver_minor; ZDriverMajor* _driver_major; diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index dc5f1e3d21d57..40aa76867f424 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -34,6 +34,7 @@ #include "gc/z/zHeap.inline.hpp" #include "gc/z/zHeapIterator.hpp" #include "gc/z/zHeuristics.hpp" +#include "gc/z/zInitialize.hpp" #include "gc/z/zPage.inline.hpp" #include "gc/z/zPageTable.inline.hpp" #include "gc/z/zResurrection.hpp" @@ -74,7 +75,7 @@ ZHeap::ZHeap() // Prime cache if (!_page_allocator.prime_cache(_old.workers(), InitialHeapSize)) { - log_error_p(gc)("Failed to allocate initial Java heap (" SIZE_FORMAT "M)", InitialHeapSize / M); + ZInitialize::error("Failed to allocate initial Java heap (" SIZE_FORMAT "M)", InitialHeapSize / M); return; } diff --git a/src/hotspot/share/gc/z/zInitialize.cpp b/src/hotspot/share/gc/z/zInitialize.cpp index 52229bf283097..e37fc550bfe2a 100644 --- a/src/hotspot/share/gc/z/zInitialize.cpp +++ b/src/hotspot/share/gc/z/zInitialize.cpp @@ -22,6 +22,7 @@ */ #include "precompiled.hpp" +#include "gc/shared/gcLogPrecious.hpp" #include "gc/z/zAddress.hpp" #include "gc/z/zBarrierSet.hpp" #include "gc/z/zCPU.hpp" @@ -38,9 +39,19 @@ #include "gc/z/zThreadLocalAllocBuffer.hpp" #include "gc/z/zTracer.hpp" #include "logging/log.hpp" +#include "nmt/memTag.hpp" #include "runtime/vm_version.hpp" +#include "utilities/formatBuffer.hpp" -ZInitialize::ZInitialize(ZBarrierSet* barrier_set) { +char ZInitialize::_error_message[ErrorMessageLength] = {}; +bool ZInitialize::_had_error = false; +bool ZInitialize::_finished = false; + +ZInitializer::ZInitializer(ZBarrierSet* barrier_set) { + ZInitialize::initialize(barrier_set); +} + +void ZInitialize::initialize(ZBarrierSet* barrier_set) { log_info(gc, init)("Initializing %s", ZName); log_info(gc, init)("Version: %s (%s)", VM_Version::vm_release(), @@ -62,3 +73,51 @@ ZInitialize::ZInitialize(ZBarrierSet* barrier_set) { pd_initialize(); } + +void ZInitialize::register_error(bool debug, const char *error_msg) { + guarantee(!_finished, "Only register errors during initialization"); + + if (!_had_error) { + strncpy(_error_message, error_msg, ErrorMessageLength - 1); + _had_error = true; + } + + if (debug) { + log_error_pd(gc)("%s", error_msg); + } else { + log_error_p(gc)("%s", error_msg); + } +} + +void ZInitialize::error(const char* msg_format, ...) { + va_list argp; + va_start(argp, msg_format); + const FormatBuffer error_msg(FormatBufferDummy(), msg_format, argp); + va_end(argp); + register_error(false /* debug */, error_msg); +} + +void ZInitialize::error_d(const char* msg_format, ...) { + va_list argp; + va_start(argp, msg_format); + const FormatBuffer error_msg(FormatBufferDummy(), msg_format, argp); + va_end(argp); + register_error(true /* debug */, error_msg); +} + +bool ZInitialize::had_error() { + return _had_error; +} + +const char* ZInitialize::error_message() { + assert(had_error(), "Should have registered an error"); + if (had_error()) { + return _error_message; + } + return "Unknown error, check error GC logs"; +} + +void ZInitialize::finish() { + guarantee(!_finished, "Only finish initialization once"); + _finished = true; +} diff --git a/src/hotspot/share/gc/z/zInitialize.hpp b/src/hotspot/share/gc/z/zInitialize.hpp index 599b656623448..3c551b4c62260 100644 --- a/src/hotspot/share/gc/z/zInitialize.hpp +++ b/src/hotspot/share/gc/z/zInitialize.hpp @@ -24,16 +24,39 @@ #ifndef SHARE_GC_Z_ZINITIALIZE_HPP #define SHARE_GC_Z_ZINITIALIZE_HPP -#include "memory/allocation.hpp" +#include "memory/allStatic.hpp" +#include "utilities/compilerWarnings.hpp" + +#include class ZBarrierSet; -class ZInitialize { +class ZInitializer { +public: + ZInitializer(ZBarrierSet* barrier_set); +}; + +class ZInitialize : public AllStatic { private: - void pd_initialize(); + static constexpr size_t ErrorMessageLength = 256; + + static char _error_message[ErrorMessageLength]; + static bool _had_error; + static bool _finished; + + static void register_error(bool debug, const char *error_msg); + + static void pd_initialize(); public: - ZInitialize(ZBarrierSet* barrier_set); + static void error(const char* msg_format, ...) ATTRIBUTE_PRINTF(1, 2); + static void error_d(const char* msg_format, ...) ATTRIBUTE_PRINTF(1, 2); + + static bool had_error(); + static const char* error_message(); + + static void initialize(ZBarrierSet* barrier_set); + static void finish(); }; #endif // SHARE_GC_Z_ZINITIALIZE_HPP diff --git a/src/hotspot/share/gc/z/zMarkStackAllocator.cpp b/src/hotspot/share/gc/z/zMarkStackAllocator.cpp index a9e404a0f55c1..100036dc3fe53 100644 --- a/src/hotspot/share/gc/z/zMarkStackAllocator.cpp +++ b/src/hotspot/share/gc/z/zMarkStackAllocator.cpp @@ -22,8 +22,8 @@ */ #include "precompiled.hpp" -#include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/gc_globals.hpp" +#include "gc/z/zInitialize.hpp" #include "gc/z/zLock.inline.hpp" #include "gc/z/zMarkStack.inline.hpp" #include "gc/z/zMarkStackAllocator.hpp" @@ -43,7 +43,7 @@ ZMarkStackSpace::ZMarkStackSpace() const size_t size = ZMarkStackSpaceLimit; const uintptr_t addr = (uintptr_t)os::reserve_memory(size, !ExecMem, mtGC); if (addr == 0) { - log_error_pd(gc, marking)("Failed to reserve address space for mark stacks"); + ZInitialize::error_d("Failed to reserve address space for mark stacks"); return; } diff --git a/src/hotspot/share/gc/z/zVirtualMemory.cpp b/src/hotspot/share/gc/z/zVirtualMemory.cpp index 6b53b2ba7c82b..2160aa3894802 100644 --- a/src/hotspot/share/gc/z/zVirtualMemory.cpp +++ b/src/hotspot/share/gc/z/zVirtualMemory.cpp @@ -27,6 +27,7 @@ #include "gc/z/zAddress.inline.hpp" #include "gc/z/zAddressSpaceLimit.hpp" #include "gc/z/zGlobals.hpp" +#include "gc/z/zInitialize.hpp" #include "gc/z/zNMT.hpp" #include "gc/z/zVirtualMemory.inline.hpp" #include "utilities/align.hpp" @@ -44,7 +45,7 @@ ZVirtualMemoryManager::ZVirtualMemoryManager(size_t max_capacity) // Reserve address space if (!reserve(max_capacity)) { - log_error_pd(gc)("Failed to reserve enough address space for Java heap"); + ZInitialize::error_d("Failed to reserve enough address space for Java heap"); return; } From 7cc7c080b5dbab61914512bf63227944697c0cbe Mon Sep 17 00:00:00 2001 From: Raphael Mosaner Date: Tue, 1 Oct 2024 11:46:13 +0000 Subject: [PATCH 077/188] 8337493: [JVMCI] Number of libgraal threads might be too low Reviewed-by: dnsimon --- src/hotspot/share/jvmci/jvmci_globals.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/jvmci/jvmci_globals.hpp b/src/hotspot/share/jvmci/jvmci_globals.hpp index d6f9ddd6739d4..4da49b24e6ef9 100644 --- a/src/hotspot/share/jvmci/jvmci_globals.hpp +++ b/src/hotspot/share/jvmci/jvmci_globals.hpp @@ -143,9 +143,11 @@ class fileStream; "on the HotSpot heap. Defaults to true if UseJVMCICompiler or " \ "EnableJVMCI is true and a JVMCI native library is available.") \ \ - product(double, JVMCINativeLibraryThreadFraction, 0.33, EXPERIMENTAL, \ + product(double, JVMCINativeLibraryThreadFraction, 0.66, EXPERIMENTAL, \ "The fraction of compiler threads used by libjvmci. " \ - "The remaining compiler threads are used by C1.") \ + "The remaining compiler threads are used by C1. " \ + "Reducing this value could reduce the max RSS but " \ + "also increase the warmup time.") \ range(0.0, 1.0) \ \ product(ccstr, JVMCINativeLibraryErrorFile, nullptr, EXPERIMENTAL, \ From 684d246ccf497f599ffcd498f2fbe4b1b2357e27 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 1 Oct 2024 13:29:56 +0000 Subject: [PATCH 078/188] 8341242: Shenandoah: LRB node is not matched as GC barrier after JDK-8340183 Reviewed-by: rkennke, phh --- src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 10b80b6802942..7ac9dcc2e8134 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -682,7 +682,8 @@ bool ShenandoahBarrierSetC2::is_gc_pre_barrier_node(Node* node) const { } bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const { - return is_shenandoah_lrb_call(node) || + return (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) || + is_shenandoah_lrb_call(node) || is_shenandoah_wb_pre_call(node) || is_shenandoah_clone_call(node); } From 2120a8414ef9c34d5875d33ac9a16594908fe403 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Tue, 1 Oct 2024 13:59:36 +0000 Subject: [PATCH 079/188] 8341333: [JVMCI] Export JavaThread::_unlocked_inflated_monitor to JVMCI Reviewed-by: dnsimon --- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index df77e8a2882ee..13b208932199a 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -246,6 +246,7 @@ nonstatic_field(JavaThread, _lock_stack, LockStack) \ 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)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_tmp_VTMS_transition, bool)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \ From 7b1e6f8ed9dbc07158717a32d341393afaa54b66 Mon Sep 17 00:00:00 2001 From: "joseph.jackson" Date: Tue, 1 Oct 2024 14:00:39 +0000 Subject: [PATCH 080/188] 8337389: Parallel: Remove unnecessary forward declarations in psScavenge.hpp Reviewed-by: kbarrett, tschatzl --- src/hotspot/share/gc/parallel/psScavenge.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psScavenge.hpp b/src/hotspot/share/gc/parallel/psScavenge.hpp index 99d0487760b15..55abdfd3cf38e 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp @@ -34,9 +34,7 @@ #include "oops/oop.hpp" #include "utilities/stack.hpp" -class ReferenceProcessor; class ParallelScavengeHeap; -class ParallelScavengeTracer; class PSIsAliveClosure; class STWGCTimer; From f2a767f59b1f66966665bc8601273b532961395a Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Tue, 1 Oct 2024 14:28:22 +0000 Subject: [PATCH 081/188] 8340907: Open source closed frame tests # 2 Reviewed-by: prr, honkar --- test/jdk/ProblemList.txt | 1 + .../jdk/java/awt/Frame/DeiconifyClipTest.java | 140 ++++++++++++++++++ .../java/awt/Frame/FrameSetCursorTest.java | 100 +++++++++++++ .../java/awt/Frame/InitialIconifiedTest.java | 98 ++++++++++++ .../java/awt/Frame/InsetCorrectionTest.java | 102 +++++++++++++ 5 files changed, 441 insertions(+) create mode 100644 test/jdk/java/awt/Frame/DeiconifyClipTest.java create mode 100644 test/jdk/java/awt/Frame/FrameSetCursorTest.java create mode 100644 test/jdk/java/awt/Frame/InitialIconifiedTest.java create mode 100644 test/jdk/java/awt/Frame/InsetCorrectionTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index f02272977aa17..ef9b82d596728 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -121,6 +121,7 @@ java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusToFrontTest.java 6848406 gen java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java 6848407 generic-all java/awt/Frame/MaximizedUndecorated/MaximizedUndecorated.java 8022302 generic-all java/awt/Frame/RestoreToOppositeScreen/RestoreToOppositeScreen.java 8286840 linux-all +java/awt/Frame/InitialIconifiedTest.java 8203920 macosx-all,linux-all java/awt/FileDialog/FileDialogIconTest/FileDialogIconTest.java 8160558 windows-all java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java 8060176 windows-all,macosx-all java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java 8060176 windows-all,macosx-all diff --git a/test/jdk/java/awt/Frame/DeiconifyClipTest.java b/test/jdk/java/awt/Frame/DeiconifyClipTest.java new file mode 100644 index 0000000000000..c650355f3ec73 --- /dev/null +++ b/test/jdk/java/awt/Frame/DeiconifyClipTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * DeiconifyClipTest.java + * + * summary: + * + * What happens is that we call AwtWindow::UpdateInsets when + * processing WM_NCCALCSIZE delivered on programmatic deiconification. + * At this point IsIconic returns false (so UpdateInsets proceeds), + * but the rect sizes still seems to be those weird of the iconic + * state. Based on them we compute insets with top = left = 0 (and + * bottom and right that are completely bogus) and pass them to + * PaintUpdateRgn which results in incorrect clip origin. Immediately + * after that we do UpdateInsets again during WM_SIZE processing and + * get real values. + */ + +import javax.swing.BoxLayout; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; + +/* + * @test + * @bug 4792958 + * @summary Incorrect clip region after programmatic restore + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DeiconifyClipTest +*/ + +public class DeiconifyClipTest { + private static final String INSTRUCTIONS = """ + This test creates a frame that is automatically iconified/deiconified + in a cycle. + + The test FAILS if after deiconfication the frame has a greyed-out area + in the lower-right corner. + If the frame contents is drawn completely - the test PASSES. + + Press PASS or FAIL button accordingly. + """; + + static TestFrame testFrame; + static volatile boolean shouldContinue = true; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("DeiconifyClipTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(DeiconifyClipTest::createAndShowUI) + .build(); + try { + runThread(); + } finally { + passFailJFrame.awaitAndCheck(); + shouldContinue = false; + } + } + + private static void runThread() { + new Thread(() -> { + for (int i = 0; i < 1000 && shouldContinue; ++i) { + try { + Thread.sleep(3000); + SwingUtilities.invokeAndWait(() -> { + if ((testFrame.getExtendedState() & Frame.ICONIFIED) + != 0) { + testFrame.setExtendedState(Frame.NORMAL); + } else { + testFrame.setState(Frame.ICONIFIED); + } + }); + } catch (Exception ignored) { + } + } + }).start(); + } + + static Frame createAndShowUI() { + testFrame = new TestFrame(); + testFrame.getContentPane().setLayout(new BoxLayout(testFrame.getContentPane(), + BoxLayout.Y_AXIS)); + testFrame.getContentPane().setBackground(Color.yellow); + testFrame.setSize(300, 300); + return testFrame; + } + + static class TestFrame extends JFrame { + public TestFrame() { + super("DeiconifyClipTest"); + } + + // make it more visible if the clip is wrong. + public void paint(Graphics g) { + Insets b = getInsets(); + Dimension d = getSize(); + + int x = b.left; + int y = b.top; + int w = d.width - x - b.right; + int h = d.height - y - b.bottom; + + g.setColor(Color.white); + g.fillRect(0, 0, d.width, d.height); + + g.setColor(Color.green); + g.drawRect(x, y, w-1, h-1); + g.drawLine(x, y, x+w, y+h); + g.drawLine(x, y+h, x+w, y); + } + } +} diff --git a/test/jdk/java/awt/Frame/FrameSetCursorTest.java b/test/jdk/java/awt/Frame/FrameSetCursorTest.java new file mode 100644 index 0000000000000..98968a8fbab82 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameSetCursorTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.event.ActionListener; +import java.lang.Exception; +import java.lang.InterruptedException; +import java.lang.Object; +import java.lang.String; +import java.lang.Thread; + +/* + * @test + * @bug 4097226 + * @summary Frame.setCursor() sometimes doesn't update the cursor until user moves the mouse + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameSetCursorTest + */ + +public class FrameSetCursorTest { + private static final String INSTRUCTIONS = """ + 1. Keep the instruction dialog and TestFrame side by side so that + you can read the instructions while doing the test + 2. Click on the 'Start Busy' button on the frame titled 'TestFrame' + and DO NOT MOVE THE MOUSE ANYWHERE till you complete the steps below + 3. The cursor on the TestFrame changes to busy cursor + 4. If you don't see the busy cursor press 'Fail' after + the `done sleeping` message + 5. If the busy cursor is seen, after 5 seconds the message + 'done sleeping' is displayed in the message window + 6. Check for the cursor type after the display of 'done sleeping' + 7. If the cursor on the TestFrame has changed back to default cursor + (without you touching or moving the mouse), then press 'Pass' + else if the frame still shows the busy cursor press 'Fail' + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FrameSetCursorTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(FrameSetCursorTest::createAndShowUI) + .logArea(5) + .build() + .awaitAndCheck(); + + } + + static Frame createAndShowUI() { + Frame frame = new Frame("TestFrame"); + Panel panel = new Panel(); + Button busyButton = new Button("Start Busy"); + + ActionListener actionListener = event -> { + Object source = event.getSource(); + if (source == busyButton) { + frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + try { + Thread.sleep(5000); + } catch (InterruptedException ignored) {} + PassFailJFrame.log("done sleeping"); + frame.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + }; + + busyButton.addActionListener(actionListener); + panel.setLayout(new BorderLayout()); + panel.add("North", busyButton); + + frame.add(panel); + frame.pack(); + frame.setSize(200, 200); + return frame; + } +} \ No newline at end of file diff --git a/test/jdk/java/awt/Frame/InitialIconifiedTest.java b/test/jdk/java/awt/Frame/InitialIconifiedTest.java new file mode 100644 index 0000000000000..f3f43929e7b16 --- /dev/null +++ b/test/jdk/java/awt/Frame/InitialIconifiedTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.imageio.ImageIO; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +/* + * @test + * @key headful + * @bug 4851435 + * @summary Frame is not shown initially iconified after pack + */ + +public class InitialIconifiedTest { + + private static Frame backgroundFrame; + private static Frame testedFrame; + + private static final Rectangle backgroundFrameBounds = + new Rectangle(100, 100, 200, 200); + private static final Rectangle testedFrameBounds = + new Rectangle(150, 150, 100, 100); + + private static Robot robot; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + + try { + EventQueue.invokeAndWait(InitialIconifiedTest::initAndShowGui); + robot.waitForIdle(); + robot.delay(500); + test(); + } finally { + EventQueue.invokeAndWait(() -> { + backgroundFrame.dispose(); + testedFrame.dispose(); + }); + } + } + + private static void initAndShowGui() { + backgroundFrame = new Frame("DisposeTest background"); + backgroundFrame.setUndecorated(true); + backgroundFrame.setBackground(Color.RED); + backgroundFrame.setBounds(backgroundFrameBounds); + backgroundFrame.setVisible(true); + + testedFrame = new Frame("Should have started ICONIC"); + testedFrame.setExtendedState(Frame.ICONIFIED); + testedFrame.setBounds(testedFrameBounds); + testedFrame.setVisible(true); + } + + private static void test() { + BufferedImage bi = robot.createScreenCapture(backgroundFrameBounds); + int redPix = Color.RED.getRGB(); + + for (int x = 0; x < bi.getWidth(); x++) { + for (int y = 0; y < bi.getHeight(); y++) { + if (bi.getRGB(x, y) != redPix) { + try { + ImageIO.write(bi, "png", + new File("failure.png")); + } catch (IOException ignored) {} + throw new RuntimeException("Test failed"); + } + } + } + } +} diff --git a/test/jdk/java/awt/Frame/InsetCorrectionTest.java b/test/jdk/java/awt/Frame/InsetCorrectionTest.java new file mode 100644 index 0000000000000..1ea6f03b24b15 --- /dev/null +++ b/test/jdk/java/awt/Frame/InsetCorrectionTest.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4091426 + * @key headful + * @summary Test inset correction when setVisible(true) BEFORE setSize(), setLocation() + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual InsetCorrectionTest + */ + +public class InsetCorrectionTest { + private static final String INSTRUCTIONS = """ + There is a frame of size 300x300 at location (100,100). + It has a menubar with one menu, 'File', but the frame + is otherwise empty. In particular, there should be no + part of the frame that is not shown in the background color. + Upon test completion, click Pass or Fail appropriately. + """; + + private static InsetCorrection testFrame; + + public static void main(String[] args) throws Exception { + EventQueue.invokeAndWait(() -> testFrame = new InsetCorrection()); + + try { + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("InsetCorrectionTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .logArea(3) + .build(); + EventQueue.invokeAndWait(() -> + PassFailJFrame.log("frame location: " + testFrame.getBounds())); + passFailJFrame.awaitAndCheck(); + } finally { + EventQueue.invokeAndWait(testFrame::dispose); + } + } + + static class InsetCorrection extends Frame + implements ActionListener { + MenuBar mb; + Menu file; + MenuItem cause_bug_b; + + public InsetCorrection() { + super("InsetCorrection"); + mb = new MenuBar(); + file = new Menu("File"); + mb.add(file); + cause_bug_b = new MenuItem("cause bug"); + file.add(cause_bug_b); + setMenuBar(mb); + cause_bug_b.addActionListener(this); + + // Making the frame visible before setSize and setLocation() + // are being called causes sometimes strange behaviour with + // JDK1.1.5G. The frame is then sometimes to large and the + // excess areas are drawn in black. This only happens + // sometimes. + setVisible(true); + setSize(300, 300); + setLocation(100, 100); + } + + public void actionPerformed(ActionEvent e) { + setVisible(false); + setVisible(true); + } + } +} From 9a7817b1376d055c5a7c1005b275cc1f198e5364 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Tue, 1 Oct 2024 16:02:02 +0000 Subject: [PATCH 082/188] 8340988: Update jdk/jfr/event/gc/collection tests to accept "CodeCache GC Threshold" as valid GC reason Reviewed-by: tschatzl --- .../event/gc/collection/TestGCCauseWithG1ConcurrentMark.java | 4 ++-- .../event/gc/collection/TestGCCauseWithG1FullCollection.java | 4 ++-- .../jfr/event/gc/collection/TestGCCauseWithParallelOld.java | 5 +++-- .../jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java | 5 +++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java index bd3a7f63a8a99..e0ea218a07f0b 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1ConcurrentMark.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ public static void main(String[] args) throws Exception { String[] vmFlags = {"-XX:+UseG1GC", "-XX:+ExplicitGCInvokesConcurrent"}; String[] gcNames = {GCHelper.gcG1New, GCHelper.gcG1Old, GCHelper.gcG1Full}; String[] gcCauses = {"Metadata GC Threshold", "G1 Evacuation Pause", "G1 Preventive Collection", - "G1 Compaction Pause", "System.gc()"}; + "G1 Compaction Pause", "CodeCache GC Threshold", "System.gc()"}; GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses); } } diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java index 072c3905baf59..308a544adeb17 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithG1FullCollection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ public static void main(String[] args) throws Exception { String[] vmFlags = {"-XX:+UseG1GC"}; String[] gcNames = {GCHelper.gcG1New, GCHelper.gcG1Old, GCHelper.gcG1Full}; String[] gcCauses = {"Metadata GC Threshold", "G1 Evacuation Pause", "G1 Preventive Collection", - "G1 Compaction Pause", "System.gc()"}; + "G1 Compaction Pause", "CodeCache GC Threshold", "System.gc()"}; GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses); } } diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java index 4d8f697d83719..16217c0cbe1b7 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithParallelOld.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,8 @@ public static void main(String[] args) throws Exception { String testID = "ParallelOld"; String[] vmFlags = {"-XX:+UseParallelGC"}; String[] gcNames = {GCHelper.gcParallelScavenge, GCHelper.gcParallelOld}; - String[] gcCauses = {"Allocation Failure", "System.gc()", "GCLocker Initiated GC"}; + String[] gcCauses = {"Allocation Failure", "System.gc()", "GCLocker Initiated GC", + "CodeCache GC Threshold"}; GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses); } } diff --git a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java index 403bd07758524..344c61043a2e1 100644 --- a/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java +++ b/test/jdk/jdk/jfr/event/gc/collection/TestGCCauseWithSerial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,8 @@ public static void main(String[] args) throws Exception { String testID = "Serial"; String[] vmFlags = {"-XX:+UseSerialGC"}; String[] gcNames = {GCHelper.gcDefNew, GCHelper.gcSerialOld}; - String[] gcCauses = {"Allocation Failure", "System.gc()", "GCLocker Initiated GC"}; + String[] gcCauses = {"Allocation Failure", "System.gc()", "GCLocker Initiated GC", + "CodeCache GC Threshold"}; GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses); } } From 021bf630351fd5369fac732b1099bc2bfe8b5e19 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Tue, 1 Oct 2024 18:27:25 +0000 Subject: [PATCH 083/188] 8340458: Open source additional Component tests (part 2) Reviewed-by: psadhukhan --- .../InitialBackgroundSettingTest.java | 132 ++++++++++++++++ .../FlickeringOnScroll.java | 139 ++++++++++++++++ .../FocusRepaintTest/FocusRepaintTest.java | 83 ++++++++++ .../ListDoubleIndentTest.java | 148 ++++++++++++++++++ 4 files changed, 502 insertions(+) create mode 100644 test/jdk/java/awt/Component/BackgroundColorTest/InitialBackgroundSettingTest.java create mode 100644 test/jdk/java/awt/Component/FlickeringOnScroll/FlickeringOnScroll.java create mode 100644 test/jdk/java/awt/Component/FocusRepaintTest/FocusRepaintTest.java create mode 100644 test/jdk/java/awt/Component/ListDoubleIndentTest/ListDoubleIndentTest.java diff --git a/test/jdk/java/awt/Component/BackgroundColorTest/InitialBackgroundSettingTest.java b/test/jdk/java/awt/Component/BackgroundColorTest/InitialBackgroundSettingTest.java new file mode 100644 index 0000000000000..3bed6f106c59a --- /dev/null +++ b/test/jdk/java/awt/Component/BackgroundColorTest/InitialBackgroundSettingTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4148334 + * @summary tests that background color is initially set correctly. + * @requires os.family == "windows" + * @key headful + * @run main InitialBackgroundSettingTest + */ +import java.awt.Button; +import java.awt.Choice; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.List; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Scrollbar; +import java.lang.reflect.InvocationTargetException; + +public class InitialBackgroundSettingTest { + Frame frame; + TextField tf; + TextArea ta; + Choice choice; + List list; + Scrollbar bar; + Button button; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + InitialBackgroundSettingTest test= new InitialBackgroundSettingTest(); + try { + EventQueue.invokeAndWait(test::setupGUI); + EventQueue.invokeAndWait(test::test); + } finally { + EventQueue.invokeAndWait(test::dispose); + } + } + + public void setupGUI () { + frame = new Frame("InitialBackgroundSettingTest frame"); + tf = new TextField("I am the TextField"); + ta = new TextArea("I am the TextArea"); + choice = new Choice(); + list = new List(); + bar = new Scrollbar(Scrollbar.HORIZONTAL); + button = new Button("I am the button"); + frame.setBackground(Color.red); + frame.setLayout(new GridLayout(7, 1)); + frame.add(button); + frame.add(bar); + frame.add(choice); + frame.add(list); + frame.add(tf); + frame.add(ta); + frame.setVisible(true); + frame.setBounds (400, 0, 300, 300); + } + + public void test() { + boolean passed = true; + System.out.println("Button background color is:" + + button.getBackground()); + if (Color.red.equals(button.getBackground())) { + System.err.println("Button background is red"); + passed = false; + } + System.out.println("Scrollbar background color is:" + + bar.getBackground()); + if (Color.red.equals(bar.getBackground())) { + System.err.println("ScrollBar background is red"); + passed = false; + } + System.out.println("Choice background color is:" + + choice.getBackground()); + if (Color.red.equals(choice.getBackground())) { + System.err.println("Choice background is red"); + passed = false; + } + System.out.println("List background color is:" + + list.getBackground()); + if (Color.red.equals(list.getBackground())) { + System.err.println("List background is red"); + passed = false; + } + System.out.println("TextField background color is:" + + tf.getBackground()); + if (Color.red.equals(tf.getBackground())) { + System.err.println("TextField background is red"); + passed = false; + } + System.out.println("TextArea background color is:" + + ta.getBackground()); + if (Color.red.equals(ta.getBackground())) { + System.err.println("TextArea background is red"); + passed = false; + } + + if (!passed) { + throw new RuntimeException("One or more component inherited" + + " background from a Frame"); + } + } + + public void dispose() { + frame.dispose(); + } +} diff --git a/test/jdk/java/awt/Component/FlickeringOnScroll/FlickeringOnScroll.java b/test/jdk/java/awt/Component/FlickeringOnScroll/FlickeringOnScroll.java new file mode 100644 index 0000000000000..2119ae7bcc01e --- /dev/null +++ b/test/jdk/java/awt/Component/FlickeringOnScroll/FlickeringOnScroll.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6347994 + * @summary REG: Scrollbar, Choice, Checkbox flickers and grays out when scrolling, XToolkit + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FlickeringOnScroll + */ + +import java.awt.BorderLayout; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; + +public class FlickeringOnScroll extends Frame { + + static final String INSTRUCTIONS = """ + There are five components in the frame: + Scrollbars(vertical and horizontal), a Choice, + a Checkbox and a TextArea + 1) Drag the thumbs of each Scrollbar. + 2) Do the same with Choice's scrollbar. + 3) Focus on Checkbox and press left mouse button or SPACE repeatedly. + 4) Right click inside TextArea and navigate through all menu items + in PopupMenu using the arrow keys. + If you notice some component or its scrollbar flickers on + key/mouse press or drag, press Fail. Otherwise press Pass. + """; + + public FlickeringOnScroll() { + Choice ch = new Choice(); + ch.add("Praveen"); + ch.add("Mohan"); + ch.add("Rakesh"); + ch.add("Menon"); + ch.add("Girish"); + ch.add("Ramachandran"); + ch.add("Elancheran"); + ch.add("Subramanian"); + ch.add("Raju"); + ch.add("Pallath"); + ch.add("Mayank"); + ch.add("Joshi"); + ch.add("Sundar"); + ch.add("Srinivas"); + ch.add("Mandalika"); + Checkbox chb = new Checkbox ("Checkbox", false); + TextArea ta = new TextArea("Text Area"); + Panel panel = new Panel(); + PopupMenu popup = new PopupMenu("Popup"); + MenuItem mi1 = new MenuItem("mi1"); + MenuItem mi2 = new MenuItem("mi2"); + MenuItem mi3 = new MenuItem("mi3"); + MenuItem mi4 = new MenuItem("mi4"); + + setTitle("Flickering Scroll Area Testing Frame"); + setLayout(new FlowLayout()); + add(ch); + add(chb); + add(ta); + + panel.setLayout(new BorderLayout()); + panel.setPreferredSize(new Dimension(200, 200)); + add(panel); + panel.add("Center",new java.awt.Label("Scrollbar flickering test..." ,java.awt.Label.CENTER)); + panel.add("South",new Scrollbar(Scrollbar.HORIZONTAL, 0, 100, 0, 255)); + panel.add("East",new Scrollbar(Scrollbar.VERTICAL, 0, 100, 0, 255)); + + ta.add(popup); + popup.add (mi1); + popup.add (mi2); + popup.add (mi3); + popup.add (mi4); + + ta.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent me) { + if (me.isPopupTrigger()) { + if (popup != null) { + popup.show(me.getComponent(), me.getX(), me.getY()); + } + } + } + public void mouseReleased(MouseEvent me) { + if (me.isPopupTrigger()) { + if (popup != null) { + popup.show(me.getComponent(), me.getX(), me.getY()); + } + } + } + }); + + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Scroll Area Flickering Repaint") + .testUI(FlickeringOnScroll::new) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Component/FocusRepaintTest/FocusRepaintTest.java b/test/jdk/java/awt/Component/FocusRepaintTest/FocusRepaintTest.java new file mode 100644 index 0000000000000..ecffdfda6135d --- /dev/null +++ b/test/jdk/java/awt/Component/FocusRepaintTest/FocusRepaintTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4079435 + * @summary Calling repaint() in focus handlers messes up the window. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FocusRepaintTest + */ + +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.lang.reflect.InvocationTargetException; + +public class FocusRepaintTest extends Frame implements FocusListener { + static final String INSTRUCTIONS = """ + Hit the tab key repeatedly in the Test window. + If any of the buttons disappear press Fail, otherwise press Pass. + """; + + public FocusRepaintTest() { + setTitle("Test"); + setLayout(new FlowLayout()); + setSize(200, 100); + Button b1 = new Button("Close"); + Button b2 = new Button("Button"); + add(b1); + add(b2); + b1.setSize(50, 30); + b2.setSize(50, 30); + b1.addFocusListener(this); + b2.addFocusListener(this); + } + + public void focusGained(FocusEvent e) { + Button b = (Button) e.getSource(); + PassFailJFrame.log("Focus gained for " + b.getLabel()); + b.repaint(); + } + + public void focusLost(FocusEvent e) { + Button b = (Button) e.getSource(); + PassFailJFrame.log("Focus lost for " + b.getLabel()); + b.repaint(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Focus Repaint") + .testUI(FocusRepaintTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Component/ListDoubleIndentTest/ListDoubleIndentTest.java b/test/jdk/java/awt/Component/ListDoubleIndentTest/ListDoubleIndentTest.java new file mode 100644 index 0000000000000..4c6c1248950e4 --- /dev/null +++ b/test/jdk/java/awt/Component/ListDoubleIndentTest/ListDoubleIndentTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4185460 + * @summary Container list the indentation is 2x the indent param value + * @key headful + * @run main ListDoubleIndentTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.EventQueue; +import java.awt.Frame; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PrintStream; +import java.io.PipedOutputStream; + +import java.lang.reflect.InvocationTargetException; +import java.util.Vector; + +public class ListDoubleIndentTest { + public static void main(final String[] args) throws InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(new ListDoubleIndentTest()::performTest); + } + + public void performTest() { + boolean bReturn = false; + int iCompCount = 0; + int iNotEqual = 0; + int iIndentWrong = 0; + System.out.println("Test: Check indentation"); + Vector v = new Vector(); + String sLine; + String sReturn; + String sExpTrim; + Button b1, b2, b3, b4, b5; + Frame f = null; + + try { + f = new Frame("ListDoubleIndentTest"); + + f.add(b1 = new Button("North"), BorderLayout.NORTH, 0); + f.add(b2 = new Button("South"), BorderLayout.SOUTH, 1); + f.add(b3 = new Button("East"), BorderLayout.EAST, 2); + f.add(b4 = new Button("West"), BorderLayout.WEST, 3); + f.add(b5 = new Button("Center"), BorderLayout.CENTER, -1); + + String[] sExpected = {f.toString(), b1.toString(), b2.toString(), + b3.toString(), b4.toString(), b5.toString()}; + + iCompCount = f.getComponentCount(); + System.out.println("Component count: " + iCompCount); + + for (int j = 0; j <= 10; j++) { + PipedInputStream pin = new PipedInputStream(); + PrintStream output = new PrintStream(new PipedOutputStream(pin), true); + BufferedReader input = new BufferedReader(new InputStreamReader(pin)); + + f.list(output, j); + + output.flush(); + output.close(); + + while ((sLine = input.readLine()) != null) { + v.addElement(sLine); + } + + for (int i = 0; i < v.size(); i++) { + sReturn = (String)v.elementAt(i); + sExpTrim = sExpected[i].trim(); + + if (!(sExpTrim.equals(sReturn.trim()))) { + System.out.println("iNotEqual"); + ++iNotEqual; + } + + int iSpace = sReturn.lastIndexOf(' ') + 1; + + if (i == 0) { + System.out.println("Indent set at: " + j); + System.out.println("Indent return: " + iSpace); + if (iSpace != j) { + System.out.println("iIndentWrong1"); + ++iIndentWrong; + } + } else { + if (iSpace != (j + 1)) { + System.out.println(iSpace + "; " + j); + ++iIndentWrong; + } + } + System.out.println(sReturn); + } + v.removeAllElements(); + v.trimToSize(); + } + + if (iNotEqual == 0 && iIndentWrong == 0) { + bReturn = true; + } else { + bReturn = false; + } + + } catch(IOException e) { + bReturn = false; + System.out.println ("Unexpected Exception thrown: " + e.getMessage()); + e.printStackTrace(); + } finally { + if (f != null) { + f.dispose(); + } + } + + if (bReturn) { + System.out.println("Test for Container.list Passed"); + } else { + System.out.println("Test for Container.list Failed"); + throw new RuntimeException("Test FAILED"); + } + } +} From 03149735e59b7d1d409a6e29ee05ae0537e03d53 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Tue, 1 Oct 2024 18:50:37 +0000 Subject: [PATCH 084/188] 8341060: Cleanup statics in HeapDumper Reviewed-by: shade, sspitsyn --- src/hotspot/share/services/heapDumper.cpp | 101 ++++++++-------------- 1 file changed, 37 insertions(+), 64 deletions(-) diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 5b3749381a01b..10e1a804ad213 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -1512,6 +1512,38 @@ class ClassDumper : public KlassClosure { } }; +// Support class used to generate HPROF_LOAD_CLASS records + +class LoadedClassDumper : public LockedClassesDo { + private: + AbstractDumpWriter* _writer; + GrowableArray* _klass_map; + u4 _class_serial_num; + AbstractDumpWriter* writer() const { return _writer; } + void add_class_serial_number(Klass* k, int serial_num) { + _klass_map->at_put_grow(serial_num, k); + } + public: + LoadedClassDumper(AbstractDumpWriter* writer, GrowableArray* klass_map) + : _writer(writer), _klass_map(klass_map), _class_serial_num(0) {} + + void do_klass(Klass* k) { + // len of HPROF_LOAD_CLASS record + u4 remaining = 2 * oopSize + 2 * sizeof(u4); + DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining); + // class serial number is just a number + writer()->write_u4(++_class_serial_num); + // class ID + writer()->write_classID(k); + // add the Klass* and class serial number pair + add_class_serial_number(k, _class_serial_num); + writer()->write_u4(STACK_TRACE_ID); + // class name ID + Symbol* name = k->name(); + writer()->write_symbolID(name); + } +}; + // Support class used to generate HPROF_GC_ROOT_JNI_LOCAL records class JNILocalsDumper : public OopClosure { @@ -2190,9 +2222,7 @@ void DumpMerger::do_merge() { // The VM operation that performs the heap dump class VM_HeapDumper : public VM_GC_Operation, public WorkerTask, public UnmountedVThreadDumper { private: - static VM_HeapDumper* _global_dumper; - static DumpWriter* _global_writer; - DumpWriter* _local_writer; + DumpWriter* _writer; JavaThread* _oome_thread; Method* _oome_constructor; bool _gc_before_heap_dump; @@ -2218,33 +2248,13 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask, public Unmounte return Atomic::fetch_then_add(&_dump_seq, 1); } - // accessors and setters - static VM_HeapDumper* dumper() { assert(_global_dumper != nullptr, "Error"); return _global_dumper; } - static DumpWriter* writer() { assert(_global_writer != nullptr, "Error"); return _global_writer; } - - void set_global_dumper() { - assert(_global_dumper == nullptr, "Error"); - _global_dumper = this; - } - void set_global_writer() { - assert(_global_writer == nullptr, "Error"); - _global_writer = _local_writer; - } - void clear_global_dumper() { _global_dumper = nullptr; } - void clear_global_writer() { _global_writer = nullptr; } + DumpWriter* writer() const { return _writer; } bool skip_operation() const; - // writes a HPROF_LOAD_CLASS record to global writer - static void do_load_class(Klass* k); - // HPROF_GC_ROOT_THREAD_OBJ records for platform and mounted virtual threads void dump_threads(AbstractDumpWriter* writer); - void add_class_serial_number(Klass* k, int serial_num) { - _klass_map->at_put_grow(serial_num, k); - } - bool is_oom_thread(JavaThread* thread) const { return thread == _oome_thread && _oome_constructor != nullptr; } @@ -2259,7 +2269,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask, public Unmounte 0 /* total full collections, dummy, ignored */, gc_before_heap_dump), WorkerTask("dump heap") { - _local_writer = writer; + _writer = writer; _gc_before_heap_dump = gc_before_heap_dump; _klass_map = new (mtServiceability) GrowableArray(INITIAL_CLASS_COUNT, mtServiceability); @@ -2313,9 +2323,6 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask, public Unmounte void dump_vthread(oop vt, AbstractDumpWriter* segment_writer); }; -VM_HeapDumper* VM_HeapDumper::_global_dumper = nullptr; -DumpWriter* VM_HeapDumper::_global_writer = nullptr; - bool VM_HeapDumper::skip_operation() const { return false; } @@ -2329,31 +2336,6 @@ void DumperSupport::end_of_dump(AbstractDumpWriter* writer) { writer->write_u4(0); } -// writes a HPROF_LOAD_CLASS record for the class -void VM_HeapDumper::do_load_class(Klass* k) { - static u4 class_serial_num = 0; - - // len of HPROF_LOAD_CLASS record - u4 remaining = 2*oopSize + 2*sizeof(u4); - - DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining); - - // class serial number is just a number - writer()->write_u4(++class_serial_num); - - // class ID - writer()->write_classID(k); - - // add the Klass* and class serial number pair - dumper()->add_class_serial_number(k, class_serial_num); - - writer()->write_u4(STACK_TRACE_ID); - - // class name ID - Symbol* name = k->name(); - writer()->write_symbolID(name); -} - // Write a HPROF_GC_ROOT_THREAD_OBJ record for platform/carrier and mounted virtual threads. // Then walk the stack so that locals and JNI locals are dumped. void VM_HeapDumper::dump_threads(AbstractDumpWriter* writer) { @@ -2430,11 +2412,6 @@ void VM_HeapDumper::doit() { } } - // At this point we should be the only dumper active, so - // the following should be safe. - set_global_dumper(); - set_global_writer(); - WorkerThreads* workers = ch->safepoint_workers(); prepare_parallel_dump(workers); @@ -2446,10 +2423,6 @@ void VM_HeapDumper::doit() { workers->run_task(this, _num_dumper_threads); _poi = nullptr; } - - // Now we clear the global variables, so that a future dumper can run. - clear_global_dumper(); - clear_global_writer(); } void VM_HeapDumper::work(uint worker_id) { @@ -2480,8 +2453,8 @@ void VM_HeapDumper::work(uint worker_id) { // write HPROF_LOAD_CLASS records { - LockedClassesDo locked_load_classes(&do_load_class); - ClassLoaderDataGraph::classes_do(&locked_load_classes); + LoadedClassDumper loaded_class_dumper(writer(), _klass_map); + ClassLoaderDataGraph::classes_do(&loaded_class_dumper); } // write HPROF_FRAME and HPROF_TRACE records From d2e77089aaeef83e6f659fd77fdd0a360def760a Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Tue, 1 Oct 2024 21:08:41 +0000 Subject: [PATCH 085/188] 8341367: Problemlist ShapeNotSetSometimes.java on macOS Reviewed-by: aivanov --- test/jdk/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index ef9b82d596728..bf1c9bd31e7a6 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -122,6 +122,7 @@ java/awt/Focus/AutoRequestFocusTest/AutoRequestFocusSetVisibleTest.java 6848407 java/awt/Frame/MaximizedUndecorated/MaximizedUndecorated.java 8022302 generic-all java/awt/Frame/RestoreToOppositeScreen/RestoreToOppositeScreen.java 8286840 linux-all java/awt/Frame/InitialIconifiedTest.java 8203920 macosx-all,linux-all +java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java 8341370 macosx-all java/awt/FileDialog/FileDialogIconTest/FileDialogIconTest.java 8160558 windows-all java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java 8060176 windows-all,macosx-all java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java 8060176 windows-all,macosx-all From 83dcb02d776448aa04f3f41df489bd4355443a4d Mon Sep 17 00:00:00 2001 From: Sandhya Viswanathan Date: Tue, 1 Oct 2024 22:48:31 +0000 Subject: [PATCH 086/188] 8340079: Modify rearrange/selectFrom Vector API methods to perform wrapIndexes instead of checkIndexes Reviewed-by: jbhateja, psandoz --- src/hotspot/share/adlc/formssel.cpp | 2 +- src/hotspot/share/classfile/vmIntrinsics.hpp | 21 ++ src/hotspot/share/opto/c2compiler.cpp | 2 + src/hotspot/share/opto/library_call.cpp | 4 + src/hotspot/share/opto/library_call.hpp | 2 + src/hotspot/share/opto/vectorIntrinsics.cpp | 202 ++++++++++++++++++ .../jdk/internal/vm/vector/VectorSupport.java | 31 +++ .../jdk/incubator/vector/AbstractShuffle.java | 2 +- .../jdk/incubator/vector/Byte128Vector.java | 9 +- .../jdk/incubator/vector/Byte256Vector.java | 9 +- .../jdk/incubator/vector/Byte512Vector.java | 9 +- .../jdk/incubator/vector/Byte64Vector.java | 9 +- .../jdk/incubator/vector/ByteMaxVector.java | 9 +- .../jdk/incubator/vector/ByteVector.java | 35 +-- .../jdk/incubator/vector/Double128Vector.java | 9 +- .../jdk/incubator/vector/Double256Vector.java | 9 +- .../jdk/incubator/vector/Double512Vector.java | 9 +- .../jdk/incubator/vector/Double64Vector.java | 9 +- .../jdk/incubator/vector/DoubleMaxVector.java | 9 +- .../jdk/incubator/vector/DoubleVector.java | 35 +-- .../jdk/incubator/vector/Float128Vector.java | 9 +- .../jdk/incubator/vector/Float256Vector.java | 9 +- .../jdk/incubator/vector/Float512Vector.java | 9 +- .../jdk/incubator/vector/Float64Vector.java | 9 +- .../jdk/incubator/vector/FloatMaxVector.java | 9 +- .../jdk/incubator/vector/FloatVector.java | 35 +-- .../jdk/incubator/vector/Int128Vector.java | 9 +- .../jdk/incubator/vector/Int256Vector.java | 9 +- .../jdk/incubator/vector/Int512Vector.java | 9 +- .../jdk/incubator/vector/Int64Vector.java | 9 +- .../jdk/incubator/vector/IntMaxVector.java | 9 +- .../jdk/incubator/vector/IntVector.java | 35 +-- .../jdk/incubator/vector/Long128Vector.java | 9 +- .../jdk/incubator/vector/Long256Vector.java | 9 +- .../jdk/incubator/vector/Long512Vector.java | 9 +- .../jdk/incubator/vector/Long64Vector.java | 9 +- .../jdk/incubator/vector/LongMaxVector.java | 9 +- .../jdk/incubator/vector/LongVector.java | 35 +-- .../jdk/incubator/vector/Short128Vector.java | 9 +- .../jdk/incubator/vector/Short256Vector.java | 9 +- .../jdk/incubator/vector/Short512Vector.java | 9 +- .../jdk/incubator/vector/Short64Vector.java | 9 +- .../jdk/incubator/vector/ShortMaxVector.java | 9 +- .../jdk/incubator/vector/ShortVector.java | 35 +-- .../classes/jdk/incubator/vector/Vector.java | 21 +- .../incubator/vector/X-Vector.java.template | 35 +-- .../vector/X-VectorBits.java.template | 9 +- 47 files changed, 663 insertions(+), 148 deletions(-) diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index e7df38ff221a9..15bc7ddc67d60 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -4357,7 +4357,7 @@ bool MatchRule::is_vector() const { "RoundDoubleModeV","RotateLeftV" , "RotateRightV", "LoadVector","StoreVector", "LoadVectorGather", "StoreVectorScatter", "LoadVectorGatherMasked", "StoreVectorScatterMasked", "VectorTest", "VectorLoadMask", "VectorStoreMask", "VectorBlend", "VectorInsert", - "VectorRearrange","VectorLoadShuffle", "VectorLoadConst", + "VectorRearrange", "VectorLoadShuffle", "VectorLoadConst", "VectorCastB2X", "VectorCastS2X", "VectorCastI2X", "VectorCastL2X", "VectorCastF2X", "VectorCastD2X", "VectorCastF2HF", "VectorCastHF2F", "VectorUCastB2X", "VectorUCastS2X", "VectorUCastI2X", diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index af1c2b31a9809..b6ce21797a618 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -1008,6 +1008,15 @@ class methodHandle; "Ljdk/internal/vm/vector/VectorSupport$Vector;") \ do_name(vector_shuffle_to_vector_name, "shuffleToVector") \ \ + do_intrinsic(_VectorWrapShuffleIndexes, jdk_internal_vm_vector_VectorSupport, vector_wrap_shuffle_indexes_name, \ + vector_wrap_shuffle_indexes_sig, F_S) \ + do_signature(vector_wrap_shuffle_indexes_sig, "(Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "Ljdk/internal/vm/vector/VectorSupport$VectorShuffle;" \ + "ILjdk/internal/vm/vector/VectorSupport$WrapShuffleIndexesOperation;)" \ + "Ljdk/internal/vm/vector/VectorSupport$VectorShuffle;") \ + do_name(vector_wrap_shuffle_indexes_name, "wrapShuffleIndexes") \ + \ do_intrinsic(_VectorLoadOp, jdk_internal_vm_vector_VectorSupport, vector_load_op_name, vector_load_op_sig, F_S) \ do_signature(vector_load_op_sig, "(Ljava/lang/Class;" \ "Ljava/lang/Class;" \ @@ -1129,6 +1138,18 @@ class methodHandle; "Ljdk/internal/vm/vector/VectorSupport$Vector;") \ do_name(vector_rearrange_name, "rearrangeOp") \ \ + do_intrinsic(_VectorSelectFrom, jdk_internal_vm_vector_VectorSupport, vector_select_from_name, vector_select_from_sig, F_S) \ + do_signature(vector_select_from_sig, "(Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "Ljava/lang/Class;" \ + "I" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;" \ + "Ljdk/internal/vm/vector/VectorSupport$VectorMask;" \ + "Ljdk/internal/vm/vector/VectorSupport$VectorSelectFromOp;)" \ + "Ljdk/internal/vm/vector/VectorSupport$Vector;") \ + do_name(vector_select_from_name, "selectFromOp") \ + \ do_intrinsic(_VectorExtract, jdk_internal_vm_vector_VectorSupport, vector_extract_name, vector_extract_sig, F_S) \ do_signature(vector_extract_sig, "(Ljava/lang/Class;" \ "Ljava/lang/Class;" \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 117e06acd6f31..151c320cadde6 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -811,6 +811,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_VectorFromBitsCoerced: case vmIntrinsics::_VectorShuffleIota: case vmIntrinsics::_VectorShuffleToVector: + case vmIntrinsics::_VectorWrapShuffleIndexes: case vmIntrinsics::_VectorLoadOp: case vmIntrinsics::_VectorLoadMaskedOp: case vmIntrinsics::_VectorStoreOp: @@ -821,6 +822,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_VectorTest: case vmIntrinsics::_VectorBlend: case vmIntrinsics::_VectorRearrange: + case vmIntrinsics::_VectorSelectFrom: case vmIntrinsics::_VectorCompare: case vmIntrinsics::_VectorBroadcastInt: case vmIntrinsics::_VectorConvert: diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 8bbb2f8115ec4..dd4f0b94af6ee 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -717,6 +717,8 @@ bool LibraryCallKit::try_to_inline(int predicate) { return inline_vector_mask_operation(); case vmIntrinsics::_VectorShuffleToVector: return inline_vector_shuffle_to_vector(); + case vmIntrinsics::_VectorWrapShuffleIndexes: + return inline_vector_wrap_shuffle_indexes(); case vmIntrinsics::_VectorLoadOp: return inline_vector_mem_operation(/*is_store=*/false); case vmIntrinsics::_VectorLoadMaskedOp: @@ -737,6 +739,8 @@ bool LibraryCallKit::try_to_inline(int predicate) { return inline_vector_blend(); case vmIntrinsics::_VectorRearrange: return inline_vector_rearrange(); + case vmIntrinsics::_VectorSelectFrom: + return inline_vector_select_from(); case vmIntrinsics::_VectorCompare: return inline_vector_compare(); case vmIntrinsics::_VectorBroadcastInt: diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index dd74734802f65..10375fc23f650 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -353,6 +353,7 @@ class LibraryCallKit : public GraphKit { bool inline_vector_nary_operation(int n); bool inline_vector_frombits_coerced(); bool inline_vector_shuffle_to_vector(); + bool inline_vector_wrap_shuffle_indexes(); bool inline_vector_shuffle_iota(); Node* partially_wrap_indexes(Node* index_vec, int num_elem, BasicType type_bt); bool inline_vector_mask_operation(); @@ -363,6 +364,7 @@ class LibraryCallKit : public GraphKit { bool inline_vector_test(); bool inline_vector_blend(); bool inline_vector_rearrange(); + bool inline_vector_select_from(); bool inline_vector_compare(); bool inline_vector_broadcast_int(); bool inline_vector_convert(); diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index cfcd903e79d95..3753619822938 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -757,6 +757,64 @@ bool LibraryCallKit::inline_vector_shuffle_to_vector() { return true; } +// public static +// > +// SH wrapShuffleIndexes(Class eClass, Class shClass, SH sh, int length, +// ShuffleWrapIndexesOperation defaultImpl) +bool LibraryCallKit::inline_vector_wrap_shuffle_indexes() { + const TypeInstPtr* elem_klass = gvn().type(argument(0))->isa_instptr(); + const TypeInstPtr* shuffle_klass = gvn().type(argument(1))->isa_instptr(); + Node* shuffle = argument(2); + const TypeInt* vlen = gvn().type(argument(3))->isa_int(); + + if (elem_klass == nullptr || shuffle_klass == nullptr || shuffle->is_top() || vlen == nullptr || + !vlen->is_con() || shuffle_klass->const_oop() == nullptr) { + // not enough info for intrinsification + return false; + } + + if (!is_klass_initialized(shuffle_klass)) { + log_if_needed(" ** klass argument not initialized"); + return false; + } + + int num_elem = vlen->get_con(); + if ((num_elem < 4) || !is_power_of_2(num_elem)) { + log_if_needed(" ** vlen < 4 or not power of two=%d", num_elem); + return false; + } + + // Shuffles use byte array based backing storage + BasicType shuffle_bt = T_BYTE; + if (!arch_supports_vector(Op_AndV, num_elem, shuffle_bt, VecMaskNotUsed) || + !arch_supports_vector(Op_Replicate, num_elem, shuffle_bt, VecMaskNotUsed)) { + log_if_needed(" ** not supported: op=wrapShuffleIndexes vlen=%d etype=%s", + num_elem, type2name(shuffle_bt)); + return false; + } + + ciKlass* sbox_klass = shuffle_klass->const_oop()->as_instance()->java_lang_Class_klass(); + const TypeInstPtr* shuffle_box_type = TypeInstPtr::make_exact(TypePtr::NotNull, sbox_klass); + + // Unbox shuffle with true flag to indicate its load shuffle to vector + // shuffle is a byte array + Node* shuffle_vec = unbox_vector(shuffle, shuffle_box_type, shuffle_bt, num_elem, true); + + const TypeVect* vt = TypeVect::make(shuffle_bt, num_elem); + const Type* shuffle_type_bt = Type::get_const_basic_type(shuffle_bt); + Node* mod_mask = gvn().makecon(TypeInt::make(num_elem-1)); + Node* bcast_mod_mask = gvn().transform(VectorNode::scalar2vector(mod_mask, num_elem, shuffle_type_bt)); + // Wrap the indices greater than lane count. + Node* res = gvn().transform(VectorNode::make(Op_AndV, shuffle_vec, bcast_mod_mask, vt)); + + // Wrap it up in VectorBox to keep object type information. + res = box_vector(res, shuffle_box_type, shuffle_bt, num_elem); + set_result(res); + C->set_max_vector_size(MAX2(C->max_vector_size(), (uint)(num_elem * type2aelembytes(shuffle_bt)))); + return true; +} + // public static // , @@ -2044,6 +2102,150 @@ static address get_svml_address(int vop, int bits, BasicType bt, char* name_ptr, return addr; } +// public static +// , +// M extends VectorMask, +// E> +// V selectFromOp(Class vClass, Class mClass, Class eClass, +// int length, V v1, V v2, M m, +// VectorSelectFromOp defaultImpl) +bool LibraryCallKit::inline_vector_select_from() { + const TypeInstPtr* vector_klass = gvn().type(argument(0))->isa_instptr(); + const TypeInstPtr* mask_klass = gvn().type(argument(1))->isa_instptr(); + const TypeInstPtr* elem_klass = gvn().type(argument(2))->isa_instptr(); + const TypeInt* vlen = gvn().type(argument(3))->isa_int(); + + if (vector_klass == nullptr || elem_klass == nullptr || vlen == nullptr || + vector_klass->const_oop() == nullptr || + elem_klass->const_oop() == nullptr || + !vlen->is_con()) { + log_if_needed(" ** missing constant: vclass=%s etype=%s vlen=%s", + NodeClassNames[argument(0)->Opcode()], + NodeClassNames[argument(2)->Opcode()], + NodeClassNames[argument(3)->Opcode()]); + return false; // not enough info for intrinsification + } + if (!is_klass_initialized(vector_klass)) { + log_if_needed(" ** klass argument not initialized"); + return false; + } + ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type(); + if (!elem_type->is_primitive_type()) { + log_if_needed(" ** not a primitive bt=%d", elem_type->basic_type()); + return false; // should be primitive type + } + BasicType elem_bt = elem_type->basic_type(); + int num_elem = vlen->get_con(); + if (!is_power_of_2(num_elem)) { + log_if_needed(" ** vlen not power of two=%d", num_elem); + return false; + } + + int cast_vopc = VectorCastNode::opcode(-1, elem_bt); // from vector of type elem_bt + if (!arch_supports_vector(Op_VectorLoadShuffle, num_elem, elem_bt, VecMaskNotUsed)|| + !arch_supports_vector(Op_AndV, num_elem, T_BYTE, VecMaskNotUsed) || + !arch_supports_vector(Op_Replicate, num_elem, T_BYTE, VecMaskNotUsed) || + !arch_supports_vector(cast_vopc, num_elem, T_BYTE, VecMaskNotUsed)) { + log_if_needed(" ** not supported: arity=0 op=selectFrom vlen=%d etype=%s ismask=no", + num_elem, type2name(elem_bt)); + return false; // not supported + } + + bool is_masked_op = argument(6)->bottom_type() != TypePtr::NULL_PTR; + bool use_predicate = is_masked_op; + if (is_masked_op && + (mask_klass == nullptr || + mask_klass->const_oop() == nullptr || + !is_klass_initialized(mask_klass))) { + log_if_needed(" ** mask_klass argument not initialized"); + return false; // not supported + } + VectorMaskUseType checkFlags = (VectorMaskUseType)(is_masked_op ? (VecMaskUseLoad | VecMaskUsePred) : VecMaskNotUsed); + if (!arch_supports_vector(Op_VectorRearrange, num_elem, elem_bt, checkFlags)) { + use_predicate = false; + if(!is_masked_op || + (!arch_supports_vector(Op_VectorRearrange, num_elem, elem_bt, VecMaskNotUsed) || + !arch_supports_vector(Op_VectorBlend, num_elem, elem_bt, VecMaskUseLoad) || + !arch_supports_vector(Op_Replicate, num_elem, elem_bt, VecMaskNotUsed))) { + log_if_needed(" ** not supported: op=selectFrom vlen=%d etype=%s is_masked_op=%d", + num_elem, type2name(elem_bt), is_masked_op); + return false; // not supported + } + } + ciKlass* vbox_klass = vector_klass->const_oop()->as_instance()->java_lang_Class_klass(); + const TypeInstPtr* vbox_type = TypeInstPtr::make_exact(TypePtr::NotNull, vbox_klass); + + // v1 is the index vector + Node* v1 = unbox_vector(argument(4), vbox_type, elem_bt, num_elem); + // v2 is the vector being rearranged + Node* v2 = unbox_vector(argument(5), vbox_type, elem_bt, num_elem); + + if (v1 == nullptr) { + log_if_needed(" ** unbox failed v1=%s", NodeClassNames[argument(4)->Opcode()]); + return false; // operand unboxing failed + } + + if (v2 == nullptr) { + log_if_needed(" ** unbox failed v2=%s", NodeClassNames[argument(5)->Opcode()]); + return false; // operand unboxing failed + } + + Node* mask = nullptr; + if (is_masked_op) { + ciKlass* mbox_klass = mask_klass->const_oop()->as_instance()->java_lang_Class_klass(); + const TypeInstPtr* mbox_type = TypeInstPtr::make_exact(TypePtr::NotNull, mbox_klass); + mask = unbox_vector(argument(6), mbox_type, elem_bt, num_elem); + if (mask == nullptr) { + log_if_needed(" ** unbox failed mask=%s", NodeClassNames[argument(6)->Opcode()]); + return false; + } + } + + // cast index vector from elem_bt vector to byte vector + const Type * byte_bt = Type::get_const_basic_type(T_BYTE); + const TypeVect * byte_vt = TypeVect::make(byte_bt, num_elem); + Node* byte_shuffle = gvn().transform(VectorCastNode::make(cast_vopc, v1, T_BYTE, num_elem)); + + // wrap the byte vector lanes to (num_elem - 1) to form the shuffle vector where num_elem is vector length + // this is a simple AND operation as we come here only for power of two vector length + Node* mod_val = gvn().makecon(TypeInt::make(num_elem-1)); + Node* bcast_mod = gvn().transform(VectorNode::scalar2vector(mod_val, num_elem, byte_bt)); + byte_shuffle = gvn().transform(VectorNode::make(Op_AndV, byte_shuffle, bcast_mod, byte_vt)); + + // load the shuffle to use in rearrange + const TypeVect * shuffle_vt = TypeVect::make(elem_bt, num_elem); + Node* load_shuffle = gvn().transform(new VectorLoadShuffleNode(byte_shuffle, shuffle_vt)); + + // and finally rearrange + Node* rearrange = new VectorRearrangeNode(v2, load_shuffle); + if (is_masked_op) { + if (use_predicate) { + // masked rearrange is supported so use that directly + rearrange->add_req(mask); + rearrange->add_flag(Node::Flag_is_predicated_vector); + } else { + // masked rearrange is not supported so emulate usig blend + const TypeVect* vt = v1->bottom_type()->is_vect(); + rearrange = gvn().transform(rearrange); + + // create a zero vector with each lane element set as zero + Node* zero = gvn().makecon(Type::get_zero_type(elem_bt)); + Node* zerovec = gvn().transform(VectorNode::scalar2vector(zero, num_elem, Type::get_const_basic_type(elem_bt))); + + // For each lane for which mask is set, blend in the rearranged lane into zero vector + rearrange = new VectorBlendNode(zerovec, rearrange, mask); + } + } + rearrange = gvn().transform(rearrange); + + // box the result + Node* box = box_vector(rearrange, vbox_type, elem_bt, num_elem); + set_result(box); + + C->set_max_vector_size(MAX2(C->max_vector_size(), (uint)(num_elem * type2aelembytes(elem_bt)))); + return true; +} + Node* LibraryCallKit::gen_call_to_svml(int vector_api_op_id, BasicType bt, int num_elem, Node* opd1, Node* opd2) { assert(UseVectorStubs, "sanity"); assert(vector_api_op_id >= VectorSupport::VECTOR_OP_SVML_START && vector_api_op_id <= VectorSupport::VECTOR_OP_SVML_END, "need valid op id"); diff --git a/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java b/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java index ccfa006b102c2..5c4040d912804 100644 --- a/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java +++ b/src/java.base/share/classes/jdk/internal/vm/vector/VectorSupport.java @@ -263,6 +263,20 @@ V shuffleToVector(Class> vClass, Class eClass, Class> { + SH apply(SH sh); + } + + @IntrinsicCandidate + public static + > + SH wrapShuffleIndexes(Class eClass, Class shClass, SH sh, int length, + WrapShuffleIndexesOperation defaultImpl) { + assert isNonCapturingLambda(defaultImpl) : defaultImpl; + return defaultImpl.apply(sh); + } + /* ============================================================================ */ public interface IndexOperation, S extends VectorSpecies> { @@ -605,6 +619,23 @@ V rearrangeOp(Class vClass, Class shClass, Class mClass, Cla return defaultImpl.apply(v, sh, m); } + public interface VectorSelectFromOp, + M extends VectorMask> { + V apply(V v1, V v2, M m); + } + + @IntrinsicCandidate + public static + , + M extends VectorMask, + E> + V selectFromOp(Class vClass, Class mClass, Class eClass, + int length, V v1, V v2, M m, + VectorSelectFromOp defaultImpl) { + assert isNonCapturingLambda(defaultImpl) : defaultImpl; + return defaultImpl.apply(v1, v2, m); + } + /* ============================================================================ */ public interface VectorBlendOp, diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractShuffle.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractShuffle.java index d648fd86484e0..fc39cb6adaccb 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractShuffle.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractShuffle.java @@ -133,7 +133,7 @@ public final VectorShuffle checkIndexes() { } @ForceInline - public final VectorShuffle wrapIndexes() { + public final VectorShuffle wrapIndexesTemplate() { Vector shufvec = this.toVector(); VectorMask vecmask = shufvec.compare(VectorOperators.LT, vspecies().zero()); if (vecmask.anyTrue()) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java index 02a389d08b2e9..0bc25958a7617 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte128Vector.java @@ -503,7 +503,7 @@ public Byte128Vector selectFrom(Vector v, VectorMask m) { return (Byte128Vector) super.selectFromTemplate((Byte128Vector) v, - (Byte128Mask) m); // specialize + Byte128Mask.class, (Byte128Mask) m); // specialize } @@ -860,6 +860,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Byte128Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Byte128Shuffle.class, this, VLENGTH, + (s) -> ((Byte128Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Byte128Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java index 4e035b13b5e04..639646aa77ad5 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte256Vector.java @@ -503,7 +503,7 @@ public Byte256Vector selectFrom(Vector v, VectorMask m) { return (Byte256Vector) super.selectFromTemplate((Byte256Vector) v, - (Byte256Mask) m); // specialize + Byte256Mask.class, (Byte256Mask) m); // specialize } @@ -892,6 +892,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Byte256Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Byte256Shuffle.class, this, VLENGTH, + (s) -> ((Byte256Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Byte256Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java index 15dd06cdccc00..2d8151f6800f3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte512Vector.java @@ -503,7 +503,7 @@ public Byte512Vector selectFrom(Vector v, VectorMask m) { return (Byte512Vector) super.selectFromTemplate((Byte512Vector) v, - (Byte512Mask) m); // specialize + Byte512Mask.class, (Byte512Mask) m); // specialize } @@ -956,6 +956,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Byte512Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Byte512Shuffle.class, this, VLENGTH, + (s) -> ((Byte512Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Byte512Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java index 6ac9d7a8918b1..bc8ed7d704d96 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Byte64Vector.java @@ -503,7 +503,7 @@ public Byte64Vector selectFrom(Vector v, VectorMask m) { return (Byte64Vector) super.selectFromTemplate((Byte64Vector) v, - (Byte64Mask) m); // specialize + Byte64Mask.class, (Byte64Mask) m); // specialize } @@ -844,6 +844,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Byte64Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Byte64Shuffle.class, this, VLENGTH, + (s) -> ((Byte64Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Byte64Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java index ed6e15ca293b2..597afd8d165b3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteMaxVector.java @@ -503,7 +503,7 @@ public ByteMaxVector selectFrom(Vector v, VectorMask m) { return (ByteMaxVector) super.selectFromTemplate((ByteMaxVector) v, - (ByteMaxMask) m); // specialize + ByteMaxMask.class, (ByteMaxMask) m); // specialize } @@ -830,6 +830,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public ByteMaxShuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, ByteMaxShuffle.class, this, VLENGTH, + (s) -> ((ByteMaxShuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public ByteMaxShuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index 8fae8d71b042a..a23bbc7f70957 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -2393,17 +2393,18 @@ ByteVector sliceTemplate(int origin) { */ @Override public abstract - ByteVector rearrange(VectorShuffle m); + ByteVector rearrange(VectorShuffle shuffle); /*package-private*/ @ForceInline final > ByteVector rearrangeTemplate(Class shuffletype, S shuffle) { - shuffle.checkIndexes(); + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, null, byte.class, length(), - this, shuffle, null, + this, ws, null, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return v1.lane(ei); @@ -2428,17 +2429,14 @@ ByteVector rearrangeTemplate(Class shuffletype, M m) { m.check(masktype, this); - VectorMask valid = shuffle.laneIsValid(); - if (m.andNot(valid).anyTrue()) { - shuffle.checkIndexes(); - throw new AssertionError(); - } + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, masktype, byte.class, length(), - this, shuffle, m, + this, ws, m, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); - return ei < 0 || !m_.laneIsSet(i) ? 0 : v1.lane(ei); + return !m_.laneIsSet(i) ? 0 : v1.lane(ei); })); } @@ -2551,7 +2549,10 @@ byte.class, length(), this, m, /*package-private*/ @ForceInline final ByteVector selectFromTemplate(ByteVector v) { - return v.rearrange(this.toShuffle()); + return (ByteVector)VectorSupport.selectFromOp(getClass(), null, byte.class, + length(), this, v, null, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle())); } /** @@ -2563,9 +2564,15 @@ final ByteVector selectFromTemplate(ByteVector v) { /*package-private*/ @ForceInline - final ByteVector selectFromTemplate(ByteVector v, - AbstractMask m) { - return v.rearrange(this.toShuffle(), m); + final + > + ByteVector selectFromTemplate(ByteVector v, + Class masktype, M m) { + m.check(masktype, this); + return (ByteVector)VectorSupport.selectFromOp(getClass(), masktype, byte.class, + length(), this, v, m, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle(), _m)); } /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java index f2a077604f7fc..00840026fff9f 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double128Vector.java @@ -490,7 +490,7 @@ public Double128Vector selectFrom(Vector v, VectorMask m) { return (Double128Vector) super.selectFromTemplate((Double128Vector) v, - (Double128Mask) m); // specialize + Double128Mask.class, (Double128Mask) m); // specialize } @@ -821,6 +821,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Double128Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Double128Shuffle.class, this, VLENGTH, + (s) -> ((Double128Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Double128Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java index da9dd421b17c2..4b42deba73841 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double256Vector.java @@ -490,7 +490,7 @@ public Double256Vector selectFrom(Vector v, VectorMask m) { return (Double256Vector) super.selectFromTemplate((Double256Vector) v, - (Double256Mask) m); // specialize + Double256Mask.class, (Double256Mask) m); // specialize } @@ -825,6 +825,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Double256Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Double256Shuffle.class, this, VLENGTH, + (s) -> ((Double256Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Double256Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java index d23f09e774b4a..c188f990c335f 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double512Vector.java @@ -490,7 +490,7 @@ public Double512Vector selectFrom(Vector v, VectorMask m) { return (Double512Vector) super.selectFromTemplate((Double512Vector) v, - (Double512Mask) m); // specialize + Double512Mask.class, (Double512Mask) m); // specialize } @@ -833,6 +833,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Double512Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Double512Shuffle.class, this, VLENGTH, + (s) -> ((Double512Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Double512Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java index 19bd640f97844..032fa1ac277d9 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Double64Vector.java @@ -490,7 +490,7 @@ public Double64Vector selectFrom(Vector v, VectorMask m) { return (Double64Vector) super.selectFromTemplate((Double64Vector) v, - (Double64Mask) m); // specialize + Double64Mask.class, (Double64Mask) m); // specialize } @@ -819,6 +819,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Double64Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Double64Shuffle.class, this, VLENGTH, + (s) -> ((Double64Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Double64Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java index 73f6f2ece5d12..7251ec82aa63c 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleMaxVector.java @@ -490,7 +490,7 @@ public DoubleMaxVector selectFrom(Vector v, VectorMask m) { return (DoubleMaxVector) super.selectFromTemplate((DoubleMaxVector) v, - (DoubleMaxMask) m); // specialize + DoubleMaxMask.class, (DoubleMaxMask) m); // specialize } @@ -818,6 +818,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public DoubleMaxShuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, DoubleMaxShuffle.class, this, VLENGTH, + (s) -> ((DoubleMaxShuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public DoubleMaxShuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index 59e6719573209..6cc12048d4632 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -2235,17 +2235,18 @@ DoubleVector sliceTemplate(int origin) { */ @Override public abstract - DoubleVector rearrange(VectorShuffle m); + DoubleVector rearrange(VectorShuffle shuffle); /*package-private*/ @ForceInline final > DoubleVector rearrangeTemplate(Class shuffletype, S shuffle) { - shuffle.checkIndexes(); + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, null, double.class, length(), - this, shuffle, null, + this, ws, null, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return v1.lane(ei); @@ -2270,17 +2271,14 @@ DoubleVector rearrangeTemplate(Class shuffletype, M m) { m.check(masktype, this); - VectorMask valid = shuffle.laneIsValid(); - if (m.andNot(valid).anyTrue()) { - shuffle.checkIndexes(); - throw new AssertionError(); - } + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, masktype, double.class, length(), - this, shuffle, m, + this, ws, m, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); - return ei < 0 || !m_.laneIsSet(i) ? 0 : v1.lane(ei); + return !m_.laneIsSet(i) ? 0 : v1.lane(ei); })); } @@ -2393,7 +2391,10 @@ DoubleVector expandTemplate(Class masktype, M m) { /*package-private*/ @ForceInline final DoubleVector selectFromTemplate(DoubleVector v) { - return v.rearrange(this.toShuffle()); + return (DoubleVector)VectorSupport.selectFromOp(getClass(), null, double.class, + length(), this, v, null, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle())); } /** @@ -2405,9 +2406,15 @@ final DoubleVector selectFromTemplate(DoubleVector v) { /*package-private*/ @ForceInline - final DoubleVector selectFromTemplate(DoubleVector v, - AbstractMask m) { - return v.rearrange(this.toShuffle(), m); + final + > + DoubleVector selectFromTemplate(DoubleVector v, + Class masktype, M m) { + m.check(masktype, this); + return (DoubleVector)VectorSupport.selectFromOp(getClass(), masktype, double.class, + length(), this, v, m, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle(), _m)); } /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java index ae47beca5de53..2e016725f812b 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float128Vector.java @@ -490,7 +490,7 @@ public Float128Vector selectFrom(Vector v, VectorMask m) { return (Float128Vector) super.selectFromTemplate((Float128Vector) v, - (Float128Mask) m); // specialize + Float128Mask.class, (Float128Mask) m); // specialize } @@ -825,6 +825,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Float128Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Float128Shuffle.class, this, VLENGTH, + (s) -> ((Float128Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Float128Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java index d5c0506a54257..00e6083588339 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float256Vector.java @@ -490,7 +490,7 @@ public Float256Vector selectFrom(Vector v, VectorMask m) { return (Float256Vector) super.selectFromTemplate((Float256Vector) v, - (Float256Mask) m); // specialize + Float256Mask.class, (Float256Mask) m); // specialize } @@ -833,6 +833,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Float256Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Float256Shuffle.class, this, VLENGTH, + (s) -> ((Float256Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Float256Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java index 536f7db69465e..1f2a792c52c2e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float512Vector.java @@ -490,7 +490,7 @@ public Float512Vector selectFrom(Vector v, VectorMask m) { return (Float512Vector) super.selectFromTemplate((Float512Vector) v, - (Float512Mask) m); // specialize + Float512Mask.class, (Float512Mask) m); // specialize } @@ -849,6 +849,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Float512Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Float512Shuffle.class, this, VLENGTH, + (s) -> ((Float512Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Float512Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java index 849062c6cb84b..6c913ce84a9ba 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Float64Vector.java @@ -490,7 +490,7 @@ public Float64Vector selectFrom(Vector v, VectorMask m) { return (Float64Vector) super.selectFromTemplate((Float64Vector) v, - (Float64Mask) m); // specialize + Float64Mask.class, (Float64Mask) m); // specialize } @@ -821,6 +821,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Float64Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Float64Shuffle.class, this, VLENGTH, + (s) -> ((Float64Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Float64Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java index b14797f6788d4..b9a0a93f91253 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatMaxVector.java @@ -490,7 +490,7 @@ public FloatMaxVector selectFrom(Vector v, VectorMask m) { return (FloatMaxVector) super.selectFromTemplate((FloatMaxVector) v, - (FloatMaxMask) m); // specialize + FloatMaxMask.class, (FloatMaxMask) m); // specialize } @@ -818,6 +818,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public FloatMaxShuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, FloatMaxShuffle.class, this, VLENGTH, + (s) -> ((FloatMaxShuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public FloatMaxShuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index 45427817e3dac..b962dc55ce351 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -2247,17 +2247,18 @@ FloatVector sliceTemplate(int origin) { */ @Override public abstract - FloatVector rearrange(VectorShuffle m); + FloatVector rearrange(VectorShuffle shuffle); /*package-private*/ @ForceInline final > FloatVector rearrangeTemplate(Class shuffletype, S shuffle) { - shuffle.checkIndexes(); + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, null, float.class, length(), - this, shuffle, null, + this, ws, null, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return v1.lane(ei); @@ -2282,17 +2283,14 @@ FloatVector rearrangeTemplate(Class shuffletype, M m) { m.check(masktype, this); - VectorMask valid = shuffle.laneIsValid(); - if (m.andNot(valid).anyTrue()) { - shuffle.checkIndexes(); - throw new AssertionError(); - } + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, masktype, float.class, length(), - this, shuffle, m, + this, ws, m, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); - return ei < 0 || !m_.laneIsSet(i) ? 0 : v1.lane(ei); + return !m_.laneIsSet(i) ? 0 : v1.lane(ei); })); } @@ -2405,7 +2403,10 @@ float.class, length(), this, m, /*package-private*/ @ForceInline final FloatVector selectFromTemplate(FloatVector v) { - return v.rearrange(this.toShuffle()); + return (FloatVector)VectorSupport.selectFromOp(getClass(), null, float.class, + length(), this, v, null, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle())); } /** @@ -2417,9 +2418,15 @@ final FloatVector selectFromTemplate(FloatVector v) { /*package-private*/ @ForceInline - final FloatVector selectFromTemplate(FloatVector v, - AbstractMask m) { - return v.rearrange(this.toShuffle(), m); + final + > + FloatVector selectFromTemplate(FloatVector v, + Class masktype, M m) { + m.check(masktype, this); + return (FloatVector)VectorSupport.selectFromOp(getClass(), masktype, float.class, + length(), this, v, m, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle(), _m)); } /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java index cd652941fb366..f7135e19cb6e2 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int128Vector.java @@ -503,7 +503,7 @@ public Int128Vector selectFrom(Vector v, VectorMask m) { return (Int128Vector) super.selectFromTemplate((Int128Vector) v, - (Int128Mask) m); // specialize + Int128Mask.class, (Int128Mask) m); // specialize } @@ -836,6 +836,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Int128Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Int128Shuffle.class, this, VLENGTH, + (s) -> ((Int128Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Int128Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java index b76a1035561f6..474ff974b3169 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int256Vector.java @@ -503,7 +503,7 @@ public Int256Vector selectFrom(Vector v, VectorMask m) { return (Int256Vector) super.selectFromTemplate((Int256Vector) v, - (Int256Mask) m); // specialize + Int256Mask.class, (Int256Mask) m); // specialize } @@ -844,6 +844,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Int256Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Int256Shuffle.class, this, VLENGTH, + (s) -> ((Int256Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Int256Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java index 3a42c6611445b..9fec8c0c99f13 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int512Vector.java @@ -503,7 +503,7 @@ public Int512Vector selectFrom(Vector v, VectorMask m) { return (Int512Vector) super.selectFromTemplate((Int512Vector) v, - (Int512Mask) m); // specialize + Int512Mask.class, (Int512Mask) m); // specialize } @@ -860,6 +860,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Int512Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Int512Shuffle.class, this, VLENGTH, + (s) -> ((Int512Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Int512Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java index 4181e6b4ea3e7..3b3c0723ee1a3 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Int64Vector.java @@ -503,7 +503,7 @@ public Int64Vector selectFrom(Vector v, VectorMask m) { return (Int64Vector) super.selectFromTemplate((Int64Vector) v, - (Int64Mask) m); // specialize + Int64Mask.class, (Int64Mask) m); // specialize } @@ -832,6 +832,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Int64Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Int64Shuffle.class, this, VLENGTH, + (s) -> ((Int64Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Int64Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java index 785022fcd65f0..5738cb7a4bc94 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntMaxVector.java @@ -503,7 +503,7 @@ public IntMaxVector selectFrom(Vector v, VectorMask m) { return (IntMaxVector) super.selectFromTemplate((IntMaxVector) v, - (IntMaxMask) m); // specialize + IntMaxMask.class, (IntMaxMask) m); // specialize } @@ -841,6 +841,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public IntMaxShuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, IntMaxShuffle.class, this, VLENGTH, + (s) -> ((IntMaxShuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public IntMaxShuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index 3317e25e73e73..16b5ceecba35e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java @@ -2378,17 +2378,18 @@ IntVector sliceTemplate(int origin) { */ @Override public abstract - IntVector rearrange(VectorShuffle m); + IntVector rearrange(VectorShuffle shuffle); /*package-private*/ @ForceInline final > IntVector rearrangeTemplate(Class shuffletype, S shuffle) { - shuffle.checkIndexes(); + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, null, int.class, length(), - this, shuffle, null, + this, ws, null, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return v1.lane(ei); @@ -2413,17 +2414,14 @@ IntVector rearrangeTemplate(Class shuffletype, M m) { m.check(masktype, this); - VectorMask valid = shuffle.laneIsValid(); - if (m.andNot(valid).anyTrue()) { - shuffle.checkIndexes(); - throw new AssertionError(); - } + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, masktype, int.class, length(), - this, shuffle, m, + this, ws, m, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); - return ei < 0 || !m_.laneIsSet(i) ? 0 : v1.lane(ei); + return !m_.laneIsSet(i) ? 0 : v1.lane(ei); })); } @@ -2536,7 +2534,10 @@ int.class, length(), this, m, /*package-private*/ @ForceInline final IntVector selectFromTemplate(IntVector v) { - return v.rearrange(this.toShuffle()); + return (IntVector)VectorSupport.selectFromOp(getClass(), null, int.class, + length(), this, v, null, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle())); } /** @@ -2548,9 +2549,15 @@ final IntVector selectFromTemplate(IntVector v) { /*package-private*/ @ForceInline - final IntVector selectFromTemplate(IntVector v, - AbstractMask m) { - return v.rearrange(this.toShuffle(), m); + final + > + IntVector selectFromTemplate(IntVector v, + Class masktype, M m) { + m.check(masktype, this); + return (IntVector)VectorSupport.selectFromOp(getClass(), masktype, int.class, + length(), this, v, m, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle(), _m)); } /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java index 302c71bc13b10..567789627c6cb 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long128Vector.java @@ -493,7 +493,7 @@ public Long128Vector selectFrom(Vector v, VectorMask m) { return (Long128Vector) super.selectFromTemplate((Long128Vector) v, - (Long128Mask) m); // specialize + Long128Mask.class, (Long128Mask) m); // specialize } @@ -822,6 +822,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Long128Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Long128Shuffle.class, this, VLENGTH, + (s) -> ((Long128Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Long128Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java index 04c51c377e1de..5ef0f121464f6 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long256Vector.java @@ -493,7 +493,7 @@ public Long256Vector selectFrom(Vector v, VectorMask m) { return (Long256Vector) super.selectFromTemplate((Long256Vector) v, - (Long256Mask) m); // specialize + Long256Mask.class, (Long256Mask) m); // specialize } @@ -826,6 +826,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Long256Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Long256Shuffle.class, this, VLENGTH, + (s) -> ((Long256Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Long256Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java index fbcd57400d579..acdb471609f22 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long512Vector.java @@ -493,7 +493,7 @@ public Long512Vector selectFrom(Vector v, VectorMask m) { return (Long512Vector) super.selectFromTemplate((Long512Vector) v, - (Long512Mask) m); // specialize + Long512Mask.class, (Long512Mask) m); // specialize } @@ -834,6 +834,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Long512Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Long512Shuffle.class, this, VLENGTH, + (s) -> ((Long512Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Long512Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java index 3b2e77f1a54ac..627f7437367cb 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Long64Vector.java @@ -493,7 +493,7 @@ public Long64Vector selectFrom(Vector v, VectorMask m) { return (Long64Vector) super.selectFromTemplate((Long64Vector) v, - (Long64Mask) m); // specialize + Long64Mask.class, (Long64Mask) m); // specialize } @@ -820,6 +820,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Long64Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Long64Shuffle.class, this, VLENGTH, + (s) -> ((Long64Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Long64Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java index cc3641be3d62f..aec3bb89fcd02 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongMaxVector.java @@ -493,7 +493,7 @@ public LongMaxVector selectFrom(Vector v, VectorMask m) { return (LongMaxVector) super.selectFromTemplate((LongMaxVector) v, - (LongMaxMask) m); // specialize + LongMaxMask.class, (LongMaxMask) m); // specialize } @@ -820,6 +820,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public LongMaxShuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, LongMaxShuffle.class, this, VLENGTH, + (s) -> ((LongMaxShuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public LongMaxShuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 9dd3f2eb13626..15ac2bc7b7f6c 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -2244,17 +2244,18 @@ LongVector sliceTemplate(int origin) { */ @Override public abstract - LongVector rearrange(VectorShuffle m); + LongVector rearrange(VectorShuffle shuffle); /*package-private*/ @ForceInline final > LongVector rearrangeTemplate(Class shuffletype, S shuffle) { - shuffle.checkIndexes(); + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, null, long.class, length(), - this, shuffle, null, + this, ws, null, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return v1.lane(ei); @@ -2279,17 +2280,14 @@ LongVector rearrangeTemplate(Class shuffletype, M m) { m.check(masktype, this); - VectorMask valid = shuffle.laneIsValid(); - if (m.andNot(valid).anyTrue()) { - shuffle.checkIndexes(); - throw new AssertionError(); - } + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, masktype, long.class, length(), - this, shuffle, m, + this, ws, m, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); - return ei < 0 || !m_.laneIsSet(i) ? 0 : v1.lane(ei); + return !m_.laneIsSet(i) ? 0 : v1.lane(ei); })); } @@ -2402,7 +2400,10 @@ long.class, length(), this, m, /*package-private*/ @ForceInline final LongVector selectFromTemplate(LongVector v) { - return v.rearrange(this.toShuffle()); + return (LongVector)VectorSupport.selectFromOp(getClass(), null, long.class, + length(), this, v, null, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle())); } /** @@ -2414,9 +2415,15 @@ final LongVector selectFromTemplate(LongVector v) { /*package-private*/ @ForceInline - final LongVector selectFromTemplate(LongVector v, - AbstractMask m) { - return v.rearrange(this.toShuffle(), m); + final + > + LongVector selectFromTemplate(LongVector v, + Class masktype, M m) { + m.check(masktype, this); + return (LongVector)VectorSupport.selectFromOp(getClass(), masktype, long.class, + length(), this, v, m, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle(), _m)); } /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java index 7703df9a59a3d..fe34886512a13 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short128Vector.java @@ -503,7 +503,7 @@ public Short128Vector selectFrom(Vector v, VectorMask m) { return (Short128Vector) super.selectFromTemplate((Short128Vector) v, - (Short128Mask) m); // specialize + Short128Mask.class, (Short128Mask) m); // specialize } @@ -844,6 +844,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Short128Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Short128Shuffle.class, this, VLENGTH, + (s) -> ((Short128Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Short128Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java index cf84593019523..243e24ad26bef 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short256Vector.java @@ -503,7 +503,7 @@ public Short256Vector selectFrom(Vector v, VectorMask m) { return (Short256Vector) super.selectFromTemplate((Short256Vector) v, - (Short256Mask) m); // specialize + Short256Mask.class, (Short256Mask) m); // specialize } @@ -860,6 +860,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Short256Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Short256Shuffle.class, this, VLENGTH, + (s) -> ((Short256Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Short256Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java index 67a5073df0525..4114783608960 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short512Vector.java @@ -503,7 +503,7 @@ public Short512Vector selectFrom(Vector v, VectorMask m) { return (Short512Vector) super.selectFromTemplate((Short512Vector) v, - (Short512Mask) m); // specialize + Short512Mask.class, (Short512Mask) m); // specialize } @@ -892,6 +892,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Short512Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Short512Shuffle.class, this, VLENGTH, + (s) -> ((Short512Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Short512Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java index 263ee10d907ba..d80d4c4e2ec52 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Short64Vector.java @@ -503,7 +503,7 @@ public Short64Vector selectFrom(Vector v, VectorMask m) { return (Short64Vector) super.selectFromTemplate((Short64Vector) v, - (Short64Mask) m); // specialize + Short64Mask.class, (Short64Mask) m); // specialize } @@ -836,6 +836,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public Short64Shuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, Short64Shuffle.class, this, VLENGTH, + (s) -> ((Short64Shuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public Short64Shuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java index 07a2caebef0ae..799483a667590 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortMaxVector.java @@ -503,7 +503,7 @@ public ShortMaxVector selectFrom(Vector v, VectorMask m) { return (ShortMaxVector) super.selectFromTemplate((ShortMaxVector) v, - (ShortMaxMask) m); // specialize + ShortMaxMask.class, (ShortMaxMask) m); // specialize } @@ -830,6 +830,13 @@ public VectorShuffle cast(VectorSpecies s) { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public ShortMaxShuffle wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, ShortMaxShuffle.class, this, VLENGTH, + (s) -> ((ShortMaxShuffle)(((AbstractShuffle)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public ShortMaxShuffle rearrange(VectorShuffle shuffle) { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index ba21e8a9e9563..fb0512fd5b9ea 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -2394,17 +2394,18 @@ ShortVector sliceTemplate(int origin) { */ @Override public abstract - ShortVector rearrange(VectorShuffle m); + ShortVector rearrange(VectorShuffle shuffle); /*package-private*/ @ForceInline final > ShortVector rearrangeTemplate(Class shuffletype, S shuffle) { - shuffle.checkIndexes(); + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, null, short.class, length(), - this, shuffle, null, + this, ws, null, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return v1.lane(ei); @@ -2429,17 +2430,14 @@ ShortVector rearrangeTemplate(Class shuffletype, M m) { m.check(masktype, this); - VectorMask valid = shuffle.laneIsValid(); - if (m.andNot(valid).anyTrue()) { - shuffle.checkIndexes(); - throw new AssertionError(); - } + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, masktype, short.class, length(), - this, shuffle, m, + this, ws, m, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); - return ei < 0 || !m_.laneIsSet(i) ? 0 : v1.lane(ei); + return !m_.laneIsSet(i) ? 0 : v1.lane(ei); })); } @@ -2552,7 +2550,10 @@ short.class, length(), this, m, /*package-private*/ @ForceInline final ShortVector selectFromTemplate(ShortVector v) { - return v.rearrange(this.toShuffle()); + return (ShortVector)VectorSupport.selectFromOp(getClass(), null, short.class, + length(), this, v, null, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle())); } /** @@ -2564,9 +2565,15 @@ final ShortVector selectFromTemplate(ShortVector v) { /*package-private*/ @ForceInline - final ShortVector selectFromTemplate(ShortVector v, - AbstractMask m) { - return v.rearrange(this.toShuffle(), m); + final + > + ShortVector selectFromTemplate(ShortVector v, + Class masktype, M m) { + m.check(masktype, this); + return (ShortVector)VectorSupport.selectFromOp(getClass(), masktype, short.class, + length(), this, v, m, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle(), _m)); } /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java index d34ac79e7c32c..fda073f686389 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/Vector.java @@ -2614,17 +2614,14 @@ public abstract VectorMask compare(VectorOperators.Comparison op, * elements of this vector. * * For each lane {@code N} of the shuffle, and for each lane - * source index {@code I=s.laneSource(N)} in the shuffle, + * source index {@code I=s.wrapIndex(s.laneSource(N))} in the shuffle, * the output lane {@code N} obtains the value from * the input vector at lane {@code I}. * * @param s the shuffle controlling lane index selection * @return the rearrangement of the lane elements of this vector - * @throws IndexOutOfBoundsException if there are any exceptional - * source indexes in the shuffle * @see #rearrange(VectorShuffle,VectorMask) * @see #rearrange(VectorShuffle,Vector) - * @see VectorShuffle#laneIsValid() */ public abstract Vector rearrange(VectorShuffle s); @@ -2636,27 +2633,22 @@ public abstract VectorMask compare(VectorOperators.Comparison op, * elements of this vector. * * For each lane {@code N} of the shuffle, and for each lane - * source index {@code I=s.laneSource(N)} in the shuffle, + * source index {@code I=s.wrapIndex(s.laneSource(N))} in the shuffle, * the output lane {@code N} obtains the value from * the input vector at lane {@code I} if the mask is set. * Otherwise the output lane {@code N} is set to zero. * *

      This method returns the value of this pseudocode: *

      {@code
      -     * Vector r = this.rearrange(s.wrapIndexes());
      -     * VectorMask valid = s.laneIsValid();
      -     * if (m.andNot(valid).anyTrue()) throw ...;
      +     * Vector r = this.rearrange(s);
            * return broadcast(0).blend(r, m);
            * }
      * * @param s the shuffle controlling lane index selection * @param m the mask controlling application of the shuffle * @return the rearrangement of the lane elements of this vector - * @throws IndexOutOfBoundsException if there are any exceptional - * source indexes in the shuffle where the mask is set * @see #rearrange(VectorShuffle) * @see #rearrange(VectorShuffle,Vector) - * @see VectorShuffle#laneIsValid() */ public abstract Vector rearrange(VectorShuffle s, VectorMask m); @@ -2747,7 +2739,7 @@ public abstract VectorMask compare(VectorOperators.Comparison op, * this vector. * * For each lane {@code N} of this vector, and for each lane - * value {@code I=this.lane(N)} in this vector, + * value {@code I=wrapIndex(this.lane(N))} in this vector, * the output lane {@code N} obtains the value from * the argument vector at lane {@code I}. * @@ -2760,8 +2752,6 @@ public abstract VectorMask compare(VectorOperators.Comparison op, * * @param v the vector supplying the result values * @return the rearrangement of the lane elements of {@code v} - * @throws IndexOutOfBoundsException if any invalid - * source indexes are found in {@code this} * @see #rearrange(VectorShuffle) */ public abstract Vector selectFrom(Vector v); @@ -2787,9 +2777,6 @@ public abstract VectorMask compare(VectorOperators.Comparison op, * @param v the vector supplying the result values * @param m the mask controlling selection from {@code v} * @return the rearrangement of the lane elements of {@code v} - * @throws IndexOutOfBoundsException if any invalid - * source indexes are found in {@code this}, - * in a lane which is set in the mask * @see #selectFrom(Vector) * @see #rearrange(VectorShuffle,VectorMask) */ diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index d7562bae4755a..fcc128ea8c7b0 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -2770,17 +2770,18 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { */ @Override public abstract - $abstractvectortype$ rearrange(VectorShuffle<$Boxtype$> m); + $abstractvectortype$ rearrange(VectorShuffle<$Boxtype$> shuffle); /*package-private*/ @ForceInline final > $abstractvectortype$ rearrangeTemplate(Class shuffletype, S shuffle) { - shuffle.checkIndexes(); + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, null, $type$.class, length(), - this, shuffle, null, + this, ws, null, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); return v1.lane(ei); @@ -2805,17 +2806,14 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { M m) { m.check(masktype, this); - VectorMask<$Boxtype$> valid = shuffle.laneIsValid(); - if (m.andNot(valid).anyTrue()) { - shuffle.checkIndexes(); - throw new AssertionError(); - } + @SuppressWarnings("unchecked") + S ws = (S) shuffle.wrapIndexes(); return VectorSupport.rearrangeOp( getClass(), shuffletype, masktype, $type$.class, length(), - this, shuffle, m, + this, ws, m, (v1, s_, m_) -> v1.uOp((i, a) -> { int ei = s_.laneSource(i); - return ei < 0 || !m_.laneIsSet(i) ? 0 : v1.lane(ei); + return !m_.laneIsSet(i) ? 0 : v1.lane(ei); })); } @@ -2928,7 +2926,10 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { /*package-private*/ @ForceInline final $abstractvectortype$ selectFromTemplate($abstractvectortype$ v) { - return v.rearrange(this.toShuffle()); + return ($Type$Vector)VectorSupport.selectFromOp(getClass(), null, $type$.class, + length(), this, v, null, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle())); } /** @@ -2940,9 +2941,15 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { /*package-private*/ @ForceInline - final $abstractvectortype$ selectFromTemplate($abstractvectortype$ v, - AbstractMask<$Boxtype$> m) { - return v.rearrange(this.toShuffle(), m); + final + > + $abstractvectortype$ selectFromTemplate($abstractvectortype$ v, + Class masktype, M m) { + m.check(masktype, this); + return ($Type$Vector)VectorSupport.selectFromOp(getClass(), masktype, $type$.class, + length(), this, v, m, + (v1, v2, _m) -> + v2.rearrange(v1.toShuffle(), _m)); } /// Ternary operations diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template index 111d4bbefd44b..483962b4e0670 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-VectorBits.java.template @@ -509,7 +509,7 @@ final class $vectortype$ extends $abstractvectortype$ { VectorMask<$Boxtype$> m) { return ($vectortype$) super.selectFromTemplate(($vectortype$) v, - ($masktype$) m); // specialize + $masktype$.class, ($masktype$) m); // specialize } @@ -1118,6 +1118,13 @@ final class $vectortype$ extends $abstractvectortype$ { return s.shuffleFromArray(shuffleArray, 0).check(s); } + @Override + @ForceInline + public $shuffletype$ wrapIndexes() { + return VectorSupport.wrapShuffleIndexes(ETYPE, $shuffletype$.class, this, VLENGTH, + (s) -> (($shuffletype$)(((AbstractShuffle<$Boxtype$>)(s)).wrapIndexesTemplate()))); + } + @ForceInline @Override public $shuffletype$ rearrange(VectorShuffle<$Boxtype$> shuffle) { From 8d6d37fea133380d4143f5db38ad3790efa84f68 Mon Sep 17 00:00:00 2001 From: Tobias Holenstein Date: Tue, 1 Oct 2024 23:52:46 +0000 Subject: [PATCH 087/188] 8320308: C2 compilation crashes in LibraryCallKit::inline_unsafe_access Reviewed-by: thartmann, kvn, vlivanov, epeter, roland --- src/hotspot/share/opto/library_call.cpp | 5 +- test/hotspot/jtreg/ProblemList.txt | 1 - .../TestUnsafeArrayAccessWithNullBase.java | 113 ++++++++++++++++++ 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/parsing/TestUnsafeArrayAccessWithNullBase.java diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index dd4f0b94af6ee..4d182e06a5657 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -2052,7 +2052,7 @@ LibraryCallKit::classify_unsafe_addr(Node* &base, Node* &offset, BasicType type) if (base_type == nullptr) { // Unknown type. return Type::AnyPtr; - } else if (base_type == TypePtr::NULL_PTR) { + } else if (_gvn.type(base->uncast()) == TypePtr::NULL_PTR) { // Since this is a null+long form, we have to switch to a rawptr. base = _gvn.transform(new CastX2PNode(offset)); offset = MakeConX(0); @@ -2370,8 +2370,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c SafePointNode* old_map = clone_map(); Node* adr = make_unsafe_address(base, offset, type, kind == Relaxed); + assert(!stopped(), "Inlining of unsafe access failed: address construction stopped unexpectedly"); - if (_gvn.type(base)->isa_ptr() == TypePtr::NULL_PTR) { + if (_gvn.type(base->uncast())->isa_ptr() == TypePtr::NULL_PTR) { if (type != T_OBJECT) { decorators |= IN_NATIVE; // off-heap primitive access } else { diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index aefe09fd3aec2..0e75009ac8a1a 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -43,7 +43,6 @@ # :hotspot_compiler -applications/ctw/modules/java_base.java 8340683 generic-all compiler/ciReplay/TestSAServer.java 8029528 generic-all compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8225370 generic-all diff --git a/test/hotspot/jtreg/compiler/parsing/TestUnsafeArrayAccessWithNullBase.java b/test/hotspot/jtreg/compiler/parsing/TestUnsafeArrayAccessWithNullBase.java new file mode 100644 index 0000000000000..28eb4f3c165d4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/parsing/TestUnsafeArrayAccessWithNullBase.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8320308 + * @summary Unsafe::getShortUnaligned with base null hidden behind CheckCastPP nodes + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @run main/othervm -Xbatch -XX:CompileCommand=quiet -XX:TypeProfileLevel=222 + * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline + * -XX:CompileCommand=compileonly,compiler.parsing.TestUnsafeArrayAccessWithNullBase::test* + * -XX:-TieredCompilation compiler.parsing.TestUnsafeArrayAccessWithNullBase + * @run main compiler.parsing.TestUnsafeArrayAccessWithNullBase + */ + +package compiler.parsing; + +import java.lang.reflect.*; +import jdk.internal.misc.Unsafe; + +public class TestUnsafeArrayAccessWithNullBase { + + /* + Trigger bug when handling Unsafe.getShortUnaligned with null checks and inlined methods. + The bug appears when the method is incrementally inlined and optimized based on the argument profile information. + + Warmup Phase: By warming up with non-null values, the argument profile for the helper methods records non-null types. + - insert CheckCastPP: speculative=byte[int:>=0] for return of getSmall/getLarge + - insert CheckCastPP: speculative=byte[int:>=0] for argument `Object array` in helperSmall/helperLarge + Trigger Phase: Calling test causes LibraryCallKit::inline_unsafe_access(..) for Unsafe::getShortUnaligned to fail: + Reason: UNSAFE.getShortUnaligned(array, offset) is called with array=null, + but ConP null is now hidden by two CheckCastPP with speculative=byte[int:>=0] in the graph + */ + + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + private static final Object byteArray = new byte[1_050_000]; + + public static Object getLarge(boolean useNull) { + return useNull ? null : byteArray; + } + + public static Object getSmall(boolean useNull) { + return useNull ? null : new byte[10]; + } + + // use a helper to delay inlining of UNSAFE.getShortUnaligned + public static int helperLarge(Object array, boolean run) { + // offset >= os::vm_page_size(): LibraryCallKit::classify_unsafe_addr returns Type::AnyPtr + return run ? UNSAFE.getShortUnaligned(array, 1_049_000) : 0; // after warmup CheckCastPP: speculative=byte[int:>=0] + } + + public static int accessLargeArray(boolean useNull, boolean run) { + Object array = getLarge(useNull); // after warmup CheckCastPP: speculative=byte[int:>=0] + // getLarge() ensures null is only visible after helperLarge was (incrementally) inlined + return helperLarge(array, run); + } + + // use a helper to delay inlining of UNSAFE.getShortUnaligned + // warmup adds argument profile information for array: CheckCastPP with type non null + public static int helperSmall(Object array, boolean run) { + // 0 <= offset < os::vm_page_size(): LibraryCallKit::classify_unsafe_addr returns Type::OopPtr + return run ? UNSAFE.getShortUnaligned(array, 1) : 0; // after warmup CheckCastPP: speculative=byte[int:>=0] + } + + public static int accessSmallArray(boolean useNull, boolean run) { + Object array = getSmall(useNull); // after warmup CheckCastPP: speculative=byte[int:>=0] + return helperSmall(array, run); + } + + public static int test1(boolean run) { + return accessLargeArray(true, run); + } + + public static int test2(boolean run) { + return accessSmallArray(true, run); + } + + public static void main(String[] args) { + // Warmup to collect speculative types + for (int i = 0; i < 10_000; i++) { + accessLargeArray(false, true); + accessSmallArray(false, true); + } + + // Trigger Compilation + for (int i = 0; i < 10_000; ++i) { + test1(false); + test2(false); + } + } +} From 0f381137cb9338453a7d77a7ebdfaa9b34b5028b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Wed, 2 Oct 2024 01:27:03 +0000 Subject: [PATCH 088/188] 8341243: Use ArraySupport.SOFT_MAX_ARRAY_LENGTH for max array size in java.base Reviewed-by: jpai, smarks --- src/java.base/share/classes/java/io/InputStream.java | 11 +++++------ src/java.base/share/classes/java/util/ArrayDeque.java | 8 +++----- src/java.base/share/classes/java/util/BitSet.java | 4 ++-- src/java.base/share/classes/java/util/Hashtable.java | 10 ++++------ .../java/util/concurrent/ConcurrentHashMap.java | 3 ++- .../share/classes/java/util/regex/Pattern.java | 4 ++-- .../share/classes/java/util/stream/Nodes.java | 6 ++++-- .../internal/foreign/AbstractMemorySegmentImpl.java | 2 +- .../sun/security/util/SignatureFileVerifier.java | 7 ++++--- test/jdk/java/lang/StringBuffer/HugeCapacity.java | 7 +++++-- test/jdk/java/lang/StringBuilder/HugeCapacity.java | 7 +++++-- .../nio/charset/CharsetDecoder/XcodeOverflow.java | 8 +++++--- .../java/util/Base64/TestEncodingDecodingLength.java | 4 +++- .../jdk/java/util/concurrent/tck/ArrayDeque8Test.java | 3 ++- test/jdk/java/util/concurrent/tck/JSR166TestCase.java | 8 ++++---- 15 files changed, 51 insertions(+), 41 deletions(-) diff --git a/src/java.base/share/classes/java/io/InputStream.java b/src/java.base/share/classes/java/io/InputStream.java index 736b6ebd90435..a87870bfce0dd 100644 --- a/src/java.base/share/classes/java/io/InputStream.java +++ b/src/java.base/share/classes/java/io/InputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package java.io; +import jdk.internal.util.ArraysSupport; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -305,12 +307,9 @@ public int read(byte[] b, int off, int len) throws IOException { } /** - * The maximum size of array to allocate. - * Some VMs reserve some header words in an array. - * Attempts to allocate larger arrays may result in - * OutOfMemoryError: Requested array size exceeds VM limit + * The maximum size of array to allocate */ - private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; + private static final int MAX_BUFFER_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; /** * Reads all remaining bytes from the input stream. This method blocks until diff --git a/src/java.base/share/classes/java/util/ArrayDeque.java b/src/java.base/share/classes/java/util/ArrayDeque.java index 9997110b658ee..60bb3ed4a4572 100644 --- a/src/java.base/share/classes/java/util/ArrayDeque.java +++ b/src/java.base/share/classes/java/util/ArrayDeque.java @@ -38,6 +38,7 @@ import java.util.function.Consumer; import java.util.function.Predicate; import jdk.internal.access.SharedSecrets; +import jdk.internal.util.ArraysSupport; /** * Resizable-array implementation of the {@link Deque} interface. Array @@ -124,12 +125,9 @@ public class ArrayDeque extends AbstractCollection transient int tail; /** - * The maximum size of array to allocate. - * Some VMs reserve some header words in an array. - * Attempts to allocate larger arrays may result in - * OutOfMemoryError: Requested array size exceeds VM limit + * The maximum size of array to allocate */ - private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + private static final int MAX_ARRAY_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; /** * Increases the capacity of this deque by at least the given amount. diff --git a/src/java.base/share/classes/java/util/BitSet.java b/src/java.base/share/classes/java/util/BitSet.java index fea9693d7ed0d..de4910b20c6d5 100644 --- a/src/java.base/share/classes/java/util/BitSet.java +++ b/src/java.base/share/classes/java/util/BitSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1184,7 +1184,7 @@ private void readObject(ObjectInputStream s) public String toString() { checkInvariants(); - final int MAX_INITIAL_CAPACITY = Integer.MAX_VALUE - 8; + final int MAX_INITIAL_CAPACITY = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; int numBits = (wordsInUse > 128) ? cardinality() : wordsInUse * BITS_PER_WORD; // Avoid overflow in the case of a humongous numBits diff --git a/src/java.base/share/classes/java/util/Hashtable.java b/src/java.base/share/classes/java/util/Hashtable.java index 1fd56d5a258e5..ddff8f7a0ab68 100644 --- a/src/java.base/share/classes/java/util/Hashtable.java +++ b/src/java.base/share/classes/java/util/Hashtable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ import java.util.function.Function; import java.util.function.BiFunction; import jdk.internal.access.SharedSecrets; +import jdk.internal.util.ArraysSupport; /** * This class implements a hash table, which maps keys to values. Any @@ -390,12 +391,9 @@ public synchronized V get(Object key) { } /** - * The maximum size of array to allocate. - * Some VMs reserve some header words in an array. - * Attempts to allocate larger arrays may result in - * OutOfMemoryError: Requested array size exceeds VM limit + * The maximum size of array to allocate */ - private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + private static final int MAX_ARRAY_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; /** * Increases the capacity of and internally reorganizes this diff --git a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java index 4df4f73695f62..5a23fdb05a656 100644 --- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java +++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java @@ -69,6 +69,7 @@ import java.util.function.ToLongFunction; import java.util.stream.Stream; import jdk.internal.misc.Unsafe; +import jdk.internal.util.ArraysSupport; /** * A hash table supporting full concurrency of retrievals and @@ -517,7 +518,7 @@ public class ConcurrentHashMap extends AbstractMap * The largest possible (non-power of two) array size. * Needed by toArray and related methods. */ - static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + static final int MAX_ARRAY_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; /** * The default concurrency level for this table. Unused but diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java index 0e87bebdcbfec..654adb5376f48 100644 --- a/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/src/java.base/share/classes/java/util/regex/Pattern.java @@ -1502,8 +1502,8 @@ public static String quote(String s) { return "\\Q" + s + "\\E"; int lenHint = s.length(); - lenHint = (lenHint < Integer.MAX_VALUE - 8 - lenHint) ? - (lenHint << 1) : (Integer.MAX_VALUE - 8); + lenHint = (lenHint < ArraysSupport.SOFT_MAX_ARRAY_LENGTH - lenHint) ? + (lenHint << 1) : ArraysSupport.SOFT_MAX_ARRAY_LENGTH; StringBuilder sb = new StringBuilder(lenHint); sb.append("\\Q"); diff --git a/src/java.base/share/classes/java/util/stream/Nodes.java b/src/java.base/share/classes/java/util/stream/Nodes.java index 7c06823b925e7..77d700917179e 100644 --- a/src/java.base/share/classes/java/util/stream/Nodes.java +++ b/src/java.base/share/classes/java/util/stream/Nodes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ */ package java.util.stream; +import jdk.internal.util.ArraysSupport; + import java.util.ArrayDeque; import java.util.Arrays; import java.util.Collection; @@ -57,7 +59,7 @@ private Nodes() { /** * The maximum size of an array that can be allocated. */ - static final long MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + static final long MAX_ARRAY_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; // IllegalArgumentException messages static final String BAD_SIZE = "Stream size exceeds max array size"; 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 64994af5cb790..c3b6295853fc6 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -379,7 +379,7 @@ private int checkArraySize(String typeName, int elemSize) { throw new IllegalStateException(String.format("Segment size is not a multiple of %d. Size: %d", elemSize, length)); } long arraySize = length / elemSize; - if (arraySize > (Integer.MAX_VALUE - 8)) { //conservative check + if (arraySize > ArraysSupport.SOFT_MAX_ARRAY_LENGTH) { //conservative check throw new IllegalStateException(String.format("Segment is too large to wrap as %s. Size: %d", typeName, length)); } return (int)arraySize; diff --git a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java index 1e204816bd65f..1576388b65322 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java +++ b/src/java.base/share/classes/sun/security/util/SignatureFileVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ import java.util.jar.Attributes; import java.util.jar.Manifest; +import jdk.internal.util.ArraysSupport; import sun.security.action.GetIntegerAction; import sun.security.jca.Providers; import sun.security.pkcs.PKCS7; @@ -87,8 +88,8 @@ public class SignatureFileVerifier { // the maximum allowed size in bytes for the signature-related files public static final int MAX_SIG_FILE_SIZE = initializeMaxSigFileSize(); - // The maximum size of array to allocate. Some VMs reserve some header words in an array. - private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + // The maximum size of array to allocate + private static final int MAX_ARRAY_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; /** * Create the named SignatureFileVerifier. diff --git a/test/jdk/java/lang/StringBuffer/HugeCapacity.java b/test/jdk/java/lang/StringBuffer/HugeCapacity.java index e3c98496c50c8..d1ff51dddb2cf 100644 --- a/test/jdk/java/lang/StringBuffer/HugeCapacity.java +++ b/test/jdk/java/lang/StringBuffer/HugeCapacity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,11 +21,14 @@ * questions. */ +import jdk.internal.util.ArraysSupport; + /** * @test * @bug 8218227 * @summary StringBuilder/StringBuffer constructor throws confusing * NegativeArraySizeException + * @modules java.base/jdk.internal.util * @requires (sun.arch.data.model == "64" & os.maxMemory >= 8G) * @run main/othervm -Xms6G -Xmx6G HugeCapacity */ @@ -43,7 +46,7 @@ public static void main(String[] args) { private static void testHugeInitialString() { try { - String str = "Z".repeat(Integer.MAX_VALUE - 8); + String str = "Z".repeat(ArraysSupport.SOFT_MAX_ARRAY_LENGTH); StringBuffer sb = new StringBuffer(str); } catch (OutOfMemoryError ignore) { } catch (Throwable unexpected) { diff --git a/test/jdk/java/lang/StringBuilder/HugeCapacity.java b/test/jdk/java/lang/StringBuilder/HugeCapacity.java index a584ce1f07a9d..a81f1614fe590 100644 --- a/test/jdk/java/lang/StringBuilder/HugeCapacity.java +++ b/test/jdk/java/lang/StringBuilder/HugeCapacity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,11 +21,14 @@ * questions. */ +import jdk.internal.util.ArraysSupport; + /** * @test * @bug 8149330 8218227 * @summary Capacity should not get close to Integer.MAX_VALUE unless * necessary + * @modules java.base/jdk.internal.util * @requires (sun.arch.data.model == "64" & os.maxMemory >= 8G) * @run main/othervm -Xms6G -Xmx6G -XX:+CompactStrings HugeCapacity true * @run main/othervm -Xms6G -Xmx6G -XX:-CompactStrings HugeCapacity false @@ -75,7 +78,7 @@ private static void testUtf16() { private static void testHugeInitialString() { try { - String str = "Z".repeat(Integer.MAX_VALUE - 8); + String str = "Z".repeat(ArraysSupport.SOFT_MAX_ARRAY_LENGTH); StringBuilder sb = new StringBuilder(str); } catch (OutOfMemoryError ignore) { } catch (Throwable unexpected) { diff --git a/test/jdk/java/nio/charset/CharsetDecoder/XcodeOverflow.java b/test/jdk/java/nio/charset/CharsetDecoder/XcodeOverflow.java index 7570da3945cef..197b61c0ac561 100644 --- a/test/jdk/java/nio/charset/CharsetDecoder/XcodeOverflow.java +++ b/test/jdk/java/nio/charset/CharsetDecoder/XcodeOverflow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ * @summary Make sure IAE is not thrown on `int` overflow, turning negative * size. The test should either not throw any Throwable, or an OOME * with real Java heap space error (not "exceeds VM limit"). + * @modules java.base/jdk.internal.util * @requires sun.arch.data.model == "64" * @run junit/othervm XcodeOverflow */ @@ -37,6 +38,7 @@ import java.nio.charset.StandardCharsets; import java.util.stream.Stream; +import jdk.internal.util.ArraysSupport; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.Arguments; @@ -44,8 +46,8 @@ public class XcodeOverflow { private static Stream sizes() { return Stream.of( - // SOFT_MAX_ARRAY_LENGTH: copied from ArraysSupport. No overflow; no OOME. - Arguments.of(Integer.MAX_VALUE - 8), + // No overflow; no OOME. + Arguments.of(ArraysSupport.SOFT_MAX_ARRAY_LENGTH), // overflow case: OOME w/ "Java heap space" is thrown on decoding Arguments.of(Integer.MAX_VALUE - 1000000) diff --git a/test/jdk/java/util/Base64/TestEncodingDecodingLength.java b/test/jdk/java/util/Base64/TestEncodingDecodingLength.java index ce6d0db4adc5e..452f11ebea9e8 100644 --- a/test/jdk/java/util/Base64/TestEncodingDecodingLength.java +++ b/test/jdk/java/util/Base64/TestEncodingDecodingLength.java @@ -21,6 +21,7 @@ * questions. */ +import jdk.internal.util.ArraysSupport; import org.junit.jupiter.api.Test; import java.lang.reflect.InvocationTargetException; @@ -37,6 +38,7 @@ * Base64.Decoder.decode behavior with large, (Integer.MAX_VALUE) sized * input array/buffer. Tests the private methods "encodedOutLength" and * "decodedOutLength". + * @modules java.base/jdk.internal.util * @run junit/othervm --add-opens java.base/java.util=ALL-UNNAMED TestEncodingDecodingLength */ @@ -45,7 +47,7 @@ public class TestEncodingDecodingLength { // A value large enough to test the desired memory conditions in encode and decode - private static final int LARGE_MEM_SIZE = Integer.MAX_VALUE - 8; + private static final int LARGE_MEM_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; private static final Base64.Decoder DECODER = Base64.getDecoder(); private static final Base64.Encoder ENCODER = Base64.getEncoder(); diff --git a/test/jdk/java/util/concurrent/tck/ArrayDeque8Test.java b/test/jdk/java/util/concurrent/tck/ArrayDeque8Test.java index eb606b0c7818e..fb21ebfed36ff 100644 --- a/test/jdk/java/util/concurrent/tck/ArrayDeque8Test.java +++ b/test/jdk/java/util/concurrent/tck/ArrayDeque8Test.java @@ -36,6 +36,7 @@ import java.util.Collections; import java.util.Spliterator; +import jdk.internal.util.ArraysSupport; import junit.framework.Test; public class ArrayDeque8Test extends JSR166TestCase { @@ -86,7 +87,7 @@ public void testHugeCapacity() { return; final Item e = fortytwo; - final int maxArraySize = Integer.MAX_VALUE - 8; + final int maxArraySize = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; assertThrows(OutOfMemoryError.class, () -> new ArrayDeque(Integer.MAX_VALUE)); diff --git a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java index 451864bcf5d89..19897fa0785ef 100644 --- a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java +++ b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java @@ -38,7 +38,7 @@ * @test id=default * @summary Conformance testing variant of JSR-166 tck tests. * @build * - * @modules java.management + * @modules java.management java.base/jdk.internal.util * @run junit/othervm/timeout=1000 JSR166TestCase */ @@ -47,7 +47,7 @@ * @summary Conformance testing variant of JSR-166 tck tests * with java security manager set to allow. * @build * - * @modules java.management + * @modules java.management java.base/jdk.internal.util * @run junit/othervm/timeout=1000 -Djava.security.manager=allow JSR166TestCase */ @@ -56,7 +56,7 @@ * @summary Test implementation details variant of JSR-166 * tck tests with ForkJoinPool common parallelism. * @build * - * @modules java.management + * @modules java.management java.base/jdk.internal.util * @run junit/othervm/timeout=1000 * --add-opens java.base/java.util.concurrent=ALL-UNNAMED * --add-opens java.base/java.lang=ALL-UNNAMED @@ -78,7 +78,7 @@ * JSR-166 tck tests apart from ForkJoinPool common * parallelism. * @build * - * @modules java.management + * @modules java.management java.base/jdk.internal.util * @run junit/othervm/timeout=1000 * --add-opens java.base/java.util.concurrent=ALL-UNNAMED * --add-opens java.base/java.lang=ALL-UNNAMED From 39c17b392699007496816f788fca9fbe670dd6f8 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Wed, 2 Oct 2024 03:30:02 +0000 Subject: [PATCH 089/188] 8341277: Validate slot argument for instruction factories Reviewed-by: asotona --- .../java/lang/classfile/CodeBuilder.java | 25 +++ .../instruction/DiscontinuedInstruction.java | 6 +- .../instruction/IncrementInstruction.java | 1 + .../instruction/LoadInstruction.java | 8 +- .../classfile/instruction/LocalVariable.java | 2 + .../instruction/LocalVariableType.java | 2 + .../instruction/NewMultiArrayInstruction.java | 3 + .../instruction/StoreInstruction.java | 8 +- .../classfile/impl/AbstractInstruction.java | 8 +- .../impl/AbstractPseudoInstruction.java | 1 + .../classfile/impl/BytecodeHelpers.java | 131 ++++++++++++- .../jdk/internal/classfile/impl/CodeImpl.java | 4 +- .../classfile/impl/DirectCodeBuilder.java | 14 +- .../classfile/InstructionValidationTest.java | 182 ++++++++++++++++++ .../jdk/classfile/OpcodesValidationTest.java | 51 ----- 15 files changed, 366 insertions(+), 80 deletions(-) create mode 100644 test/jdk/jdk/classfile/InstructionValidationTest.java delete mode 100644 test/jdk/jdk/classfile/OpcodesValidationTest.java diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index 16f513801a249..7b27238bbdfae 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -429,6 +429,8 @@ default CodeBuilder trying(Consumer tryHandler, * @param tk the load type * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code tk} is {@link TypeKind#VOID void} + * or {@code slot} is out of range * @since 23 */ default CodeBuilder loadLocal(TypeKind tk, int slot) { @@ -440,6 +442,8 @@ default CodeBuilder loadLocal(TypeKind tk, int slot) { * @param tk the store type * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code tk} is {@link TypeKind#VOID void} + * or {@code slot} is out of range * @since 23 */ default CodeBuilder storeLocal(TypeKind tk, int slot) { @@ -793,6 +797,7 @@ default CodeBuilder characterRange(Label startScope, Label endScope, int charact * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder localVariable(int slot, Utf8Entry nameEntry, Utf8Entry descriptorEntry, Label startScope, Label endScope) { return with(LocalVariable.of(slot, nameEntry, descriptorEntry, startScope, endScope)); @@ -806,6 +811,7 @@ default CodeBuilder localVariable(int slot, Utf8Entry nameEntry, Utf8Entry descr * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder localVariable(int slot, String name, ClassDesc descriptor, Label startScope, Label endScope) { return localVariable(slot, @@ -822,6 +828,7 @@ default CodeBuilder localVariable(int slot, String name, ClassDesc descriptor, L * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder localVariableType(int slot, Utf8Entry nameEntry, Utf8Entry signatureEntry, Label startScope, Label endScope) { return with(LocalVariableType.of(slot, nameEntry, signatureEntry, startScope, endScope)); @@ -835,6 +842,7 @@ default CodeBuilder localVariableType(int slot, Utf8Entry nameEntry, Utf8Entry s * @param startScope the start scope of the variable * @param endScope the end scope of the variable * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder localVariableType(int slot, String name, Signature signature, Label startScope, Label endScope) { return localVariableType(slot, @@ -877,6 +885,7 @@ default CodeBuilder aastore() { * * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder aload(int slot) { return loadLocal(TypeKind.REFERENCE, slot); @@ -925,6 +934,7 @@ default CodeBuilder arraylength() { * * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder astore(int slot) { return storeLocal(TypeKind.REFERENCE, slot); @@ -958,6 +968,7 @@ default CodeBuilder bastore() { * Generate an instruction pushing an int in the range of byte onto the operand stack. * @param b the int in the range of byte * @return this builder + * @throws IllegalArgumentException if {@code b} is out of range of byte */ default CodeBuilder bipush(int b) { return with(ConstantInstruction.ofArgument(Opcode.BIPUSH, b)); @@ -1094,6 +1105,7 @@ default CodeBuilder ddiv() { * * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder dload(int slot) { return loadLocal(TypeKind.DOUBLE, slot); @@ -1139,6 +1151,7 @@ default CodeBuilder dreturn() { * * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder dstore(int slot) { return storeLocal(TypeKind.DOUBLE, slot); @@ -1306,6 +1319,7 @@ default CodeBuilder fdiv() { * * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder fload(int slot) { return loadLocal(TypeKind.FLOAT, slot); @@ -1351,6 +1365,7 @@ default CodeBuilder freturn() { * * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder fstore(int slot) { return storeLocal(TypeKind.FLOAT, slot); @@ -1726,6 +1741,7 @@ default CodeBuilder ifne(Label target) { * @param slot the local variable slot * @param val the increment value * @return this builder + * @throws IllegalArgumentException if {@code slot} or {@code val} is out of range */ default CodeBuilder iinc(int slot, int val) { return with(IncrementInstruction.of(slot, val)); @@ -1739,6 +1755,7 @@ default CodeBuilder iinc(int slot, int val) { * * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder iload(int slot) { return loadLocal(TypeKind.INT, slot); @@ -1997,6 +2014,7 @@ default CodeBuilder ishr() { * * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder istore(int slot) { return storeLocal(TypeKind.INT, slot); @@ -2159,6 +2177,7 @@ default CodeBuilder ldiv() { * * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder lload(int slot) { return loadLocal(TypeKind.LONG, slot); @@ -2228,6 +2247,7 @@ default CodeBuilder lshr() { * * @param slot the local variable slot * @return this builder + * @throws IllegalArgumentException if {@code slot} is out of range */ default CodeBuilder lstore(int slot) { return storeLocal(TypeKind.LONG, slot); @@ -2278,6 +2298,7 @@ default CodeBuilder monitorexit() { * @param array the array type * @param dims the number of dimensions * @return this builder + * @throws IllegalArgumentException if {@code dims} is out of range */ default CodeBuilder multianewarray(ClassEntry array, int dims) { return with(NewMultiArrayInstruction.of(array, dims)); @@ -2289,6 +2310,7 @@ default CodeBuilder multianewarray(ClassEntry array, int dims) { * @param dims the number of dimensions * @return this builder * @throws IllegalArgumentException if {@code array} represents a primitive type + * or if {@code dims} is out of range */ default CodeBuilder multianewarray(ClassDesc array, int dims) { return multianewarray(constantPool().classEntry(array), dims); @@ -2327,6 +2349,8 @@ default CodeBuilder new_(ClassDesc clazz) { * Generate an instruction to create a new array of a primitive type * @param typeKind the primitive array type * @return this builder + * @throws IllegalArgumentException when the {@code typeKind} is not a legal + * primitive array component type */ default CodeBuilder newarray(TypeKind typeKind) { return with(NewPrimitiveArrayInstruction.of(typeKind)); @@ -2423,6 +2447,7 @@ default CodeBuilder sastore() { * Generate an instruction pushing an int in the range of short onto the operand stack. * @param s the int in the range of short * @return this builder + * @throws IllegalArgumentException if {@code s} is out of range of short */ default CodeBuilder sipush(int s) { return with(ConstantInstruction.ofArgument(Opcode.SIPUSH, s)); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java index 61ea14c459884..84bead6d8ccb4 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/DiscontinuedInstruction.java @@ -30,6 +30,7 @@ import java.lang.classfile.Label; import java.lang.classfile.Opcode; import jdk.internal.classfile.impl.AbstractInstruction; +import jdk.internal.classfile.impl.BytecodeHelpers; import jdk.internal.classfile.impl.Util; import jdk.internal.javac.PreviewFeature; @@ -112,10 +113,10 @@ sealed interface RetInstruction extends DiscontinuedInstruction * which must be of kind {@link Opcode.Kind#DISCONTINUED_RET} * @param slot the local variable slot to load return address from * @throws IllegalArgumentException if the opcode kind is not - * {@link Opcode.Kind#DISCONTINUED_RET}. + * {@link Opcode.Kind#DISCONTINUED_RET} or if {@code slot} is out of range */ static RetInstruction of(Opcode op, int slot) { - Util.checkKind(op, Opcode.Kind.DISCONTINUED_RET); + BytecodeHelpers.validateRet(op, slot); return new AbstractInstruction.UnboundRetInstruction(op, slot); } @@ -123,6 +124,7 @@ static RetInstruction of(Opcode op, int slot) { * {@return a RET instruction} * * @param slot the local variable slot to load return address from + * @throws IllegalArgumentException if {@code slot} is out of range */ static RetInstruction of(int slot) { return of(slot < 256 ? Opcode.RET : Opcode.RET_W, slot); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java index 3bde87ee48dbc..bebb101d7f326 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/IncrementInstruction.java @@ -58,6 +58,7 @@ public sealed interface IncrementInstruction extends Instruction * * @param slot the local variable slot to increment * @param constant the value to increment by + * @throws IllegalArgumentException if {@code slot} or {@code constant} is out of range */ static IncrementInstruction of(int slot, int constant) { return new AbstractInstruction.UnboundIncrementInstruction(slot, constant); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java index f4cc8bab794fb..ea10ba6a0d0fb 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LoadInstruction.java @@ -62,9 +62,12 @@ public sealed interface LoadInstruction extends Instruction * * @param kind the type of the value to be loaded * @param slot the local variable slot to load from + * @throws IllegalArgumentException if {@code kind} is + * {@link TypeKind#VOID void} or {@code slot} is out of range */ static LoadInstruction of(TypeKind kind, int slot) { - return of(BytecodeHelpers.loadOpcode(kind, slot), slot); + var opcode = BytecodeHelpers.loadOpcode(kind, slot); // validates slot, trusted + return new AbstractInstruction.UnboundLoadInstruction(opcode, slot); } /** @@ -74,10 +77,11 @@ static LoadInstruction of(TypeKind kind, int slot) { * which must be of kind {@link Opcode.Kind#LOAD} * @param slot the local variable slot to load from * @throws IllegalArgumentException if the opcode kind is not - * {@link Opcode.Kind#LOAD}. + * {@link Opcode.Kind#LOAD} or {@code slot} is out of range */ static LoadInstruction of(Opcode op, int slot) { Util.checkKind(op, Opcode.Kind.LOAD); + BytecodeHelpers.validateSlot(op, slot, true); return new AbstractInstruction.UnboundLoadInstruction(op, slot); } } diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java index 84a8599315218..390034bd6663d 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariable.java @@ -92,6 +92,7 @@ default ClassDesc typeSymbol() { * @param descriptorEntry the local variable descriptor * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope + * @throws IllegalArgumentException if {@code slot} is out of range */ static LocalVariable of(int slot, Utf8Entry nameEntry, Utf8Entry descriptorEntry, Label startScope, Label endScope) { return new AbstractPseudoInstruction.UnboundLocalVariable(slot, nameEntry, descriptorEntry, @@ -106,6 +107,7 @@ static LocalVariable of(int slot, Utf8Entry nameEntry, Utf8Entry descriptorEntry * @param descriptor the local variable descriptor * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope + * @throws IllegalArgumentException if {@code slot} is out of range */ static LocalVariable of(int slot, String name, ClassDesc descriptor, Label startScope, Label endScope) { return of(slot, diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java index 4409abe6db272..d0d2cd1581fe0 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/LocalVariableType.java @@ -89,6 +89,7 @@ default Signature signatureSymbol() { * @param signatureEntry the local variable signature * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope + * @throws IllegalArgumentException if {@code slot} is out of range */ static LocalVariableType of(int slot, Utf8Entry nameEntry, Utf8Entry signatureEntry, Label startScope, Label endScope) { return new AbstractPseudoInstruction.UnboundLocalVariableType(slot, nameEntry, signatureEntry, @@ -103,6 +104,7 @@ static LocalVariableType of(int slot, Utf8Entry nameEntry, Utf8Entry signatureEn * @param signature the local variable signature * @param startScope the start range of the local variable scope * @param endScope the end range of the local variable scope + * @throws IllegalArgumentException if {@code slot} is out of range */ static LocalVariableType of(int slot, String name, Signature signature, Label startScope, Label endScope) { return of(slot, diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java index 2f45b96760361..2c572c607b4f4 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/NewMultiArrayInstruction.java @@ -29,6 +29,7 @@ import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.Instruction; import jdk.internal.classfile.impl.AbstractInstruction; +import jdk.internal.classfile.impl.BytecodeHelpers; import jdk.internal.javac.PreviewFeature; /** @@ -58,9 +59,11 @@ public sealed interface NewMultiArrayInstruction extends Instruction * * @param arrayTypeEntry the type of the array * @param dimensions the number of dimensions of the array + * @throws IllegalArgumentException if {@code dimensions} is out of range */ static NewMultiArrayInstruction of(ClassEntry arrayTypeEntry, int dimensions) { + BytecodeHelpers.validateMultiArrayDimensions(dimensions); return new AbstractInstruction.UnboundNewMultidimensionalArrayInstruction(arrayTypeEntry, dimensions); } } diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java index 278bf8c0ec399..5bfe13421da35 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/StoreInstruction.java @@ -61,9 +61,12 @@ public sealed interface StoreInstruction extends Instruction * * @param kind the type of the value to be stored * @param slot the local variable slot to store to + * @throws IllegalArgumentException if {@code kind} is {@link + * TypeKind#VOID void} or {@code slot} is out of range */ static StoreInstruction of(TypeKind kind, int slot) { - return of(BytecodeHelpers.storeOpcode(kind, slot), slot); + var opcode = BytecodeHelpers.storeOpcode(kind, slot); // validates slot + return new AbstractInstruction.UnboundStoreInstruction(opcode, slot); } /** @@ -73,10 +76,11 @@ static StoreInstruction of(TypeKind kind, int slot) { * which must be of kind {@link Opcode.Kind#STORE} * @param slot the local variable slot to store to * @throws IllegalArgumentException if the opcode kind is not - * {@link Opcode.Kind#STORE}. + * {@link Opcode.Kind#STORE} or {@code slot} is out of range */ static StoreInstruction of(Opcode op, int slot) { Util.checkKind(op, Opcode.Kind.STORE); + BytecodeHelpers.validateSlot(op, slot, false); return new AbstractInstruction.UnboundStoreInstruction(op, slot); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index edcd6a7abff25..d325842793705 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java @@ -848,9 +848,9 @@ public static final class UnboundIncrementInstruction final int constant; public UnboundIncrementInstruction(int slot, int constant) { - super(slot <= 255 && constant < 128 && constant > -127 - ? Opcode.IINC - : Opcode.IINC_W); + super(BytecodeHelpers.validateAndIsWideIinc(slot, constant) + ? Opcode.IINC_W + : Opcode.IINC); this.slot = slot; this.constant = constant; } @@ -867,7 +867,7 @@ public int constant() { @Override public void writeTo(DirectCodeBuilder writer) { - writer.writeIncrement(slot, constant); + writer.writeIncrement(op == Opcode.IINC_W, slot, constant); } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java index 00d817b8cb0cb..dc170ce72b501 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPseudoInstruction.java @@ -163,6 +163,7 @@ private abstract static sealed class AbstractLocalPseudo extends AbstractPseudoI protected final Label endScope; public AbstractLocalPseudo(int slot, Utf8Entry name, Utf8Entry descriptor, Label startScope, Label endScope) { + BytecodeHelpers.validateSlot(slot); this.slot = slot; this.name = name; this.descriptor = descriptor; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index a5b4b55b05b27..6994a62c0ab06 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -45,6 +45,7 @@ import java.lang.classfile.constantpool.MemberRefEntry; import java.lang.classfile.constantpool.MethodHandleEntry; import java.lang.classfile.constantpool.NameAndTypeEntry; +import java.util.Objects; import static jdk.internal.classfile.impl.RawBytecodeHelper.*; @@ -60,6 +61,14 @@ public static IllegalArgumentException cannotConvertException(TypeKind from, Typ return new IllegalArgumentException(String.format("convert %s -> %s", from, to)); } + public static IllegalArgumentException slotOutOfBounds(int slot) { + return new IllegalArgumentException("Invalid slot index :".concat(Integer.toString(slot))); + } + + public static IllegalArgumentException slotOutOfBounds(Opcode opcode, int slot) { + return new IllegalArgumentException("Invalid slot index %d for %s".formatted(slot, opcode)); + } + public static Opcode loadOpcode(TypeKind tk, int slot) { return switch (tk) { case INT, SHORT, BYTE, CHAR, BOOLEAN @@ -78,7 +87,13 @@ public static Opcode aload(int slot) { case 1 -> Opcode.ALOAD_1; case 2 -> Opcode.ALOAD_2; case 3 -> Opcode.ALOAD_3; - default -> (slot < 256) ? Opcode.ALOAD : Opcode.ALOAD_W; + default -> { + if ((slot & 0xFF) == slot) + yield Opcode.ALOAD; + if ((slot & 0xFFFF) == slot) + yield Opcode.ALOAD_W; + throw slotOutOfBounds(slot); + } }; } @@ -88,7 +103,13 @@ public static Opcode fload(int slot) { case 1 -> Opcode.FLOAD_1; case 2 -> Opcode.FLOAD_2; case 3 -> Opcode.FLOAD_3; - default -> (slot < 256) ? Opcode.FLOAD : Opcode.FLOAD_W; + default -> { + if ((slot & 0xFF) == slot) + yield Opcode.FLOAD; + if ((slot & 0xFFFF) == slot) + yield Opcode.FLOAD_W; + throw slotOutOfBounds(slot); + } }; } @@ -98,7 +119,13 @@ public static Opcode dload(int slot) { case 1 -> Opcode.DLOAD_1; case 2 -> Opcode.DLOAD_2; case 3 -> Opcode.DLOAD_3; - default -> (slot < 256) ? Opcode.DLOAD : Opcode.DLOAD_W; + default -> { + if ((slot & 0xFF) == slot) + yield Opcode.DLOAD; + if ((slot & 0xFFFF) == slot) + yield Opcode.DLOAD_W; + throw slotOutOfBounds(slot); + } }; } @@ -108,7 +135,13 @@ public static Opcode lload(int slot) { case 1 -> Opcode.LLOAD_1; case 2 -> Opcode.LLOAD_2; case 3 -> Opcode.LLOAD_3; - default -> (slot < 256) ? Opcode.LLOAD : Opcode.LLOAD_W; + default -> { + if ((slot & 0xFF) == slot) + yield Opcode.LLOAD; + if ((slot & 0xFFFF) == slot) + yield Opcode.LLOAD_W; + throw slotOutOfBounds(slot); + } }; } @@ -118,7 +151,13 @@ public static Opcode iload(int slot) { case 1 -> Opcode.ILOAD_1; case 2 -> Opcode.ILOAD_2; case 3 -> Opcode.ILOAD_3; - default -> (slot < 256) ? Opcode.ILOAD : Opcode.ILOAD_W; + default -> { + if ((slot & 0xFF) == slot) + yield Opcode.ILOAD; + if ((slot & 0xFFFF) == slot) + yield Opcode.ILOAD_W; + throw slotOutOfBounds(slot); + } }; } @@ -140,7 +179,13 @@ public static Opcode astore(int slot) { case 1 -> Opcode.ASTORE_1; case 2 -> Opcode.ASTORE_2; case 3 -> Opcode.ASTORE_3; - default -> (slot < 256) ? Opcode.ASTORE : Opcode.ASTORE_W; + default -> { + if ((slot & 0xFF) == slot) + yield Opcode.ASTORE; + if ((slot & 0xFFFF) == slot) + yield Opcode.ASTORE_W; + throw slotOutOfBounds(slot); + } }; } @@ -150,7 +195,13 @@ public static Opcode fstore(int slot) { case 1 -> Opcode.FSTORE_1; case 2 -> Opcode.FSTORE_2; case 3 -> Opcode.FSTORE_3; - default -> (slot < 256) ? Opcode.FSTORE : Opcode.FSTORE_W; + default -> { + if ((slot & 0xFF) == slot) + yield Opcode.FSTORE; + if ((slot & 0xFFFF) == slot) + yield Opcode.FSTORE_W; + throw slotOutOfBounds(slot); + } }; } @@ -160,7 +211,13 @@ public static Opcode dstore(int slot) { case 1 -> Opcode.DSTORE_1; case 2 -> Opcode.DSTORE_2; case 3 -> Opcode.DSTORE_3; - default -> (slot < 256) ? Opcode.DSTORE : Opcode.DSTORE_W; + default -> { + if ((slot & 0xFF) == slot) + yield Opcode.DSTORE; + if ((slot & 0xFFFF) == slot) + yield Opcode.DSTORE_W; + throw slotOutOfBounds(slot); + } }; } @@ -170,7 +227,13 @@ public static Opcode lstore(int slot) { case 1 -> Opcode.LSTORE_1; case 2 -> Opcode.LSTORE_2; case 3 -> Opcode.LSTORE_3; - default -> (slot < 256) ? Opcode.LSTORE : Opcode.LSTORE_W; + default -> { + if ((slot & 0xFF) == slot) + yield Opcode.LSTORE; + if ((slot & 0xFFFF) == slot) + yield Opcode.LSTORE_W; + throw slotOutOfBounds(slot); + } }; } @@ -180,7 +243,13 @@ public static Opcode istore(int slot) { case 1 -> Opcode.ISTORE_1; case 2 -> Opcode.ISTORE_2; case 3 -> Opcode.ISTORE_3; - default -> (slot < 256) ? Opcode.ISTORE : Opcode.ISTORE_W; + default -> { + if ((slot & 0xFF) == slot) + yield Opcode.ISTORE; + if ((slot & 0xFFFF) == slot) + yield Opcode.ISTORE_W; + throw slotOutOfBounds(slot); + } }; } @@ -305,6 +374,48 @@ public static TypeKind convertToType(Opcode opcode) { }; } + public static void validateSlot(Opcode opcode, int slot, boolean load) { + int size = opcode.sizeIfFixed(); + if (size == 1 && slot == (load ? intrinsicLoadSlot(opcode) : intrinsicStoreSlot(opcode)) || + size == 2 && slot == (slot & 0xFF) || + size == 4 && slot == (slot & 0xFFFF)) + return; + throw slotOutOfBounds(opcode, slot); + } + + public static void validateSlot(int slot) { + if ((slot & 0xFFFF) != slot) + throw slotOutOfBounds(slot); + } + + public static boolean validateAndIsWideIinc(int slot, int val) { + var ret = false; + if ((slot & 0xFF) != slot) { + validateSlot(slot); + ret = true; + } + if ((byte) val != val) { + if ((short) val != val) { + throw new IllegalArgumentException("cannot encode as S2: ".concat(String.valueOf(val))); + } + ret = true; + } + return ret; + } + + public static void validateRet(Opcode opcode, int slot) { + if (opcode == Opcode.RET && slot == (slot & 0xFF) || + opcode == Opcode.RET_W && slot == (slot & 0xFFFF)) + return; + Objects.requireNonNull(opcode); + throw slotOutOfBounds(opcode, slot); + } + + public static void validateMultiArrayDimensions(int value) { + if (value < 1 || value > 0xFF) + throw new IllegalArgumentException("Not a valid array dimension: ".concat(String.valueOf(value))); + } + public static void validateSipush(int value) { if (value != (short) value) throw new IllegalArgumentException( diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index 48394d3da96c3..aa9603b150855 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -55,13 +55,13 @@ public final class CodeImpl case ARRAY_STORE -> ArrayStoreInstruction.of(o); case CONSTANT -> ConstantInstruction.ofIntrinsic(o); case CONVERT -> ConvertInstruction.of(o); - case LOAD -> LoadInstruction.of(o, BytecodeHelpers.intrinsicLoadSlot(o)); + case LOAD -> new AbstractInstruction.UnboundLoadInstruction(o, BytecodeHelpers.intrinsicLoadSlot(o)); case MONITOR -> MonitorInstruction.of(o); case NOP -> NopInstruction.of(); case OPERATOR -> OperatorInstruction.of(o); case RETURN -> ReturnInstruction.of(o); case STACK -> StackInstruction.of(o); - case STORE -> StoreInstruction.of(o, BytecodeHelpers.intrinsicStoreSlot(o)); + case STORE -> new AbstractInstruction.UnboundStoreInstruction(o, BytecodeHelpers.intrinsicStoreSlot(o)); case THROW_EXCEPTION -> ThrowInstruction.of(); default -> throw new AssertionError("invalid opcode: " + o); }; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index 301b61241f71e..ee312a97dad80 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -506,12 +506,12 @@ public void writeLocalVar(Opcode opcode, int localVar) { } } - public void writeIncrement(int slot, int val) { - Opcode opcode = (slot < 256 && val < 128 && val > -127) - ? IINC - : IINC_W; - writeBytecode(opcode); - if (opcode.isWide()) { + public void writeIncrement(boolean wide, int slot, int val) { + if (wide) { + bytecodesBufWriter.writeU1(RawBytecodeHelper.WIDE); + } + bytecodesBufWriter.writeU1(RawBytecodeHelper.IINC); + if (wide) { bytecodesBufWriter.writeU2(slot); bytecodesBufWriter.writeU2(val); } else { @@ -1216,7 +1216,7 @@ public CodeBuilder idiv() { @Override public CodeBuilder iinc(int slot, int val) { - writeIncrement(slot, val); + writeIncrement(validateAndIsWideIinc(slot, val), slot, val); return this; } diff --git a/test/jdk/jdk/classfile/InstructionValidationTest.java b/test/jdk/jdk/classfile/InstructionValidationTest.java new file mode 100644 index 0000000000000..17210e1173b3a --- /dev/null +++ b/test/jdk/jdk/classfile/InstructionValidationTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8341277 + * @summary Testing ClassFile instruction argument validation. + * @run junit InstructionValidationTest + */ + +import java.lang.classfile.*; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.classfile.instruction.*; +import java.util.List; +import java.util.function.ObjIntConsumer; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +import static java.lang.constant.ConstantDescs.*; +import static org.junit.jupiter.api.Assertions.*; +import static java.lang.classfile.Opcode.*; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class InstructionValidationTest { + + @Test + void testArgumentConstant() { + assertDoesNotThrow(() -> ConstantInstruction.ofArgument(SIPUSH, 0)); + assertDoesNotThrow(() -> ConstantInstruction.ofArgument(SIPUSH, Short.MIN_VALUE)); + assertDoesNotThrow(() -> ConstantInstruction.ofArgument(SIPUSH, Short.MAX_VALUE)); + assertDoesNotThrow(() -> ConstantInstruction.ofArgument(BIPUSH, 0)); + assertDoesNotThrow(() -> ConstantInstruction.ofArgument(BIPUSH, Byte.MIN_VALUE)); + assertDoesNotThrow(() -> ConstantInstruction.ofArgument(BIPUSH, Byte.MAX_VALUE)); + + assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(SIPUSH, (int) Short.MIN_VALUE - 1)); + assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(SIPUSH, (int) Short.MAX_VALUE + 1)); + assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(BIPUSH, (int) Byte.MIN_VALUE - 1)); + assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(BIPUSH, (int) Byte.MAX_VALUE + 1)); + } + + /** + * Tests the bad slot argument IAE for load, store, increment, and ret. + */ + @Test + void testSlots() { + record Result(boolean shouldFail, int slot) { + } + + List badSlots = List.of(-1, 72694, -42, 0x10000, Integer.MIN_VALUE, Integer.MAX_VALUE); + List u2OnlySlots = List.of(0x100, 1000, 0xFFFF); + List u1Slots = List.of(0, 2, 15, 0xFF); + + List badU1Slots = Stream.concat(badSlots.stream(), u2OnlySlots.stream()).toList(); + List u2Slots = Stream.concat(u1Slots.stream(), u2OnlySlots.stream()).toList(); + List u2Cases = Stream.concat( + badSlots.stream().map(i -> new Result(true, i)), + u2Slots.stream().map(i -> new Result(false, i)) + ).toList(); + List u1Cases = Stream.concat( + badU1Slots.stream().map(i -> new Result(true, i)), + u1Slots.stream().map(i -> new Result(false, i)) + ).toList(); + List nonIntrinsicValues = Stream.of(badSlots, u2Slots, u1Slots).mapMulti(List::forEach) + .filter(i -> i < 0 || i > 3).toList(); + + Label[] capture = new Label[1]; + ClassFile.of().build(CD_Object, clb -> clb.withMethodBody("test", MTD_void, 0, cob -> { + capture[0] = cob.startLabel(); + cob.return_(); + })); + Label dummyLabel = capture[0]; + + List> cbFactories = List.of( + CodeBuilder::aload, + CodeBuilder::iload, + CodeBuilder::lload, + CodeBuilder::dload, + CodeBuilder::fload, + CodeBuilder::astore, + CodeBuilder::istore, + CodeBuilder::lstore, + CodeBuilder::dstore, + CodeBuilder::fstore + ); + + for (var r : u2Cases) { + var fails = r.shouldFail; + var i = r.slot; + for (var fac : cbFactories) { + //check(fails, () -> execute(cob -> fac.accept(cob, i))); + } + for (TypeKind tk : TypeKind.values()) { + if (tk == TypeKind.VOID) + continue; + //check(fails, () -> execute(cob -> cob.loadLocal(tk, i))); + //check(fails, () -> execute(cob -> cob.storeLocal(tk, i))); + check(fails, () -> LoadInstruction.of(tk, i)); + check(fails, () -> StoreInstruction.of(tk, i)); + } + //check(fails, () -> execute(cob -> cob.iinc(i, 1))); + check(fails, () -> IncrementInstruction.of(i, 1)); + check(fails, () -> DiscontinuedInstruction.RetInstruction.of(i)); + check(fails, () -> DiscontinuedInstruction.RetInstruction.of(RET_W, i)); + check(fails, () -> LocalVariable.of(i, "test", CD_Object, dummyLabel, dummyLabel)); + check(fails, () -> LocalVariableType.of(i, "test", Signature.of(CD_Object), dummyLabel, dummyLabel)); + } + + for (var r : u1Cases) { + var fails = r.shouldFail; + var i = r.slot; + for (var u1Op : List.of(ALOAD, ILOAD, LLOAD, FLOAD, DLOAD)) + check(fails, () -> LoadInstruction.of(u1Op, i)); + for (var u1Op : List.of(ASTORE, ISTORE, LSTORE, FSTORE, DSTORE)) + check(fails, () -> StoreInstruction.of(u1Op, i)); + check(fails, () -> DiscontinuedInstruction.RetInstruction.of(RET, i)); + } + + for (var i : nonIntrinsicValues) { + for (var intrinsicOp : List.of(ALOAD_0, ILOAD_0, LLOAD_0, FLOAD_0, DLOAD_0, ALOAD_1, ILOAD_1, LLOAD_1, FLOAD_1, DLOAD_1, + ALOAD_2, ILOAD_2, LLOAD_2, FLOAD_2, DLOAD_2, ALOAD_3, ILOAD_3, LLOAD_3, FLOAD_3, DLOAD_3)) { + assertThrows(IllegalArgumentException.class, () -> LoadInstruction.of(intrinsicOp, i)); + } + for (var intrinsicOp : List.of(ASTORE_0, ISTORE_0, LSTORE_0, FSTORE_0, DSTORE_0, ASTORE_1, ISTORE_1, LSTORE_1, FSTORE_1, DSTORE_1, + ASTORE_2, ISTORE_2, LSTORE_2, FSTORE_2, DSTORE_2, ASTORE_3, ISTORE_3, LSTORE_3, FSTORE_3, DSTORE_3)) { + assertThrows(IllegalArgumentException.class, () -> StoreInstruction.of(intrinsicOp, i)); + } + } + } + + static void check(boolean fails, Executable exec) { + if (fails) { + assertThrows(IllegalArgumentException.class, exec); + } else { + assertDoesNotThrow(exec); + } + } + + @Test + void testIincConstant() { + IncrementInstruction.of(0, 2); + IncrementInstruction.of(0, Short.MAX_VALUE); + IncrementInstruction.of(0, Short.MIN_VALUE); + assertThrows(IllegalArgumentException.class, () -> IncrementInstruction.of(0, Short.MAX_VALUE + 1)); + assertThrows(IllegalArgumentException.class, () -> IncrementInstruction.of(0, Short.MIN_VALUE - 1)); + } + + @Test + void testNewMultiArrayDimension() { + ClassEntry ce = ConstantPoolBuilder.of().classEntry(CD_Class); + NewMultiArrayInstruction.of(ce, 1); + NewMultiArrayInstruction.of(ce, 13); + NewMultiArrayInstruction.of(ce, 0xFF); + assertThrows(IllegalArgumentException.class, () -> NewMultiArrayInstruction.of(ce, 0)); + assertThrows(IllegalArgumentException.class, () -> NewMultiArrayInstruction.of(ce, 0x100)); + assertThrows(IllegalArgumentException.class, () -> NewMultiArrayInstruction.of(ce, -1)); + assertThrows(IllegalArgumentException.class, () -> NewMultiArrayInstruction.of(ce, Integer.MIN_VALUE)); + assertThrows(IllegalArgumentException.class, () -> NewMultiArrayInstruction.of(ce, Integer.MAX_VALUE)); + } +} diff --git a/test/jdk/jdk/classfile/OpcodesValidationTest.java b/test/jdk/jdk/classfile/OpcodesValidationTest.java deleted file mode 100644 index 2470fcf132c54..0000000000000 --- a/test/jdk/jdk/classfile/OpcodesValidationTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @summary Testing ClassFile constant instruction argument validation. - * @run junit OpcodesValidationTest - */ -import java.lang.classfile.instruction.ConstantInstruction; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; -import static java.lang.classfile.Opcode.*; - -class OpcodesValidationTest { - - @Test - void testArgumentConstant() { - assertDoesNotThrow(() -> ConstantInstruction.ofArgument(SIPUSH, 0)); - assertDoesNotThrow(() -> ConstantInstruction.ofArgument(SIPUSH, Short.MIN_VALUE)); - assertDoesNotThrow(() -> ConstantInstruction.ofArgument(SIPUSH, Short.MAX_VALUE)); - assertDoesNotThrow(() -> ConstantInstruction.ofArgument(BIPUSH, 0)); - assertDoesNotThrow(() -> ConstantInstruction.ofArgument(BIPUSH, Byte.MIN_VALUE)); - assertDoesNotThrow(() -> ConstantInstruction.ofArgument(BIPUSH, Byte.MAX_VALUE)); - - assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(SIPUSH, (int)Short.MIN_VALUE - 1)); - assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(SIPUSH, (int)Short.MAX_VALUE + 1)); - assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(BIPUSH, (int)Byte.MIN_VALUE - 1)); - assertThrows(IllegalArgumentException.class, () -> ConstantInstruction.ofArgument(BIPUSH, (int)Byte.MAX_VALUE + 1)); - } -} From 90c944fefe4a7827c08a8e6a81f137c3157a749b Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 2 Oct 2024 07:11:10 +0000 Subject: [PATCH 090/188] 8340824: C2: Memory for TypeInterfaces not reclaimed by hashcons() Reviewed-by: vlivanov, qamai --- src/hotspot/share/opto/type.cpp | 143 ++++++++++++++++---------------- src/hotspot/share/opto/type.hpp | 10 +-- 2 files changed, 78 insertions(+), 75 deletions(-) diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 967b4a815d09e..73f852c0f047d 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -3260,23 +3260,28 @@ void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const { // Convenience common pre-built type. const TypeOopPtr *TypeOopPtr::BOTTOM; -TypeInterfaces::TypeInterfaces() - : Type(Interfaces), _list(Compile::current()->type_arena(), 0, 0, nullptr), +TypeInterfaces::TypeInterfaces(ciInstanceKlass** interfaces_base, int nb_interfaces) + : Type(Interfaces), _interfaces(interfaces_base, nb_interfaces), _hash(0), _exact_klass(nullptr) { - DEBUG_ONLY(_initialized = true); -} - -TypeInterfaces::TypeInterfaces(GrowableArray* interfaces) - : Type(Interfaces), _list(Compile::current()->type_arena(), interfaces->length(), 0, nullptr), - _hash(0), _exact_klass(nullptr) { - for (int i = 0; i < interfaces->length(); i++) { - add(interfaces->at(i)); - } + _interfaces.sort(compare); initialize(); } const TypeInterfaces* TypeInterfaces::make(GrowableArray* interfaces) { - TypeInterfaces* result = (interfaces == nullptr) ? new TypeInterfaces() : new TypeInterfaces(interfaces); + // hashcons() can only delete the last thing that was allocated: to + // make sure all memory for the newly created TypeInterfaces can be + // freed if an identical one exists, allocate space for the array of + // interfaces right after the TypeInterfaces object so that they + // form a contiguous piece of memory. + int nb_interfaces = interfaces == nullptr ? 0 : interfaces->length(); + size_t total_size = sizeof(TypeInterfaces) + nb_interfaces * sizeof(ciInstanceKlass*); + + void* allocated_mem = operator new(total_size); + ciInstanceKlass** interfaces_base = (ciInstanceKlass**)((char*)allocated_mem + sizeof(TypeInterfaces)); + for (int i = 0; i < nb_interfaces; ++i) { + interfaces_base[i] = interfaces->at(i); + } + TypeInterfaces* result = ::new (allocated_mem) TypeInterfaces(interfaces_base, nb_interfaces); return (const TypeInterfaces*)result->hashcons(); } @@ -3295,20 +3300,18 @@ int TypeInterfaces::compare(ciInstanceKlass* const& k1, ciInstanceKlass* const& return 0; } -void TypeInterfaces::add(ciInstanceKlass* interface) { - assert(interface->is_interface(), "for interfaces only"); - _list.insert_sorted(interface); - verify(); +int TypeInterfaces::compare(ciInstanceKlass** k1, ciInstanceKlass** k2) { + return compare(*k1, *k2); } bool TypeInterfaces::eq(const Type* t) const { const TypeInterfaces* other = (const TypeInterfaces*)t; - if (_list.length() != other->_list.length()) { + if (_interfaces.length() != other->_interfaces.length()) { return false; } - for (int i = 0; i < _list.length(); i++) { - ciKlass* k1 = _list.at(i); - ciKlass* k2 = other->_list.at(i); + for (int i = 0; i < _interfaces.length(); i++) { + ciKlass* k1 = _interfaces.at(i); + ciKlass* k2 = other->_interfaces.at(i); if (!k1->equals(k2)) { return false; } @@ -3319,12 +3322,12 @@ bool TypeInterfaces::eq(const Type* t) const { bool TypeInterfaces::eq(ciInstanceKlass* k) const { assert(k->is_loaded(), "should be loaded"); GrowableArray* interfaces = k->transitive_interfaces(); - if (_list.length() != interfaces->length()) { + if (_interfaces.length() != interfaces->length()) { return false; } for (int i = 0; i < interfaces->length(); i++) { bool found = false; - _list.find_sorted(interfaces->at(i), found); + _interfaces.find_sorted(interfaces->at(i), found); if (!found) { return false; } @@ -3344,8 +3347,8 @@ const Type* TypeInterfaces::xdual() const { void TypeInterfaces::compute_hash() { uint hash = 0; - for (int i = 0; i < _list.length(); i++) { - ciKlass* k = _list.at(i); + for (int i = 0; i < _interfaces.length(); i++) { + ciKlass* k = _interfaces.at(i); hash += k->hash(); } _hash = hash; @@ -3356,13 +3359,13 @@ static int compare_interfaces(ciInstanceKlass** k1, ciInstanceKlass** k2) { } void TypeInterfaces::dump(outputStream* st) const { - if (_list.length() == 0) { + if (_interfaces.length() == 0) { return; } ResourceMark rm; st->print(" ("); GrowableArray interfaces; - interfaces.appendAll(&_list); + interfaces.appendAll(&_interfaces); // Sort the interfaces so they are listed in the same order from one run to the other of the same compilation interfaces.sort(compare_interfaces); for (int i = 0; i < interfaces.length(); i++) { @@ -3377,9 +3380,9 @@ void TypeInterfaces::dump(outputStream* st) const { #ifdef ASSERT void TypeInterfaces::verify() const { - for (int i = 1; i < _list.length(); i++) { - ciInstanceKlass* k1 = _list.at(i-1); - ciInstanceKlass* k2 = _list.at(i); + for (int i = 1; i < _interfaces.length(); i++) { + ciInstanceKlass* k1 = _interfaces.at(i-1); + ciInstanceKlass* k2 = _interfaces.at(i); assert(compare(k2, k1) > 0, "should be ordered"); assert(k1 != k2, "no duplicate"); } @@ -3390,23 +3393,23 @@ const TypeInterfaces* TypeInterfaces::union_with(const TypeInterfaces* other) co GrowableArray result_list; int i = 0; int j = 0; - while (i < _list.length() || j < other->_list.length()) { - while (i < _list.length() && - (j >= other->_list.length() || - compare(_list.at(i), other->_list.at(j)) < 0)) { - result_list.push(_list.at(i)); + while (i < _interfaces.length() || j < other->_interfaces.length()) { + while (i < _interfaces.length() && + (j >= other->_interfaces.length() || + compare(_interfaces.at(i), other->_interfaces.at(j)) < 0)) { + result_list.push(_interfaces.at(i)); i++; } - while (j < other->_list.length() && - (i >= _list.length() || - compare(other->_list.at(j), _list.at(i)) < 0)) { - result_list.push(other->_list.at(j)); + while (j < other->_interfaces.length() && + (i >= _interfaces.length() || + compare(other->_interfaces.at(j), _interfaces.at(i)) < 0)) { + result_list.push(other->_interfaces.at(j)); j++; } - if (i < _list.length() && - j < other->_list.length() && - _list.at(i) == other->_list.at(j)) { - result_list.push(_list.at(i)); + if (i < _interfaces.length() && + j < other->_interfaces.length() && + _interfaces.at(i) == other->_interfaces.at(j)) { + result_list.push(_interfaces.at(i)); i++; j++; } @@ -3414,14 +3417,14 @@ const TypeInterfaces* TypeInterfaces::union_with(const TypeInterfaces* other) co const TypeInterfaces* result = TypeInterfaces::make(&result_list); #ifdef ASSERT result->verify(); - for (int i = 0; i < _list.length(); i++) { - assert(result->_list.contains(_list.at(i)), "missing"); + for (int i = 0; i < _interfaces.length(); i++) { + assert(result->_interfaces.contains(_interfaces.at(i)), "missing"); } - for (int i = 0; i < other->_list.length(); i++) { - assert(result->_list.contains(other->_list.at(i)), "missing"); + for (int i = 0; i < other->_interfaces.length(); i++) { + assert(result->_interfaces.contains(other->_interfaces.at(i)), "missing"); } - for (int i = 0; i < result->_list.length(); i++) { - assert(_list.contains(result->_list.at(i)) || other->_list.contains(result->_list.at(i)), "missing"); + for (int i = 0; i < result->_interfaces.length(); i++) { + assert(_interfaces.contains(result->_interfaces.at(i)) || other->_interfaces.contains(result->_interfaces.at(i)), "missing"); } #endif return result; @@ -3431,21 +3434,21 @@ const TypeInterfaces* TypeInterfaces::intersection_with(const TypeInterfaces* ot GrowableArray result_list; int i = 0; int j = 0; - while (i < _list.length() || j < other->_list.length()) { - while (i < _list.length() && - (j >= other->_list.length() || - compare(_list.at(i), other->_list.at(j)) < 0)) { + while (i < _interfaces.length() || j < other->_interfaces.length()) { + while (i < _interfaces.length() && + (j >= other->_interfaces.length() || + compare(_interfaces.at(i), other->_interfaces.at(j)) < 0)) { i++; } - while (j < other->_list.length() && - (i >= _list.length() || - compare(other->_list.at(j), _list.at(i)) < 0)) { + while (j < other->_interfaces.length() && + (i >= _interfaces.length() || + compare(other->_interfaces.at(j), _interfaces.at(i)) < 0)) { j++; } - if (i < _list.length() && - j < other->_list.length() && - _list.at(i) == other->_list.at(j)) { - result_list.push(_list.at(i)); + if (i < _interfaces.length() && + j < other->_interfaces.length() && + _interfaces.at(i) == other->_interfaces.at(j)) { + result_list.push(_interfaces.at(i)); i++; j++; } @@ -3453,14 +3456,14 @@ const TypeInterfaces* TypeInterfaces::intersection_with(const TypeInterfaces* ot const TypeInterfaces* result = TypeInterfaces::make(&result_list); #ifdef ASSERT result->verify(); - for (int i = 0; i < _list.length(); i++) { - assert(!other->_list.contains(_list.at(i)) || result->_list.contains(_list.at(i)), "missing"); + for (int i = 0; i < _interfaces.length(); i++) { + assert(!other->_interfaces.contains(_interfaces.at(i)) || result->_interfaces.contains(_interfaces.at(i)), "missing"); } - for (int i = 0; i < other->_list.length(); i++) { - assert(!_list.contains(other->_list.at(i)) || result->_list.contains(other->_list.at(i)), "missing"); + for (int i = 0; i < other->_interfaces.length(); i++) { + assert(!_interfaces.contains(other->_interfaces.at(i)) || result->_interfaces.contains(other->_interfaces.at(i)), "missing"); } - for (int i = 0; i < result->_list.length(); i++) { - assert(_list.contains(result->_list.at(i)) && other->_list.contains(result->_list.at(i)), "missing"); + for (int i = 0; i < result->_interfaces.length(); i++) { + assert(_interfaces.contains(result->_interfaces.at(i)) && other->_interfaces.contains(result->_interfaces.at(i)), "missing"); } #endif return result; @@ -3473,13 +3476,13 @@ ciInstanceKlass* TypeInterfaces::exact_klass() const { } void TypeInterfaces::compute_exact_klass() { - if (_list.length() == 0) { + if (_interfaces.length() == 0) { _exact_klass = nullptr; return; } ciInstanceKlass* res = nullptr; - for (int i = 0; i < _list.length(); i++) { - ciInstanceKlass* interface = _list.at(i); + for (int i = 0; i < _interfaces.length(); i++) { + ciInstanceKlass* interface = _interfaces.at(i); if (eq(interface)) { assert(res == nullptr, ""); res = interface; @@ -3490,8 +3493,8 @@ void TypeInterfaces::compute_exact_klass() { #ifdef ASSERT void TypeInterfaces::verify_is_loaded() const { - for (int i = 0; i < _list.length(); i++) { - ciKlass* interface = _list.at(i); + for (int i = 0; i < _interfaces.length(); i++) { + ciKlass* interface = _interfaces.at(i); assert(interface->is_loaded(), "Interface not loaded"); } } diff --git a/src/hotspot/share/opto/type.hpp b/src/hotspot/share/opto/type.hpp index b9883d5139136..902155e975d16 100644 --- a/src/hotspot/share/opto/type.hpp +++ b/src/hotspot/share/opto/type.hpp @@ -877,19 +877,18 @@ class TypeVectMask : public TypeVect { // Set of implemented interfaces. Referenced from TypeOopPtr and TypeKlassPtr. class TypeInterfaces : public Type { private: - GrowableArray _list; + GrowableArrayFromArray _interfaces; uint _hash; ciInstanceKlass* _exact_klass; DEBUG_ONLY(bool _initialized;) void initialize(); - void add(ciInstanceKlass* interface); void verify() const NOT_DEBUG_RETURN; void compute_hash(); void compute_exact_klass(); - TypeInterfaces(); - TypeInterfaces(GrowableArray* interfaces); + + TypeInterfaces(ciInstanceKlass** interfaces_base, int nb_interfaces); NONCOPYABLE(TypeInterfaces); public: @@ -904,12 +903,13 @@ class TypeInterfaces : public Type { bool contains(const TypeInterfaces* other) const { return intersection_with(other)->eq(other); } - bool empty() const { return _list.length() == 0; } + bool empty() const { return _interfaces.length() == 0; } ciInstanceKlass* exact_klass() const; void verify_is_loaded() const NOT_DEBUG_RETURN; static int compare(ciInstanceKlass* const& k1, ciInstanceKlass* const& k2); + static int compare(ciInstanceKlass** k1, ciInstanceKlass** k2); const Type* xmeet(const Type* t) const; From 52c2ea65c4ab6a2d25e9de465fbf20034fe79028 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Wed, 2 Oct 2024 07:48:22 +0000 Subject: [PATCH 091/188] 8340732: RISC-V: Refactor crc32 scalar version Reviewed-by: fyang --- .../cpu/riscv/macroAssembler_riscv.cpp | 62 ++++++++----------- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 17 ++--- 2 files changed, 31 insertions(+), 48 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 32a446959a246..b99ba542423a1 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1564,7 +1564,10 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Register table0, Register table1, Register table2, Register table3, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6) { assert_different_registers(crc, buf, len, table0, table1, table2, table3, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); - Label L_by16_loop, L_vector_entry, L_unroll_loop, L_unroll_loop_entry, L_by4, L_by4_loop, L_by1, L_by1_loop, L_exit; + Label L_vector_entry, + L_unroll_loop, + L_by4_loop_entry, L_by4_loop, + L_by1_loop, L_exit; const int64_t single_table_size = 256; const int64_t unroll = 16; @@ -1585,21 +1588,17 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, bge(len, tmp1, L_vector_entry); } #endif // COMPILER2 - subw(len, len, unroll_words); - bge(len, zr, L_unroll_loop_entry); - addiw(len, len, unroll_words-4); - bge(len, zr, L_by4_loop); - addiw(len, len, 4); - bgt(len, zr, L_by1_loop); - j(L_exit); + mv(tmp1, unroll_words); + blt(len, tmp1, L_by4_loop_entry); + + const Register loop_buf_end = tmp3; align(CodeEntryAlignment); - bind(L_unroll_loop_entry); - const Register buf_end = tmp3; - add(buf_end, buf, len); // buf_end will be used as endpoint for loop below + // Entry for L_unroll_loop + add(loop_buf_end, buf, len); // loop_buf_end will be used as endpoint for loop below andi(len, len, unroll_words-1); // len = (len % unroll_words) - sub(len, len, unroll_words); // Length after all iterations + sub(loop_buf_end, loop_buf_end, len); bind(L_unroll_loop); for (int i = 0; i < unroll; i++) { ld(tmp1, Address(buf, i*wordSize)); @@ -1608,57 +1607,50 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, } addi(buf, buf, unroll_words); - ble(buf, buf_end, L_unroll_loop); - addiw(len, len, unroll_words-4); - bge(len, zr, L_by4_loop); - addiw(len, len, 4); - bgt(len, zr, L_by1_loop); - j(L_exit); - + blt(buf, loop_buf_end, L_unroll_loop); + + bind(L_by4_loop_entry); + mv(tmp1, 4); + blt(len, tmp1, L_by1_loop); + add(loop_buf_end, buf, len); // loop_buf_end will be used as endpoint for loop below + andi(len, len, 3); + sub(loop_buf_end, loop_buf_end, len); bind(L_by4_loop); lwu(tmp1, Address(buf)); update_word_crc32(crc, tmp1, tmp2, tmp4, tmp6, table0, table1, table2, table3, false); - subw(len, len, 4); addi(buf, buf, 4); - bge(len, zr, L_by4_loop); - addiw(len, len, 4); - ble(len, zr, L_exit); + blt(buf, loop_buf_end, L_by4_loop); bind(L_by1_loop); + beqz(len, L_exit); + subw(len, len, 1); lwu(tmp1, Address(buf)); andi(tmp2, tmp1, right_8_bits); update_byte_crc32(crc, tmp2, table0); - ble(len, zr, L_exit); + beqz(len, L_exit); subw(len, len, 1); srli(tmp2, tmp1, 8); andi(tmp2, tmp2, right_8_bits); update_byte_crc32(crc, tmp2, table0); - ble(len, zr, L_exit); + beqz(len, L_exit); subw(len, len, 1); srli(tmp2, tmp1, 16); andi(tmp2, tmp2, right_8_bits); update_byte_crc32(crc, tmp2, table0); - ble(len, zr, L_exit); - - srli(tmp2, tmp1, 24); - andi(tmp2, tmp2, right_8_bits); - update_byte_crc32(crc, tmp2, table0); #ifdef COMPILER2 // put vector code here, otherwise "offset is too large" error occurs. if (UseRVV) { - j(L_exit); // only need to jump exit when UseRVV == true, it's a jump from end of block `L_by1_loop`. + // only need to jump exit when UseRVV == true, it's a jump from end of block `L_by1_loop`. + j(L_exit); bind(L_vector_entry); vector_update_crc32(crc, buf, len, tmp1, tmp2, tmp3, tmp4, tmp6, table0, table3); - addiw(len, len, -4); - bge(len, zr, L_by4_loop); - addiw(len, len, 4); - bgt(len, zr, L_by1_loop); + bgtz(len, L_by4_loop_entry); } #endif // COMPILER2 diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index d4ec76da94315..5970111088fd1 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -6092,26 +6092,17 @@ static const int64_t right_3_bits = right_n_bits(3); address start = __ pc(); + // input parameters const Register crc = c_rarg0; // crc const Register buf = c_rarg1; // source java byte array address const Register len = c_rarg2; // length - const Register table0 = c_rarg3; // crc_table address - const Register table1 = c_rarg4; - const Register table2 = c_rarg5; - const Register table3 = c_rarg6; - - const Register tmp1 = c_rarg7; - const Register tmp2 = t2; - const Register tmp3 = x28; // t3 - const Register tmp4 = x29; // t4 - const Register tmp5 = x30; // t5 - const Register tmp6 = x31; // t6 BLOCK_COMMENT("Entry:"); __ enter(); // required for proper stackwalking of RuntimeStub frame - __ kernel_crc32(crc, buf, len, table0, table1, table2, - table3, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + __ kernel_crc32(crc, buf, len, + c_rarg3, c_rarg4, c_rarg5, c_rarg6, // tmp's for tables + c_rarg7, t2, x28, x29, x30, x31); // misc tmps __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(); From efe3573b9b4ecec0630fdc1c61c765713a5b68e6 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 2 Oct 2024 07:58:17 +0000 Subject: [PATCH 092/188] 8340109: Ubsan: ciEnv.cpp:1660:65: runtime error: member call on null pointer of type 'struct CompileTask' Reviewed-by: kvn, lucy --- src/hotspot/share/ci/ciEnv.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 9caf89628ccfd..155ce032400e8 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -1616,7 +1616,10 @@ void ciEnv::dump_replay_data_helper(outputStream* out) { for (int i = 0; i < objects->length(); i++) { objects->at(i)->dump_replay_data(out); } - dump_compile_data(out); + + if (this->task() != nullptr) { + dump_compile_data(out); + } out->flush(); } From c8c4ff2035c4e19a71f4395d23f036ba88d2e291 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 2 Oct 2024 08:14:48 +0000 Subject: [PATCH 093/188] 8341135: Incorrect format string after JDK-8339475 Reviewed-by: shade, clanger, alanb --- src/java.base/macosx/native/libjli/java_md_macosx.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/macosx/native/libjli/java_md_macosx.m b/src/java.base/macosx/native/libjli/java_md_macosx.m index d8742aa1204d5..7aeb32be859f2 100644 --- a/src/java.base/macosx/native/libjli/java_md_macosx.m +++ b/src/java.base/macosx/native/libjli/java_md_macosx.m @@ -312,12 +312,12 @@ static void MacOSXStartup(int argc, char *argv[]) { pthread_t main_thr; rc = pthread_create(&main_thr, NULL, &apple_main, &args); if (rc != 0) { - JLI_ReportErrorMessageSys("Could not create main thread, return code: %s\n", rc); + JLI_ReportErrorMessageSys("Could not create main thread, return code: %d\n", rc); exit(1); } rc = pthread_detach(main_thr); if (rc != 0) { - JLI_ReportErrorMessage("pthread_detach() failed, return code: %s\n", rc); + JLI_ReportErrorMessage("pthread_detach() failed, return code: %d\n", rc); exit(1); } From a4ca6267e17815153f8fa119db19b97b1da2bd84 Mon Sep 17 00:00:00 2001 From: Feilong Jiang Date: Wed, 2 Oct 2024 09:14:31 +0000 Subject: [PATCH 094/188] 8341146: RISC-V: Unnecessary fences used for load-acquire in template interpreter Reviewed-by: fyang, rehn --- src/hotspot/cpu/riscv/templateTable_riscv.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 078f54adc3682..2e6902180a892 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -178,7 +178,6 @@ void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg, __ la(temp_reg, Address(temp_reg, in_bytes(ResolvedFieldEntry::put_code_offset()))); } // Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in() - __ membar(MacroAssembler::AnyAny); __ lbu(temp_reg, Address(temp_reg, 0)); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ mv(bc_reg, bc); @@ -320,7 +319,6 @@ void TemplateTable::ldc(LdcType type) { // get type __ addi(x13, x11, tags_offset); __ add(x13, x10, x13); - __ membar(MacroAssembler::AnyAny); __ lbu(x13, Address(x13, 0)); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); @@ -2189,7 +2187,6 @@ void TemplateTable::resolve_cache_and_index_for_method(int byte_no, break; } // Load-acquire the bytecode to match store-release in InterpreterRuntime - __ membar(MacroAssembler::AnyAny); __ lbu(temp, Address(temp, 0)); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); @@ -2241,7 +2238,6 @@ void TemplateTable::resolve_cache_and_index_for_field(int byte_no, __ la(temp, Address(Rcache, in_bytes(ResolvedFieldEntry::put_code_offset()))); } // Load-acquire the bytecode to match store-release in ResolvedFieldEntry::fill_in() - __ membar(MacroAssembler::AnyAny); __ lbu(temp, Address(temp, 0)); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ mv(t0, (int) code); // have we resolved this bytecode? @@ -2403,7 +2399,6 @@ void TemplateTable::load_invokedynamic_entry(Register method) { Label resolved; __ load_resolved_indy_entry(cache, index); - __ membar(MacroAssembler::AnyAny); __ ld(method, Address(cache, in_bytes(ResolvedIndyEntry::method_offset()))); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); @@ -2418,7 +2413,6 @@ void TemplateTable::load_invokedynamic_entry(Register method) { __ call_VM(noreg, entry, method); // Update registers with resolved info __ load_resolved_indy_entry(cache, index); - __ membar(MacroAssembler::AnyAny); __ ld(method, Address(cache, in_bytes(ResolvedIndyEntry::method_offset()))); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); @@ -3533,7 +3527,6 @@ void TemplateTable::_new() { const int tags_offset = Array::base_offset_in_bytes(); __ add(t0, x10, x13); __ la(t0, Address(t0, tags_offset)); - __ membar(MacroAssembler::AnyAny); __ lbu(t0, t0); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ sub(t1, t0, (u1)JVM_CONSTANT_Class); @@ -3651,7 +3644,6 @@ void TemplateTable::checkcast() { // See if bytecode has already been quicked __ add(t0, x13, Array::base_offset_in_bytes()); __ add(x11, t0, x9); - __ membar(MacroAssembler::AnyAny); __ lbu(x11, x11); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ sub(t0, x11, (u1)JVM_CONSTANT_Class); @@ -3707,7 +3699,6 @@ void TemplateTable::instanceof() { // See if bytecode has already been quicked __ add(t0, x13, Array::base_offset_in_bytes()); __ add(x11, t0, x9); - __ membar(MacroAssembler::AnyAny); __ lbu(x11, x11); __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ sub(t0, x11, (u1)JVM_CONSTANT_Class); From d6820d1324711eac95a297dd68ec94e6f6be4b35 Mon Sep 17 00:00:00 2001 From: fabioromano1 <51378941+fabioromano1@users.noreply.github.com> Date: Wed, 2 Oct 2024 09:45:43 +0000 Subject: [PATCH 095/188] 8336274: MutableBigInteger.leftShift(int) optimization Reviewed-by: rgiulietti --- .../classes/java/math/MutableBigInteger.java | 133 +++++++----- .../MutableBigIntegerShiftTests.java | 191 ++++++++++++++++++ .../java/math/MutableBigIntegerBox.java | 180 +++++++++++++++++ 3 files changed, 451 insertions(+), 53 deletions(-) create mode 100644 test/jdk/java/math/BigInteger/MutableBigIntegerShiftTests.java create mode 100644 test/jdk/java/math/BigInteger/java.base/java/math/MutableBigIntegerBox.java diff --git a/src/java.base/share/classes/java/math/MutableBigInteger.java b/src/java.base/share/classes/java/math/MutableBigInteger.java index b84e50f567eb7..6ff435ba1ed3d 100644 --- a/src/java.base/share/classes/java/math/MutableBigInteger.java +++ b/src/java.base/share/classes/java/math/MutableBigInteger.java @@ -597,44 +597,52 @@ void leftShift(int n) { */ if (intLen == 0) return; + int nInts = n >>> 5; - int nBits = n&0x1F; - int bitsInHighWord = BigInteger.bitLengthForInt(value[offset]); + int nBits = n & 0x1F; + int leadingZeros = Integer.numberOfLeadingZeros(value[offset]); // If shift can be done without moving words, do so - if (n <= (32-bitsInHighWord)) { + if (n <= leadingZeros) { primitiveLeftShift(nBits); return; } - int newLen = intLen + nInts +1; - if (nBits <= (32-bitsInHighWord)) - newLen--; - if (value.length < newLen) { - // The array must grow - int[] result = new int[newLen]; - for (int i=0; i < intLen; i++) - result[i] = value[offset+i]; - setValue(result, newLen); - } else if (value.length - offset >= newLen) { - // Use space on right - for(int i=0; i < newLen - intLen; i++) - value[offset+intLen+i] = 0; + int newLen = intLen + nInts; + if (nBits > leadingZeros) + newLen++; + + int[] result; + final int newOffset; + if (value.length < newLen) { // The array must grow + result = new int[newLen]; + newOffset = 0; } else { - // Must use space on left - for (int i=0; i < intLen; i++) - value[i] = value[offset+i]; - for (int i=intLen; i < newLen; i++) - value[i] = 0; - offset = 0; + result = value; + newOffset = value.length - offset >= newLen ? offset : 0; } + + int trailingZerosPos = newOffset + intLen; + if (nBits != 0) { + // Do primitive shift directly for speed + if (nBits <= leadingZeros) { + primitiveLeftShift(nBits, result, newOffset); // newOffset <= offset + } else { + int lastInt = value[offset + intLen - 1]; + primitiveRightShift(32 - nBits, result, newOffset); // newOffset <= offset + result[trailingZerosPos++] = lastInt << nBits; + } + } else if (result != value || newOffset != offset) { + System.arraycopy(value, offset, result, newOffset, intLen); + } + + // Add trailing zeros + if (result == value) + Arrays.fill(result, trailingZerosPos, newOffset + newLen, 0); + + value = result; intLen = newLen; - if (nBits == 0) - return; - if (nBits <= (32-bitsInHighWord)) - primitiveLeftShift(nBits); - else - primitiveRightShift(32 -nBits); + offset = newOffset; } /** @@ -698,15 +706,30 @@ private int mulsubBorrow(int[] q, int[] a, int x, int len, int offset) { * less than 32. * Assumes that intLen > 0, n > 0 for speed */ - private final void primitiveRightShift(int n) { + private void primitiveRightShift(int n) { + primitiveRightShift(n, value, offset); + } + + /** + * Right shift this MutableBigInteger n bits, where n is + * less than 32, placing the result in the specified array. + * Assumes that intLen > 0, n > 0 for speed. + * The result can be the value array of this MutableBigInteger, + * but for speed the copy is not performed safely, so, in that case + * the caller has to make sure that + * {@code (resFrom <= offset || resFrom >= offset + intLen)}. + */ + private void primitiveRightShift(int n, int[] result, int resFrom) { int[] val = value; int n2 = 32 - n; - for (int i=offset+intLen-1, c=val[i]; i > offset; i--) { - int b = c; - c = val[i-1]; - val[i] = (c << n2) | (b >>> n); + + int b = val[offset]; + result[resFrom] = b >>> n; + for (int i = 1; i < intLen; i++) { + int c = b; + b = val[offset + i]; + result[resFrom + i] = (c << n2) | (b >>> n); } - val[offset] >>>= n; } /** @@ -714,15 +737,30 @@ private final void primitiveRightShift(int n) { * less than 32. * Assumes that intLen > 0, n > 0 for speed */ - private final void primitiveLeftShift(int n) { + private void primitiveLeftShift(int n) { + primitiveLeftShift(n, value, offset); + } + + /** + * Left shift this MutableBigInteger n bits, where n is + * less than 32, placing the result in the specified array. + * Assumes that intLen > 0, n > 0 for speed. + * The result can be the value array of this MutableBigInteger, + * but for speed the copy is not performed safely, so, in that case + * the caller has to make sure that + * {@code (resFrom <= offset || resFrom >= offset + intLen)}. + */ + private void primitiveLeftShift(int n, int[] result, int resFrom) { int[] val = value; int n2 = 32 - n; - for (int i=offset, c=val[i], m=i+intLen-1; i < m; i++) { - int b = c; - c = val[i+1]; - val[i] = (b << n) | (c >>> n2); + final int m = intLen - 1; + int b = val[offset]; + for (int i = 0; i < m; i++) { + int c = val[offset + i + 1]; + result[resFrom + i] = (b << n) | (c >>> n2); + b = c; } - val[offset+intLen-1] <<= n; + result[resFrom + m] = b << n; } /** @@ -1511,17 +1549,6 @@ long divide(long v, MutableBigInteger quotient) { } } - private static void copyAndShift(int[] src, int srcFrom, int srcLen, int[] dst, int dstFrom, int shift) { - int n2 = 32 - shift; - int c=src[srcFrom]; - for (int i=0; i < srcLen-1; i++) { - int b = c; - c = src[++srcFrom]; - dst[dstFrom+i] = (b << shift) | (c >>> n2); - } - dst[dstFrom+srcLen-1] = c << shift; - } - /** * Divide this MutableBigInteger by the divisor. * The quotient will be placed into the provided quotient object & @@ -1539,13 +1566,13 @@ private MutableBigInteger divideMagnitude(MutableBigInteger div, MutableBigInteger rem; // Remainder starts as dividend with space for a leading zero if (shift > 0) { divisor = new int[dlen]; - copyAndShift(div.value,div.offset,dlen,divisor,0,shift); + div.primitiveLeftShift(shift, divisor, 0); if (Integer.numberOfLeadingZeros(value[offset]) >= shift) { int[] remarr = new int[intLen + 1]; rem = new MutableBigInteger(remarr); rem.intLen = intLen; rem.offset = 1; - copyAndShift(value,offset,intLen,remarr,1,shift); + this.primitiveLeftShift(shift, remarr, 1); } else { int[] remarr = new int[intLen + 2]; rem = new MutableBigInteger(remarr); diff --git a/test/jdk/java/math/BigInteger/MutableBigIntegerShiftTests.java b/test/jdk/java/math/BigInteger/MutableBigIntegerShiftTests.java new file mode 100644 index 0000000000000..e64cae480d3f0 --- /dev/null +++ b/test/jdk/java/math/BigInteger/MutableBigIntegerShiftTests.java @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.test.lib.RandomFactory; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.Arguments; + +import java.math.BigInteger; +import java.math.MutableBigIntegerBox; +import java.util.Arrays; +import java.util.Random; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static java.math.MutableBigIntegerBox.*; + +/** + * @test + * @bug 8336274 + * @summary Tests for correctness of MutableBigInteger.leftShift(int) + * @library /test/lib + * @build jdk.test.lib.RandomFactory + * @build java.base/java.math.MutableBigIntegerBox + * @key randomness + * @run junit MutableBigIntegerShiftTests + */ +public class MutableBigIntegerShiftTests { + + private static final int ORDER_SMALL = 60; + private static final int ORDER_MEDIUM = 100; + + private static final Random random = RandomFactory.getRandom(); + + private static int[] orders() { + return new int[] { ORDER_SMALL, ORDER_MEDIUM }; + } + + @ParameterizedTest + @MethodSource("orders") + public void shift(int order) { + for (int i = 0; i < 100; i++) { + test(fetchNumber(order), random.nextInt(200)); + } + } + + @ParameterizedTest + @MethodSource("pathTargetedCases") + public void test(MutableBigIntegerBox x, int n) { + leftShiftAssertions(x, n); + } + + private static Arguments[] pathTargetedCases() { + return new Arguments[] { + // intLen == 0 + Arguments.of(MutableBigIntegerBox.ZERO, + random.nextInt(33)), + // intLen != 0 && n <= leadingZeros + Arguments.of(new MutableBigIntegerBox(new int[] { (int) random.nextLong(1L, 1L << 16) }), + random.nextInt(1, 17)), + // intLen != 0 && n > leadingZeros && nBits <= leadingZeros && value.length < newLen && nBits == 0 + Arguments.of(new MutableBigIntegerBox(new int[] { (int) random.nextLong(1L, 1L << 32) }), + 32), + // intLen != 0 && n > leadingZeros && nBits <= leadingZeros && value.length < newLen && nBits != 0 + Arguments.of(new MutableBigIntegerBox(new int[] { (int) random.nextLong(1L, 1L << 16) }), + 32 + random.nextInt(1, 17)), + // intLen != 0 && n > leadingZeros && nBits <= leadingZeros && value.length >= newLen && nBits == 0 + // && newOffset != offset + Arguments.of(new MutableBigIntegerBox(new int[] { random.nextInt(), (int) random.nextLong(1L, 1L << 32) }, 1, 1), + 32), + // intLen != 0 && n > leadingZeros && nBits <= leadingZeros && value.length >= newLen && nBits == 0 + // && newOffset == offset + Arguments.of(new MutableBigIntegerBox(new int[] { (int) random.nextLong(1L, 1L << 32), random.nextInt() }, 0, 1), + 32), + // intLen != 0 && n > leadingZeros && nBits <= leadingZeros && value.length >= newLen && nBits != 0 + // && newOffset != offset + Arguments.of(new MutableBigIntegerBox(new int[] { random.nextInt(), (int) random.nextLong(1L, 1L << 16) }, 1, 1), + 32 + random.nextInt(1, 17)), + // intLen != 0 && n > leadingZeros && nBits <= leadingZeros && value.length >= newLen && nBits != 0 + // && newOffset == offset + Arguments.of(new MutableBigIntegerBox(new int[] { (int) random.nextLong(1L, 1L << 16), random.nextInt() }, 0, 1), + 32 + random.nextInt(1, 17)), + // intLen != 0 && n > leadingZeros && nBits > leadingZeros && value.length < newLen + Arguments.of(new MutableBigIntegerBox(new int[] { (int) random.nextLong(1L << 15, 1L << 32) }), + random.nextInt(17, 32)), + // intLen != 0 && n > leadingZeros && nBits > leadingZeros && value.length >= newLen && newOffset != offset + Arguments.of(new MutableBigIntegerBox(new int[] { random.nextInt(), (int) random.nextLong(1L << 15, 1L << 32) }, 1, 1), + random.nextInt(17, 32)), + // intLen != 0 && n > leadingZeros && nBits > leadingZeros && value.length >= newLen && newOffset == offset + Arguments.of(new MutableBigIntegerBox(new int[] { (int) random.nextLong(1L << 15, 1L << 32), random.nextInt() }, 0, 1), + random.nextInt(17, 32)), + }; + } + + private static void leftShiftAssertions(MutableBigIntegerBox x, int n) { + MutableBigIntegerBox xShifted = x.shiftLeft(n); + assertEquals(x.multiply(new MutableBigIntegerBox(BigInteger.TWO.pow(n))), xShifted); + assertEquals(x, xShifted.shiftRight(n)); + } + + /* + * Get a random or boundary-case number. This is designed to provide + * a lot of numbers that will find failure points, such as max sized + * numbers, empty MutableBigIntegers, etc. + * + * If order is less than 2, order is changed to 2. + */ + private static MutableBigIntegerBox fetchNumber(int order) { + int numType = random.nextInt(8); + MutableBigIntegerBox result = null; + if (order < 2) order = 2; + + int[] val; + switch (numType) { + case 0: // Empty + result = MutableBigIntegerBox.ZERO; + break; + + case 1: // One + result = MutableBigIntegerBox.ONE; + break; + + case 2: // All bits set in number + int numInts = (order + 31) >> 5; + int[] fullBits = new int[numInts]; + Arrays.fill(fullBits, -1); + + fullBits[0] &= -1 >>> -order; + result = new MutableBigIntegerBox(fullBits); + break; + + case 3: // One bit in number + result = MutableBigIntegerBox.ONE.shiftLeft(random.nextInt(order)); + break; + + case 4: // Random bit density + val = new int[(order + 31) >> 5]; + int iterations = random.nextInt(order); + for (int i = 0; i < iterations; i++) { + int bitIdx = random.nextInt(order); + val[bitIdx >> 5] |= 1 << bitIdx; + } + result = new MutableBigIntegerBox(val); + break; + case 5: // Runs of consecutive ones and zeros + result = ZERO; + int remaining = order; + int bit = random.nextInt(2); + while (remaining > 0) { + int runLength = Math.min(remaining, random.nextInt(order)); + result = result.shiftLeft(runLength); + if (bit > 0) + result = result.add(ONE.shiftLeft(runLength).subtract(ONE)); + remaining -= runLength; + bit = 1 - bit; + } + break; + case 6: // random bits with trailing space + int len = random.nextInt((order + 31) >> 5) + 1; + int offset = random.nextInt(len); + val = new int[len << 1]; + for (int i = 0; i < val.length; i++) + val[i] = random.nextInt(); + result = new MutableBigIntegerBox(val, offset, len); + break; + default: // random bits + result = new MutableBigIntegerBox(new BigInteger(order, random)); + } + + return result; + } +} diff --git a/test/jdk/java/math/BigInteger/java.base/java/math/MutableBigIntegerBox.java b/test/jdk/java/math/BigInteger/java.base/java/math/MutableBigIntegerBox.java new file mode 100644 index 0000000000000..1f82e4491987f --- /dev/null +++ b/test/jdk/java/math/BigInteger/java.base/java/math/MutableBigIntegerBox.java @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.math; + +import java.util.Arrays; + +/** + * A class for tests. + */ +public class MutableBigIntegerBox { + + /** + * Constant zero + */ + public static final MutableBigIntegerBox ZERO = new MutableBigIntegerBox(new MutableBigInteger()); + + /** + * Constant one + */ + public static final MutableBigIntegerBox ONE = new MutableBigIntegerBox(MutableBigInteger.ONE); + + /** + * Constant two + */ + public static final MutableBigIntegerBox TWO = new MutableBigIntegerBox(new MutableBigInteger(2)); + + private MutableBigInteger val; + + MutableBigIntegerBox(MutableBigInteger val) { + this.val = val; + } + + /** + * Construct MutableBigIntegerBox from magnitude, starting from + * offset and with a length of intLen ints. + * The value is normalized. + * @param mag the magnitude + * @param offset the offset where the value starts + * @param intLen the length of the value, in int words. + */ + public MutableBigIntegerBox(int[] mag, int offset, int intLen) { + this(new MutableBigInteger(mag)); + val.offset = offset; + val.intLen = intLen; + val.normalize(); + } + + /** + * Construct MutableBigIntegerBox from magnitude. + * The value is normalized. + * @param mag the magnitude + */ + public MutableBigIntegerBox(int[] mag) { + this(mag, 0, mag.length); + } + + /** + * Construct MutableBigIntegerBox from BigInteger val + * @param val the value + */ + public MutableBigIntegerBox(BigInteger val) { + this(val.mag); + } + + /** + * Returns the bit length of this MutableBigInteger value + * @return the bit length of this MutableBigInteger value + */ + public long bitLength() { + return val.bitLength(); + } + + /** + * Return {@code this << n} + * @return {@code this << n} + * @param n the shift + */ + public MutableBigIntegerBox shiftLeft(int n) { + MutableBigIntegerBox res = new MutableBigIntegerBox(val.value.clone(), val.offset, val.intLen); + res.val.safeLeftShift(n); + return res; + } + + /** + * Return {@code this >> n} + * @return {@code this >> n} + * @param n the shift + */ + public MutableBigIntegerBox shiftRight(int n) { + MutableBigInteger res = new MutableBigInteger(val); + res.safeRightShift(n); + return new MutableBigIntegerBox(res); + } + + /** + * Return this + addend + * @return this + addend + * @param addend the addend + */ + public MutableBigIntegerBox add(MutableBigIntegerBox addend) { + MutableBigInteger res = new MutableBigInteger(val); + res.add(addend.val); + return new MutableBigIntegerBox(res); + } + + /** + * Return this - subtraend + * @return this - subtraend + * @param subtraend the subtraend + */ + public MutableBigIntegerBox subtract(MutableBigIntegerBox subtraend) { + MutableBigInteger res = new MutableBigInteger(val); + res.subtract(subtraend.val); + return new MutableBigIntegerBox(res); + } + + /** + * Return this * multiplier + * @return this * multiplier + * @param multiplier the multiplier + */ + public MutableBigIntegerBox multiply(MutableBigIntegerBox multiplier) { + MutableBigInteger res = new MutableBigInteger(); + if (!(val.isZero() || multiplier.val.isZero())) + val.multiply(multiplier.val, res); + + return new MutableBigIntegerBox(res); + } + + /** + * Compare the magnitude of two MutableBigIntegers. Returns -1, 0 or 1 + * as this is numerically less than, equal to, or greater than {@code b}. + * @return -1, 0 or 1 as this is numerically less than, equal to, or + * greater than {@code b}. + * @param b the value to compare + */ + public int compare(MutableBigIntegerBox b) { + return val.compare(b.val); + } + + /** + * Compares this MutableBigIntegerBox with the specified Object for equality. + * + * @param x Object to which this MutableBigIntegerBox is to be compared. + * @return {@code true} if and only if the specified Object is a + * MutableBigIntegerBox whose value is numerically equal to this MutableBigIntegerBox. + */ + @Override + public boolean equals(Object x) { + return (x instanceof MutableBigIntegerBox xInt) + && Arrays.equals(val.value, val.offset, val.offset + val.intLen, + xInt.val.value, xInt.val.offset, xInt.val.offset + xInt.val.intLen); + } + + @Override + public String toString() { + return val.toString(); + } +} From 855c8a7def21025bc2fc47594f7285a55924c213 Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Wed, 2 Oct 2024 10:48:21 +0000 Subject: [PATCH 096/188] 8334305: Remove all code for nsk.share.Log verbose mode Reviewed-by: mli, cjplummer, lmesnik --- .../jit/escape/LockElision/MatMul/MatMul.java | 4 +- .../launchnosuspend/launchnosuspend001.java | 1 - .../filter_tagged/HeapFilter.java | 3 +- .../isexceeded001.java | 3 +- .../isexceeded001.java | 3 +- .../monitoring/stress/lowmem/lowmem001.java | 4 +- .../jtreg/vmTestbase/nsk/share/Log.java | 122 ++---------------- .../nsk/share/aod/AODTestRunner.java | 4 +- .../nsk/share/aod/AbstractJarAgent.java | 4 +- .../nsk/share/aod/DummyTargetApplication.java | 2 +- .../aod/TargetApplicationWaitingAgents.java | 2 +- .../vmTestbase/nsk/share/jvmti/JVMTITest.java | 4 +- .../coverage/parentheses/Parentheses.java | 4 +- 13 files changed, 30 insertions(+), 130 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/jit/escape/LockElision/MatMul/MatMul.java b/test/hotspot/jtreg/vmTestbase/jit/escape/LockElision/MatMul/MatMul.java index cf20b0df8a073..8d1a5fac9aefa 100644 --- a/test/hotspot/jtreg/vmTestbase/jit/escape/LockElision/MatMul/MatMul.java +++ b/test/hotspot/jtreg/vmTestbase/jit/escape/LockElision/MatMul/MatMul.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,7 +85,7 @@ public static void main(String[] args) { } public int run() { - log = new Log(System.out, verbose); + log = new Log(System.out); log.display("Parallel matrix multiplication test"); Matrix a = Matrix.randomMatrix(dim); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001.java index 015643f3a1892..142d6387610f6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/LaunchingConnector/launchnosuspend/launchnosuspend001.java @@ -73,7 +73,6 @@ private launchnosuspend001 (String args[], PrintStream out) { argHandler = new ArgumentHandler(args); log = new Log(this.out, argHandler); - //log.enableVerbose(true); } private PrintStream out; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/IterateThroughHeap/filter_tagged/HeapFilter.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/IterateThroughHeap/filter_tagged/HeapFilter.java index 91f315ee7a968..b690955307ef7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/IterateThroughHeap/filter_tagged/HeapFilter.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/IterateThroughHeap/filter_tagged/HeapFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,7 +49,6 @@ public int runTest(String args[], PrintStream out) { log = new Log(out, argHandler); testObjects = new Object[]{new TaggedClass(), new UntaggedClass()}; - log.enableVerbose(true); log.display("Verifying reachable objects."); status = checkStatus(status); testObjects = null; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isCollectionUsageThresholdExceeded/isexceeded001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isCollectionUsageThresholdExceeded/isexceeded001.java index 702a5a793791a..a9e75bb7cecee 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isCollectionUsageThresholdExceeded/isexceeded001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isCollectionUsageThresholdExceeded/isexceeded001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,6 @@ public static void main(String[] argv) { public static int run(String[] argv, PrintStream out) { ArgumentHandler argHandler = new ArgumentHandler(argv); Log log = new Log(out, argHandler); - log.enableVerbose(true); monitor = Monitor.getMemoryMonitor(log, argHandler); List pools = monitor.getMemoryPoolMBeans(); 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 390bfdd625188..a684c03e67a38 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/MemoryPoolMBean/isUsageThresholdExceeded/isexceeded001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,6 @@ public static void main(String[] argv) { public static int run(String[] argv, PrintStream out) { ArgumentHandler argHandler = new ArgumentHandler(argv); Log log = new Log(out, argHandler); - log.enableVerbose(true); // show log output MemoryMonitor monitor = Monitor.getMemoryMonitor(log, argHandler); List pools = monitor.getMemoryPoolMBeans(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/lowmem/lowmem001.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/lowmem/lowmem001.java index d698e5aec837f..67f0d17f56109 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/lowmem/lowmem001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/lowmem/lowmem001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ public static void main(String[] args) { @Override public void run() { - Log log = new Log(System.out, true); + Log log = new Log(System.out); // System.err is duplicated into buffer // it should be empty MyStream stream = new MyStream(System.err); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java index e575018249533..dbaa1e6646cef 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java @@ -29,22 +29,15 @@ import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringReader; -import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.HashSet; import java.util.Vector; -import nsk.share.test.LazyFormatString; /** - * This class helps to print test-execution trace messages - * and filter them when execution mode is not verbose. - *

      - * Verbose mode if defined by providing -verbose command line - * option, handled by ArgumentParser. Use verbose() - * method to determine which mode is used. + * This class helps to print test-execution trace messages. *

      * Log provides with two main methods to print messages: *

        @@ -60,7 +53,6 @@ * To provide printing messages from different sources into one log * with distinct prefixes use internal Log.Logger class. * - * @see #verbose() * @see #complain(String) * @see #display(String) * @see ArgumentParser @@ -72,18 +64,6 @@ public class Log { */ private PrintStream out = null; - /** - * Is log-mode verbose? - * Always enabled. - */ - private final boolean verbose = true; - - /** - * Should log messages prefixed with timestamps? - * Always enabled. - */ - private final boolean timestamp = true; - /** * Names for trace levels */ @@ -188,41 +168,14 @@ public Log(PrintStream stream) { /** * Incarnate new Log for the given stream; and - * either for verbose or for non-verbose mode accordingly to - * the given verbose key. - */ - public Log(PrintStream stream, boolean verbose) { - this(stream); - } - - /** - * Incarnate new Log for the given stream; and - * either for verbose or for non-verbose mode accordingly to * the given argsHandler. */ public Log(PrintStream stream, ArgumentParser argsParser) { - this(stream, argsParser.verbose()); traceLevel = argsParser.getTraceLevel(); } ///////////////////////////////////////////////////////////////// - /** - * Return true if log mode is verbose. - */ - public boolean verbose() { - return verbose; - } - - /** - * Enable or disable verbose mode for printing messages. - */ - public void enableVerbose(boolean enable) { - if (!enable) { - throw new RuntimeException("The non-verbose logging is not supported."); - } - } - public int getTraceLevel() { return traceLevel; } @@ -266,9 +219,6 @@ public static String printExceptionToString(Object prefix, Throwable exception) @Deprecated public synchronized void println(String message) { doPrint(message); - if (!verbose()) { - keepLog(composeLine(message)); - } } /** @@ -282,9 +232,6 @@ public synchronized void println(String message) { */ @Deprecated public synchronized void comment(String message) { - if (!verbose()) { - doPrint(message); - } } /** @@ -314,17 +261,10 @@ public void trace(int level, Object message, Throwable exception) { } /** - * Print message to the assigned output stream, - * if log mode is verbose. The message will be lost, - * if execution mode is non-verbose, and there is no error messages - * printed. + * Print message to the assigned output stream. */ public synchronized void display(Object message) { - if (verbose()) { - doPrint(message.toString()); - } else { - keepLog(composeLine(message.toString())); - } + doPrint(message.toString()); } /** @@ -333,15 +273,6 @@ public synchronized void display(Object message) { * into errorsBuffer. */ public synchronized void complain(Object message) { - if (!verbose()) { - PrintStream stream = findOutStream(); - stream.println("#> "); - stream.println("#> WARNING: switching log to verbose mode,"); - stream.println("#> because error is complained"); - stream.println("#> "); - stream.flush(); - enableVerbose(true); - } String msgStr = message.toString(); printError(msgStr); @@ -406,10 +337,7 @@ private void logExceptionForFailureAnalysis(String msg) { ///////////////////////////////////////////////////////////////// /** - * Redirect log to the given stream, and switch - * log mode to verbose. - * Prints errors summary to current stream, cancel current stream - * and switches to new stream. Turns on verbose mode for new stream. + * Redirect log to the given stream. * * @deprecated This method is obsolete. */ @@ -430,20 +358,6 @@ public synchronized void clearLogBuffer() { logBuffer.clear(); } - /** - * Print all messages from log buffer which were hidden because - * of non-verbose mode, - */ - private synchronized void flushLogBuffer() { - if (!logBuffer.isEmpty()) { - PrintStream stream = findOutStream(); - for (int i = 0; i < logBuffer.size(); i++) { - stream.println(logBuffer.elementAt(i)); - } - stream.flush(); - } - } - /** * Return out stream if defined or Sytem.err otherwise; * print a warning message when System.err is used first time. @@ -468,18 +382,15 @@ private synchronized PrintStream findOutStream() { * Compose line to print possible prefixing it with timestamp. */ private String composeLine(String message) { - if (timestamp) { - long time = System.currentTimeMillis(); - long ms = time % 1000; - time /= 1000; - long secs = time % 60; - time /= 60; - long mins = time % 60; - time /= 60; - long hours = time % 24; - return "[" + hours + ":" + mins + ":" + secs + "." + ms + "] " + message; - } - return message; + long time = System.currentTimeMillis(); + long ms = time % 1000; + time /= 1000; + long secs = time % 60; + time /= 60; + long mins = time % 60; + time /= 60; + long hours = time % 24; + return "[" + hours + ":" + mins + ":" + secs + "." + ms + "] " + message; } /** @@ -513,13 +424,6 @@ private synchronized void printError(String message) { } } - /** - * Keep the given log message into logBuffer. - */ - private synchronized void keepLog(String message) { - logBuffer.addElement(message); - } - /** * This class can be used as a base for each class that use Log * for print messages and errors. diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java index bde40cc7e2021..9899c762a7a90 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AODTestRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,7 +68,7 @@ public class AODTestRunner { protected AODRunnerArgParser argParser; protected AODTestRunner(String[] args) { - log = new Log(System.out, true); + log = new Log(System.out); argParser = createArgParser(args); } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java index 3fa3141a8cd9e..fb02327a42224 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/AbstractJarAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,7 +157,7 @@ private void defaultInit(String[] args) { if (name == null) throw new TestBug("Agent name wasn't specified"); - log = new Log(System.out, true); + log = new Log(System.out); } /* diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java index bb726453e9bd3..c8fb3bf266324 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/DummyTargetApplication.java @@ -39,7 +39,7 @@ */ public class DummyTargetApplication { - protected Log log = new Log(System.out, true); + protected Log log = new Log(System.out); protected AODTargetArgParser argParser; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java index 6f80033dff504..0b5acfb24ba00 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/aod/TargetApplicationWaitingAgents.java @@ -213,7 +213,7 @@ private void initTargetApplication(String[] args) { if (targetApplicationInitialized) throw new TestBug("TargetApplication already initialized"); - log = new Log(System.out, true); + log = new Log(System.out); argParser = createArgParser(args); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/JVMTITest.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/JVMTITest.java index c8d26b6ea1f5e..d9b847e110dc0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/JVMTITest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/JVMTITest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,7 @@ static void attachAgent(String[] args) { AgentsAttacher attacher = new AgentsAttacher(Utils.findCurrentVMIdUsingJPS(jdkPath), agents, - new Log(System.out, true)); + new Log(System.out)); attacher.attachAgents(); } } diff --git a/test/hotspot/jtreg/vmTestbase/vm/compiler/coverage/parentheses/Parentheses.java b/test/hotspot/jtreg/vmTestbase/vm/compiler/coverage/parentheses/Parentheses.java index 66546e9b13f15..219af51045a23 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/compiler/coverage/parentheses/Parentheses.java +++ b/test/hotspot/jtreg/vmTestbase/vm/compiler/coverage/parentheses/Parentheses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,7 +69,7 @@ public static void main(String[] args) throws Exception { public void run() throws IOException, ReflectiveOperationException { - log = new Log(System.out, verbose); + log = new Log(System.out); InstructionSequence instructionSequence = null; for (int i = 0; i < iterations * stressOptions.getIterationsFactor(); i++) { From 5e9800721a29dbb85be76a6f56c2e2677a3274f2 Mon Sep 17 00:00:00 2001 From: Roman Kennke Date: Wed, 2 Oct 2024 13:27:57 +0000 Subject: [PATCH 097/188] 8307532: Implement LM_LIGHTWEIGHT for Zero Reviewed-by: aboldtch, jwaters --- src/hotspot/cpu/zero/vm_version_zero.cpp | 5 --- src/hotspot/cpu/zero/zeroInterpreter_zero.cpp | 34 +++++++++++-------- src/hotspot/share/runtime/arguments.cpp | 11 ------ .../share/runtime/basicLock.inline.hpp | 2 +- 4 files changed, 20 insertions(+), 32 deletions(-) diff --git a/src/hotspot/cpu/zero/vm_version_zero.cpp b/src/hotspot/cpu/zero/vm_version_zero.cpp index 1fcf4b1086253..7312dd116468c 100644 --- a/src/hotspot/cpu/zero/vm_version_zero.cpp +++ b/src/hotspot/cpu/zero/vm_version_zero.cpp @@ -116,11 +116,6 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseVectorizedMismatchIntrinsic, false); } - if ((LockingMode != LM_LEGACY) && (LockingMode != LM_MONITOR)) { - warning("Unsupported locking mode for this CPU."); - FLAG_SET_DEFAULT(LockingMode, LM_LEGACY); - } - // Enable error context decoding on known platforms #if defined(IA32) || defined(AMD64) || defined(ARM) || \ defined(AARCH64) || defined(PPC) || defined(RISCV) || \ diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index 2b53042ef1017..aab43e733964e 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -485,26 +485,30 @@ int ZeroInterpreter::native_entry(Method* method, intptr_t UNUSED, TRAPS) { // Unlock if necessary if (monitor) { - BasicLock *lock = monitor->lock(); - markWord header = lock->displaced_header(); - oop rcvr = monitor->obj(); - monitor->set_obj(nullptr); - - bool dec_monitor_count = true; - if (header.to_pointer() != nullptr) { - markWord old_header = markWord::encode(lock); - if (rcvr->cas_set_mark(header, old_header) != old_header) { - monitor->set_obj(rcvr); - dec_monitor_count = false; - InterpreterRuntime::monitorexit(monitor); + bool success = false; + if (LockingMode == LM_LEGACY) { + BasicLock* lock = monitor->lock(); + oop rcvr = monitor->obj(); + monitor->set_obj(nullptr); + success = true; + markWord header = lock->displaced_header(); + if (header.to_pointer() != nullptr) { // Check for recursive lock + markWord old_header = markWord::encode(lock); + if (rcvr->cas_set_mark(header, old_header) != old_header) { + monitor->set_obj(rcvr); + success = false; + } + } + if (success) { + THREAD->dec_held_monitor_count(); } } - if (dec_monitor_count) { - THREAD->dec_held_monitor_count(); + if (!success) { + InterpreterRuntime::monitorexit(monitor); } } - unwind_and_return: + unwind_and_return: // Unwind the current activation thread->pop_zero_frame(); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 0d0b58412aefa..0df3492f92557 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -1817,17 +1817,6 @@ bool Arguments::check_vm_args_consistency() { } #endif -#if !defined(X86) && !defined(AARCH64) && !defined(RISCV64) && !defined(ARM) && !defined(PPC64) && !defined(S390) - if (LockingMode == LM_LIGHTWEIGHT) { - FLAG_SET_CMDLINE(LockingMode, LM_LEGACY); - warning("New lightweight locking not supported on this platform"); - } - if (UseObjectMonitorTable) { - FLAG_SET_CMDLINE(UseObjectMonitorTable, false); - warning("UseObjectMonitorTable not supported on this platform"); - } -#endif - if (UseObjectMonitorTable && LockingMode != LM_LIGHTWEIGHT) { // ObjectMonitorTable requires lightweight locking. FLAG_SET_CMDLINE(UseObjectMonitorTable, false); diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp index 30abd575da46a..1090241c3e1f0 100644 --- a/src/hotspot/share/runtime/basicLock.inline.hpp +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -39,7 +39,7 @@ inline void BasicLock::set_displaced_header(markWord header) { inline ObjectMonitor* BasicLock::object_monitor_cache() const { assert(UseObjectMonitorTable, "must be"); -#if defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390) +#if !defined(ZERO) && (defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390)) return reinterpret_cast(get_metadata()); #else // Other platforms do not make use of the cache yet, From 883804841ef9319a18f90a852272c69bc54f5395 Mon Sep 17 00:00:00 2001 From: Matias Saavedra Silva Date: Wed, 2 Oct 2024 14:45:56 +0000 Subject: [PATCH 098/188] 8324259: Classes used by CDS at runtime should be archived Reviewed-by: iklam, ccheung --- src/hotspot/share/cds/metaspaceShared.cpp | 11 ++++ test/hotspot/jtreg/TEST.groups | 1 + .../cds/appcds/DumpRuntimeClassesTest.java | 65 +++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index c66398cefac5a..b6f5d2be50f22 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -77,6 +77,7 @@ #include "runtime/globals.hpp" #include "runtime/globals_extension.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/javaCalls.hpp" #include "runtime/os.inline.hpp" #include "runtime/safepointVerifiers.hpp" #include "runtime/sharedRuntime.hpp" @@ -794,6 +795,16 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS } #endif + // Dummy call to load classes used at CDS runtime + JavaValue result(T_OBJECT); + Handle path_string = java_lang_String::create_from_str("dummy.jar", CHECK); + JavaCalls::call_static(&result, + vmClasses::jdk_internal_loader_ClassLoaders_klass(), + vmSymbols::toFileURL_name(), + vmSymbols::toFileURL_signature(), + path_string, + CHECK); + VM_PopulateDumpSharedSpace op(builder); VMThread::execute(&op); diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 4ab4ba68692c1..37bcb6883a4c6 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -454,6 +454,7 @@ hotspot_appcds_dynamic = \ -runtime/cds/appcds/BadBSM.java \ -runtime/cds/appcds/DumpClassList.java \ -runtime/cds/appcds/DumpClassListWithLF.java \ + -runtime/cds/appcds/DumpRuntimeClassesTest.java \ -runtime/cds/appcds/DumpingWithNoCoops.java \ -runtime/cds/appcds/ExtraSymbols.java \ -runtime/cds/appcds/LambdaContainsOldInf.java \ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java b/test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java new file mode 100644 index 0000000000000..2e530a8d6ddab --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/DumpRuntimeClassesTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @summary Classes used by CDS at runtime should be in the archived + * @bug 8324259 + * @requires vm.cds + * @library /test/lib + * @compile test-classes/Hello.java + * @run driver DumpRuntimeClassesTest + */ + +import jdk.test.lib.cds.CDSOptions; +import jdk.test.lib.cds.CDSTestUtils; + +public class DumpRuntimeClassesTest { + public static void main(String[] args) throws Exception { + // build The app + String appClass = "Hello"; + String classList = "hello.classlist"; + String archiveName = "hello.jsa"; + JarBuilder.build("hello", appClass); + String appJar = TestCommon.getTestJar("hello.jar"); + + // Dump class list + CDSTestUtils.dumpClassList(classList, "-cp", appJar, appClass); + + // Dump archive + CDSOptions opts = (new CDSOptions()) + .addPrefix("-cp", appJar, "-XX:SharedClassListFile=" + classList) + .setArchiveName(archiveName); + CDSTestUtils.createArchive(opts); + + // Run with archive and ensure all the classes used were in the archive + CDSOptions runOpts = (new CDSOptions()) + .addPrefix("-cp", appJar, "-Xlog:class+load,cds=debug") + .setArchiveName(archiveName) + .setUseVersion(false) + .addSuffix(appClass); + CDSTestUtils.runWithArchive(runOpts) + .shouldNotContain("source: jrt:/java.base"); + } +} From 49501fe9c4d0fc4d6285ba4f5d403754e5a147bd Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Wed, 2 Oct 2024 15:13:27 +0000 Subject: [PATCH 099/188] 8341412: Various test failures after JDK-8334305 Reviewed-by: lmesnik, dcubed --- test/hotspot/jtreg/vmTestbase/nsk/share/Log.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java index dbaa1e6646cef..99467fc033412 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java @@ -171,6 +171,7 @@ public Log(PrintStream stream) { * the given argsHandler. */ public Log(PrintStream stream, ArgumentParser argsParser) { + this(stream); traceLevel = argsParser.getTraceLevel(); } From 85f0442727201e0d36ed0a71d2199e602501c98d Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 2 Oct 2024 15:16:32 +0000 Subject: [PATCH 100/188] 8317116: Provide layouts for multiple test UI in PassFailJFrame Reviewed-by: azvegint, prr --- .../awt/regtesthelpers/PassFailJFrame.java | 86 ++++++- .../awt/regtesthelpers/WindowLayouts.java | 237 ++++++++++++++++++ 2 files changed, 319 insertions(+), 4 deletions(-) create mode 100644 test/jdk/java/awt/regtesthelpers/WindowLayouts.java diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 45cd191ae39db..5a9e7671e3958 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -170,6 +170,11 @@ public final class PassFailJFrame { private static final int ROWS = 10; private static final int COLUMNS = 40; + /** + * A gap between windows. + */ + public static final int WINDOW_GAP = 8; + /** * Prefix for the user-provided failure reason. */ @@ -1007,13 +1012,13 @@ private static void positionInstructionFrame(final Position position) { switch (position) { case HORIZONTAL: - int newX = ((screenSize.width / 2) - frame.getWidth()); + int newX = (((screenSize.width + WINDOW_GAP) / 2) - frame.getWidth()); frame.setLocation((newX + screenInsets.left), (frame.getY() + screenInsets.top)); break; case VERTICAL: - int newY = ((screenSize.height / 2) - frame.getHeight()); + int newY = (((screenSize.height + WINDOW_GAP) / 2) - frame.getHeight()); frame.setLocation((frame.getX() + screenInsets.left), (newY + screenInsets.top)); break; @@ -1061,13 +1066,13 @@ public static void positionTestWindow(Window testWindow, Position position) { switch (position) { case HORIZONTAL: case TOP_LEFT_CORNER: - testWindow.setLocation((frame.getX() + frame.getWidth() + 5), + testWindow.setLocation((frame.getX() + frame.getWidth() + WINDOW_GAP), frame.getY()); break; case VERTICAL: testWindow.setLocation(frame.getX(), - (frame.getY() + frame.getHeight() + 5)); + (frame.getY() + frame.getHeight() + WINDOW_GAP)); break; } } @@ -1370,6 +1375,7 @@ public Builder testUI(WindowCreator windowCreator) { return this; } + /** * Adds an implementation of {@link PositionWindows PositionWindows} * which the framework will use to position multiple test UI windows. @@ -1393,6 +1399,77 @@ public Builder positionTestUI(PositionWindows positionWindows) { return this; } + /** + * Positions the test UI windows in a row to the right of + * the instruction frame. The top of the windows is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIRightRow() { + return position(Position.HORIZONTAL) + .positionTestUI(WindowLayouts::rightOneRow); + } + + /** + * Positions the test UI windows in a column to the right of + * the instruction frame. The top of the first window is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIRightColumn() { + return position(Position.HORIZONTAL) + .positionTestUI(WindowLayouts::rightOneColumn); + } + + /** + * Positions the test UI windows in a column to the right of + * the instruction frame centering the stack of the windows. + * + * @return this builder + */ + public Builder positionTestUIRightColumnCentered() { + return position(Position.HORIZONTAL) + .positionTestUI(WindowLayouts::rightOneColumnCentered); + } + + /** + * Positions the test UI windows in a row to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIBottomRow() { + return position(Position.VERTICAL) + .positionTestUI(WindowLayouts::bottomOneRow); + } + + /** + * Positions the test UI windows in a row to the bottom of + * the instruction frame centering the row of the windows. + * + * @return this builder + */ + public Builder positionTestUIBottomRowCentered() { + return position(Position.VERTICAL) + .positionTestUI(WindowLayouts::bottomOneRowCentered); + } + + /** + * Positions the test UI windows in a column to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @return this builder + */ + public Builder positionTestUIBottomColumn() { + return position(Position.VERTICAL) + .positionTestUI(WindowLayouts::bottomOneColumn); + } + + /** * Adds a {@code WindowListCreator} which the framework will use * to create a list of test UI windows. @@ -1495,6 +1572,7 @@ public Builder testUI(PanelCreator panelCreator) { return this; } + /** * Adds a {@code PanelCreator} which the framework will use * to create a component with test UI and display it in a split pane. diff --git a/test/jdk/java/awt/regtesthelpers/WindowLayouts.java b/test/jdk/java/awt/regtesthelpers/WindowLayouts.java new file mode 100644 index 0000000000000..4368e3a59432f --- /dev/null +++ b/test/jdk/java/awt/regtesthelpers/WindowLayouts.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GraphicsConfiguration; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Window; +import java.util.List; + +import static java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment; +import static java.awt.Toolkit.getDefaultToolkit; + +/** + * A utility class which provides standard window layouts for multi-window + * manual tests using the {@link PassFailJFrame} framework. + * The layout methods {@code right-} and {@code bottom-} implement the + * {@link PassFailJFrame.PositionWindows PositionWindows} interface and + * can be used directly or via builder methods. + *

        + * There are several helper methods, such as + * {@link #getScreenCenter() getScreenCenter}, which could help you + * implement customized windows layouts. + */ +public final class WindowLayouts { + + /** Private constructor to prevent instantiating the utility class. */ + private WindowLayouts() { + } + + /** A gap between windows. (Local copy makes expressions shorter.) */ + private static final int WINDOW_GAP = PassFailJFrame.WINDOW_GAP; + + /** + * Lays out the window list in one row to the right of + * the instruction frame. The top of the windows is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void rightOneRow(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutRow(instructionUI.getLocation().x + + instructionUI.getSize().width + + WINDOW_GAP, + instructionUI.getLocation().y, + windows); + } + + /** + * Lays out the window list in one column to the right of + * the instruction frame. The top of the first window is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void rightOneColumn(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutColumn(instructionUI.getLocation().x + + instructionUI.getSize().width + + WINDOW_GAP, + instructionUI.getLocation().y, + windows); + } + + /** + * Lays out the window list in one column to the right of + * the instruction frame centering the stack of the windows. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void rightOneColumnCentered(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutColumn(instructionUI.getLocation().x + + instructionUI.getSize().width + + WINDOW_GAP, + getScreenCenter().y + - getWindowListHeight(windows) / 2, + windows); + } + + + /** + * Lays out the window list in one row to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void bottomOneRow(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutRow(instructionUI.getLocation().x, + instructionUI.getLocation().y + + instructionUI.getSize().height + + WINDOW_GAP, + windows); + } + + /** + * Lays out the window list in one row to the bottom of + * the instruction frame centering the row of the windows. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void bottomOneRowCentered(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutRow(getScreenCenter().x + - getWindowListWidth(windows) / 2, + instructionUI.getLocation().y + + instructionUI.getSize().height + + WINDOW_GAP, + windows); + } + + /** + * Lays out the window list in one column to the bottom of + * the instruction frame. The left of the first window is aligned to + * that of the instruction frame. + * + * @param windows the list of windows to lay out + * @param instructionUI information about the instruction frame + */ + public static void bottomOneColumn(final List windows, + final PassFailJFrame.InstructionUI instructionUI) { + layoutColumn(instructionUI.getLocation().x, + instructionUI.getLocation().y + + instructionUI.getSize().height + + WINDOW_GAP, + windows); + } + + + /** + * Lays out the window list in one row starting at + * ({@code x0}, {@code y}). + * + * @param x0 the starting x coordinate of the windows + * @param y the y coordinate of the windows + * @param windows the list of windows to lay out + */ + public static void layoutRow(final int x0, + final int y, + final List windows) { + int x = x0; + for (Window w : windows) { + w.setLocation(x, y); + x += w.getWidth() + WINDOW_GAP; + } + } + + /** + * Lays out the window list in one column starting at + * ({@code x}, {@code y0}). + * + * @param x the x coordinate of the windows + * @param y0 the starting y coordinate of the windows + * @param windows the list of windows to lay out + */ + public static void layoutColumn(final int x, + final int y0, + final List windows) { + int y = y0; + for (Window w : windows) { + w.setLocation(x, y); + y += w.getHeight() + WINDOW_GAP; + } + } + + + /** + * {@return the center point of the main screen} + */ + public static Point getScreenCenter() { + GraphicsConfiguration gc = getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .getDefaultConfiguration(); + Dimension size = gc.getBounds() + .getSize(); + Insets insets = getDefaultToolkit() + .getScreenInsets(gc); + + return new Point((size.width - insets.left - insets.right) / 2, + (size.height - insets.top - insets.bottom) / 2); + } + + /** + * {@return width of the windows in the list, taking into account + * the gap between windows} + * + * @param windows the list of windows to get the width of + */ + public static int getWindowListWidth(final List windows) { + return windows.stream() + .mapToInt(Component::getWidth) + .sum() + + WINDOW_GAP * (windows.size() - 1); + } + + /** + * {@return height of the windows in the list, taking into account + * the gap between windows} + * + * @param windows the list of windows to get the height of + */ + public static int getWindowListHeight(final List windows) { + return windows.stream() + .mapToInt(Component::getHeight) + .sum() + + WINDOW_GAP * (windows.size() - 1); + } +} From 5063494f5b0859a396b4e41096793c777d4650b8 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 2 Oct 2024 15:16:55 +0000 Subject: [PATCH 101/188] 8340785: Update description of PassFailJFrame and samples Reviewed-by: prr --- .../awt/regtesthelpers/PassFailJFrame.java | 192 +++++++++++++++--- 1 file changed, 159 insertions(+), 33 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 5a9e7671e3958..feb5da43a5ced 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -79,15 +79,77 @@ import static javax.swing.SwingUtilities.isEventDispatchThread; /** - * Provides a framework for manual tests to display test instructions and - * Pass/Fail buttons. + * A framework for manual tests to display test instructions and + * Pass / Fail buttons. The framework automatically + * creates a frame to display the instructions, provides buttons + * to select the test result, and handles test timeout. + * + *

        + * The instruction UI frame displays a timer at the top which indicates + * how much time is left. The timer can be paused using the Pause + * button to the right of the time; the title of the button changes to + * Resume. To resume the timer, use the Resume button. + * + *

        + * In the center, the instruction UI frame displays instructions for the + * tester. The instructions can be either plain text or HTML. If the + * text of the instructions starts with {@code ""}, the + * instructions are displayed as HTML, as supported by Swing, which + * provides richer formatting options. + *

        + * The instructions are displayed in a text component with word-wrapping + * so that there's no horizontal scroll bar. If the text doesn't fit, a + * vertical scroll bar is shown. Use {@code rows} and {@code columns} + * parameters to change the size of this text component. + * If possible, choose the number of rows and columns so that + * the instructions fit and no scroll bars are shown. + * + *

        + * At the bottom, the instruction UI frame displays the + * Pass and Fail buttons. The tester clicks either Pass + * or Fail button to finish the test. When the tester clicks the + * Fail button, the framework displays a dialog box prompting for + * a reason why the test fails. The tester enters the reason and clicks + * OK to close the dialog and fail the test, + * or simply closes the dialog to fail the test without providing any reason. + * + *

        + * If you enable the screenshot feature, a Screenshot button is + * added to the right of the Fail button. The tester can choose either + * Capture Full Screen (default) or Capture Frames and click the + * Screenshot button to take a screenshot. + * If there are multiple screens, screenshots of each screen are created. + * If the tester selects the Capture Frames mode, screenshots of all + * the windows or frames registered in the {@code PassFailJFrame} framework + * are created. + * + *

        + * If you enable a log area, the instruction UI frame adds a text component + * to display log messages below the buttons. + * Use {@link #log(String) log}, {@link #logSet(String) logSet} + * and {@link #logClear() logClear} static methods of {@code PassFailJFrame} + * to add or clear messages from the log area. + * + *

        + * After you create an instance of {@code PassFailJFrame}, call the + * {@link #awaitAndCheck() awaitAndCheck} method to stop the current thread + * (usually the main thread) and wait until the tester clicks + * either Pass or Fail button, + * or until the test times out. *

        - * Instructions for the user can be either plain text or HTML as supported - * by Swing. If the instructions start with {@code }, the - * instructions are displayed as HTML. + * The call to the {@code awaitAndCheck} method is usually the last + * statement in the {@code main} method of your test. + * If the test fails, an exception is thrown to signal the failure to jtreg. + * The test fails if the tester clicks the Fail button, + * if the timeout occurs, + * or if any window or frame is closed. *

        + * Before returning from {@code awaitAndCheck}, the framework disposes of + * all the windows and frames. + * + *

        Sample Manual Test

        * A simple test would look like this: - *
        {@code
        + * {@snippet id='sampleManualTestCode' lang='java':
          * public class SampleManualTest {
          *     private static final String INSTRUCTIONS =
          *             "Click Pass, or click Fail if the test failed.";
        @@ -95,7 +157,7 @@
          *     public static void main(String[] args) throws Exception {
          *         PassFailJFrame.builder()
          *                       .instructions(INSTRUCTIONS)
        - *                       .testUI(() -> createTestUI())
        + *                       .testUI(SampleManualTest::createTestUI)
          *                       .build()
          *                       .awaitAndCheck();
          *     }
        @@ -106,39 +168,87 @@
          *         return testUI;
          *     }
          * }
        - * }
        + * } *

        - * The above example uses the {@link Builder Builder} to set the parameters of - * the instruction frame. It is the recommended way. + * The above example uses the {@link Builder Builder} class to set + * the parameters of the instruction frame. + * It is the recommended way. + * *

        - * The framework will create instruction UI, it will call - * the provided {@code createTestUI} on the Event Dispatch Thread (EDT), - * and it will automatically position the test UI and make it visible. + * The framework will create an instruction UI frame, it will call + * the provided {@code createTestUI} on the Event Dispatch Thread (EDT), + * and it will automatically position the test UI frame and make it visible. + * + *

        + * Add the following jtreg tags before the test class declaration + * {@snippet : + * /* + * * @test + * * @summary Sample manual test + * * @library /java/awt/regtesthelpers + * * @build PassFailJFrame + * * @run main/manual SampleManualTest + * } + * and the closing comment tag */. *

        + * The {@code @library} tag points to the location of the + * {@code PassFailJFrame} class in the source code; + * the {@code @build} tag makes jtreg compile the {@code PassFailJFrame} class, + * and finally the {@code @run} tag specifies it is a manual + * test and the class to run. + * + *

        Using {@code Builder}

        + * Use methods of the {@link Builder Builder} class to set or change + * parameters of {@code PassFailJFrame} and its instruction UI: + *
          + *
        • {@link Builder#title(String) title} sets + * the title of the instruction UI + * (the default is {@value #TITLE});
        • + *
        • {@link Builder#testTimeOut(long) testTimeOut} sets + * the timeout of the test + * (the default is {@value #TEST_TIMEOUT});
        • + *
        • {@link Builder#rows(int) rows} and + * {@link Builder#columns(int) columns} control the size + * the text component which displays the instructions + * (the default number of rows is the number of lines in the text + * of the instructions, + * the default number of columns is {@value #COLUMNS});
        • + *
        • {@link Builder#logArea() logArea} adds a log area;
        • + *
        • {@link Builder#screenCapture() screenCapture} + * enables screenshots.
        • + *
        + * + *

        Using {@code testUI} and {@code splitUI}

        * The {@code Builder.testUI} methods accept interfaces which create one window * or a list of windows if the test needs multiple windows, * or directly a single window, an array of windows or a list of windows. *

        - * For simple test UI, use {@code Builder.splitUI}, or explicitly - * {@code Builder.splitUIRight} or {@code Builder.splitUIBottom} with - * a {@code PanelCreator}. The framework will call the provided - * {@code createUIPanel} to create the component with test UI and + * For simple test UI, use {@link Builder#splitUI(PanelCreator) splitUI}, + * or explicitly + * {@link Builder#splitUIRight(PanelCreator) splitUIRight} or + * {@link Builder#splitUIBottom(PanelCreator) splitUIBottom} with + * a {@link PanelCreator PanelCreator}. + * The framework will call the provided + * {@code createUIPanel} method to create the component with test UI and * will place it as the right or bottom component in a split pane * along with instruction UI. *

        + * Note: support for multiple windows is incomplete. + * + *

        Obsolete Sample Test

        * Alternatively, use one of the {@code PassFailJFrame} constructors to * create an object, then create secondary test UI, register it * with {@code PassFailJFrame}, position it and make it visible. * The following sample demonstrates it: - *
        {@code
        - * public class SampleOldManualTest {
        + * {@snippet id='obsoleteSampleTestCode' lang='java':
        + * public class ObsoleteManualTest {
          *     private static final String INSTRUCTIONS =
          *             "Click Pass, or click Fail if the test failed.";
          *
          *     public static void main(String[] args) throws Exception {
          *         PassFailJFrame passFail = new PassFailJFrame(INSTRUCTIONS);
          *
        - *         SwingUtilities.invokeAndWait(() -> createTestUI());
        + *         SwingUtilities.invokeAndWait(ObsoleteManualTest::createTestUI);
          *
          *         passFail.awaitAndCheck();
          *     }
        @@ -151,17 +261,29 @@
          *         testUI.setVisible(true);
          *     }
          * }
        - * }
        + * } *

        - * Use methods of the {@code Builder} class or constructors of the - * {@code PassFailJFrame} class to control other parameters: - *

          - *
        • the title of the instruction UI,
        • - *
        • the timeout of the test,
        • - *
        • the size of the instruction UI via rows and columns, and
        • - *
        • to add a log area,
        • - *
        • to enable screenshots.
        • - *
        + * This sample uses {@link #PassFailJFrame(String) a constructor} of + * {@code PassFailJFrame} to create its instance, + * there are several overloads provided which allow changing other parameters. + *

        + * When you use the constructors, you have to explicitly create + * your test UI window on EDT. After you create the window, + * you need to register it with the framework using + * {@link #addTestWindow(Window) addTestWindow} + * to ensure the window is disposed of when the test completes. + * Before showing the window, you have to call + * {@link #positionTestWindow(Window, Position) positionTestWindow} + * to position the test window near the instruction UI frame provided + * by the framework. And finally you have to explicitly show the test UI + * window by calling {@code setVisible(true)}. + *

        + * To avoid the complexity, use the {@link Builder Builder} class + * which provides a streamlined way to configure and create an + * instance of {@code PassFailJFrame}. + *

        + * Consider updating tests which use {@code PassFailJFrame} constructors to + * use the builder pattern. */ public final class PassFailJFrame { @@ -541,7 +663,11 @@ private static JComponent createInstructionUIPanel(String instructions, : configurePlainText(instructions, rows, columns); text.setEditable(false); - main.add(new JScrollPane(text), BorderLayout.CENTER); + JPanel textPanel = new JPanel(new BorderLayout()); + textPanel.setBorder(createEmptyBorder(4, 0, 0, 0)); + textPanel.add(new JScrollPane(text), BorderLayout.CENTER); + + main.add(textPanel, BorderLayout.CENTER); JButton btnPass = new JButton("Pass"); btnPass.addActionListener((e) -> { @@ -822,7 +948,7 @@ public void windowClosing(WindowEvent e) { private static JComponent createCapturePanel() { JComboBox screenShortType = new JComboBox<>(CaptureType.values()); - JButton capture = new JButton("ScreenShot"); + JButton capture = new JButton("Screenshot"); capture.addActionListener((e) -> captureScreen((CaptureType) screenShortType.getSelectedItem())); @@ -834,7 +960,7 @@ private static JComponent createCapturePanel() { private enum CaptureType { FULL_SCREEN("Capture Full Screen"), - WINDOWS("Capture Individual Frame"); + WINDOWS("Capture Frames"); private final String type; CaptureType(String type) { From 9fc1c684421043ac8df9ac7cd10fefd2a75e7a6b Mon Sep 17 00:00:00 2001 From: Sorin Basca Date: Wed, 2 Oct 2024 15:30:21 +0000 Subject: [PATCH 102/188] 8339850: Restore the interrupt status in FileSystemPreferences.lockFile() Reviewed-by: bpb, djelinski, vtewari --- .../unix/classes/java/util/prefs/FileSystemPreferences.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java b/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java index ed76ce57f9472..5f0531c0ff7de 100644 --- a/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java +++ b/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -957,6 +957,8 @@ private boolean lockFile(boolean shared) throws SecurityException{ try { Thread.sleep(sleepTime); } catch(InterruptedException e) { + // Don't lose the interrupt. + Thread.currentThread().interrupt(); checkLockFile0ErrorCode(errorCode); return false; } From 0bdfe88e4c5d2f2364b07b803aae16ca0ba7b9d2 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Wed, 2 Oct 2024 15:51:56 +0000 Subject: [PATCH 103/188] 8328313: Archived module graph should allow identical --module-path to be specified during dump time and run time Reviewed-by: alanb, dholmes, iklam --- src/hotspot/share/cds/cdsConfig.cpp | 2 +- src/hotspot/share/cds/filemap.cpp | 66 ++- src/hotspot/share/cds/filemap.hpp | 2 + src/hotspot/share/cds/heapShared.cpp | 20 + src/hotspot/share/cds/metaspaceShared.cpp | 4 + src/hotspot/share/classfile/classLoader.cpp | 2 + .../share/classfile/classLoaderExt.cpp | 49 ++- .../share/classfile/classLoaderExt.hpp | 11 + src/hotspot/share/runtime/arguments.cpp | 5 + src/hotspot/share/runtime/arguments.hpp | 1 + .../internal/loader/BuiltinClassLoader.java | 3 + .../jdk/internal/loader/ClassLoaders.java | 7 - .../jdk/internal/module/ModuleBootstrap.java | 33 +- .../jdk/internal/module/ModuleReferences.java | 21 +- test/hotspot/jtreg/TEST.groups | 2 + .../appcds/dynamicArchive/MainModuleOnly.java | 6 +- .../jigsaw/modulepath/MainModuleOnly.java | 6 +- .../jigsaw/modulepath/ModulePathAndFMG.java | 385 ++++++++++++++++++ .../OptimizeModuleHandlingTest.java | 17 +- 19 files changed, 591 insertions(+), 51 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index a0a562eca21a0..5915424c4fe87 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -236,7 +236,7 @@ void CDSConfig::init_shared_archive_paths() { } void CDSConfig::check_internal_module_property(const char* key, const char* value) { - if (Arguments::is_internal_module_property(key)) { + if (Arguments::is_internal_module_property(key) && !Arguments::is_module_path_property(key)) { stop_using_optimized_module_handling(); log_info(cds)("optimized module handling: disabled due to incompatible property: %s=%s", key, value); } diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 78613ae4b36c4..715fce5f3fc86 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -781,12 +781,12 @@ bool FileMapInfo::check_paths(int shared_path_start_idx, int num_paths, Growable assert(strlen(rp_array->at(i)) > (size_t)runtime_prefix_len, "sanity"); const char* runtime_path = rp_array->at(i) + runtime_prefix_len; if (!os::same_files(dumptime_path, runtime_path)) { - return true; + return false; } i++; j++; } - return false; + return true; } bool FileMapInfo::validate_boot_class_paths() { @@ -810,7 +810,7 @@ bool FileMapInfo::validate_boot_class_paths() { char* rp = skip_first_path_entry(runtime_boot_path); assert(shared_path(0)->is_modules_image(), "first shared_path must be the modules image"); int dp_len = header()->app_class_paths_start_index() - 1; // ignore the first path to the module image - bool mismatch = false; + bool match = true; bool relaxed_check = !header()->has_platform_or_app_classes(); if (dp_len == 0 && rp == nullptr) { @@ -823,7 +823,7 @@ bool FileMapInfo::validate_boot_class_paths() { if (check_paths_existence(rp)) { // If a path exists in the runtime boot paths, it is considered a mismatch // since there's no boot path specified during dump time. - mismatch = true; + match = false; } } } else if (dp_len > 0 && rp != nullptr) { @@ -840,16 +840,16 @@ bool FileMapInfo::validate_boot_class_paths() { // check the full runtime boot path, must match with dump time num = rp_len; } - mismatch = check_paths(1, num, rp_array, 0, 0); + match = check_paths(1, num, rp_array, 0, 0); } else { // create_path_array() ignores non-existing paths. Although the dump time and runtime boot classpath lengths // are the same initially, after the call to create_path_array(), the runtime boot classpath length could become // shorter. We consider boot classpath mismatch in this case. - mismatch = true; + match = false; } } - if (mismatch) { + if (!match) { // The paths are different return classpath_failure("[BOOT classpath mismatch, actual =", runtime_boot_path); } @@ -860,7 +860,7 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) { const char *appcp = Arguments::get_appclasspath(); assert(appcp != nullptr, "null app classpath"); int rp_len = num_paths(appcp); - bool mismatch = false; + bool match = false; if (rp_len < shared_app_paths_len) { return classpath_failure("Run time APP classpath is shorter than the one at dump time: ", appcp); } @@ -889,8 +889,8 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) { // run 2: -cp x.jar:NE4:b.jar -> x.jar:b.jar -> mismatched int j = header()->app_class_paths_start_index(); - mismatch = check_paths(j, shared_app_paths_len, rp_array, 0, 0); - if (mismatch) { + match = check_paths(j, shared_app_paths_len, rp_array, 0, 0); + if (!match) { // To facilitate app deployment, we allow the JAR files to be moved *together* to // a different location, as long as they are still stored under the same directory // structure. E.g., the following is OK. @@ -901,10 +901,10 @@ bool FileMapInfo::validate_app_class_paths(int shared_app_paths_len) { if (dumptime_prefix_len != 0 || runtime_prefix_len != 0) { log_info(class, path)("LCP length for app classpath (dumptime: %u, runtime: %u)", dumptime_prefix_len, runtime_prefix_len); - mismatch = check_paths(j, shared_app_paths_len, rp_array, + match = check_paths(j, shared_app_paths_len, rp_array, dumptime_prefix_len, runtime_prefix_len); } - if (mismatch) { + if (!match) { return classpath_failure("[APP classpath mismatch, actual: -Djava.class.path=", appcp); } } @@ -926,15 +926,35 @@ void FileMapInfo::log_paths(const char* msg, int start_idx, int end_idx) { } } +void FileMapInfo::extract_module_paths(const char* runtime_path, GrowableArray* module_paths) { + GrowableArray* path_array = create_path_array(runtime_path); + int num_paths = path_array->length(); + for (int i = 0; i < num_paths; i++) { + const char* name = path_array->at(i); + ClassLoaderExt::extract_jar_files_from_path(name, module_paths); + } + // module paths are stored in sorted order in the CDS archive. + module_paths->sort(ClassLoaderExt::compare_module_path_by_name); +} + bool FileMapInfo::check_module_paths() { - const char* rp = Arguments::get_property("jdk.module.path"); - int num_paths = CDSConfig::num_archives(rp); - if (num_paths != header()->num_module_paths()) { + const char* runtime_path = Arguments::get_property("jdk.module.path"); + int archived_num_module_paths = header()->num_module_paths(); + if (runtime_path == nullptr && archived_num_module_paths == 0) { + return true; + } + if ((runtime_path == nullptr && archived_num_module_paths > 0) || + (runtime_path != nullptr && archived_num_module_paths == 0)) { return false; } ResourceMark rm; - GrowableArray* rp_array = create_path_array(rp); - return check_paths(header()->app_module_paths_start_index(), num_paths, rp_array, 0, 0); + GrowableArray* module_paths = new GrowableArray(3); + extract_module_paths(runtime_path, module_paths); + int num_paths = module_paths->length(); + if (num_paths != archived_num_module_paths) { + return false; + } + return check_paths(header()->app_module_paths_start_index(), num_paths, module_paths, 0, 0); } bool FileMapInfo::validate_shared_path_table() { @@ -944,6 +964,16 @@ bool FileMapInfo::validate_shared_path_table() { // Load the shared path table info from the archive header _shared_path_table = header()->shared_path_table(); + + bool matched_module_paths = true; + if (CDSConfig::is_dumping_dynamic_archive() || header()->has_full_module_graph()) { + matched_module_paths = check_module_paths(); + } + if (header()->has_full_module_graph() && !matched_module_paths) { + CDSConfig::stop_using_optimized_module_handling(); + log_info(cds)("optimized module handling: disabled because of mismatched module paths"); + } + if (CDSConfig::is_dumping_dynamic_archive()) { // Only support dynamic dumping with the usage of the default CDS archive // or a simple base archive. @@ -959,7 +989,7 @@ bool FileMapInfo::validate_shared_path_table() { "Dynamic archiving is disabled because base layer archive has appended boot classpath"); } if (header()->num_module_paths() > 0) { - if (!check_module_paths()) { + if (!matched_module_paths) { CDSConfig::disable_dumping_dynamic_archive(); log_warning(cds)( "Dynamic archiving is disabled because base layer archive has a different module path"); diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 1bf2510a3351c..6650f52440881 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -271,6 +271,7 @@ class FileMapHeader: private CDSFileMapHeaderBase { bool compressed_oops() const { return _compressed_oops; } bool compressed_class_pointers() const { return _compressed_class_ptrs; } HeapRootSegments heap_root_segments() const { return _heap_root_segments; } + bool has_full_module_graph() const { return _has_full_module_graph; } size_t heap_oopmap_start_pos() const { return _heap_oopmap_start_pos; } size_t heap_ptrmap_start_pos() const { return _heap_ptrmap_start_pos; } size_t rw_ptrmap_start_pos() const { return _rw_ptrmap_start_pos; } @@ -554,6 +555,7 @@ class FileMapInfo : public CHeapObj { GrowableArray* rp_array, unsigned int dumptime_prefix_len, unsigned int runtime_prefix_len) NOT_CDS_RETURN_(false); + void extract_module_paths(const char* runtime_path, GrowableArray* module_paths); bool validate_boot_class_paths() NOT_CDS_RETURN_(false); bool validate_app_class_paths(int shared_app_paths_len) NOT_CDS_RETURN_(false); bool map_heap_region_impl() NOT_CDS_JAVA_HEAP_RETURN_(false); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 1fddcb0d81f8a..1f07e972f059a 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -33,6 +33,7 @@ #include "cds/heapShared.hpp" #include "cds/metaspaceShared.hpp" #include "classfile/classLoaderData.hpp" +#include "classfile/classLoaderExt.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/modules.hpp" #include "classfile/stringTable.hpp" @@ -55,6 +56,7 @@ #include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" +#include "runtime/arguments.hpp" #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/init.hpp" #include "runtime/javaCalls.hpp" @@ -875,6 +877,17 @@ void HeapShared::initialize_from_archived_subgraph(JavaThread* current, Klass* k return; // nothing to do } + if (k->name()->equals("jdk/internal/module/ArchivedModuleGraph") && + !CDSConfig::is_using_optimized_module_handling() && + // archive was created with --module-path + ClassLoaderExt::num_module_paths() > 0) { + // ArchivedModuleGraph was created with a --module-path that's different than the runtime --module-path. + // Thus, it might contain references to modules that do not exist at runtime. We cannot use it. + log_info(cds, heap)("Skip initializing ArchivedModuleGraph subgraph: is_using_optimized_module_handling=%s num_module_paths=%d", + BOOL_TO_STR(CDSConfig::is_using_optimized_module_handling()), ClassLoaderExt::num_module_paths()); + return; + } + ExceptionMark em(THREAD); const ArchivedKlassSubGraphInfoRecord* record = resolve_or_init_classes_for_subgraph_of(k, /*do_init=*/true, THREAD); @@ -1123,6 +1136,13 @@ bool HeapShared::archive_reachable_objects_from(int level, // these objects that are referenced (directly or indirectly) by static fields. ResourceMark rm; log_error(cds, heap)("Cannot archive object of class %s", orig_obj->klass()->external_name()); + if (log_is_enabled(Trace, cds, heap)) { + WalkOopAndArchiveClosure* walker = WalkOopAndArchiveClosure::current(); + if (walker != nullptr) { + LogStream ls(Log(cds, heap)::trace()); + CDSHeapVerifier::trace_to_root(&ls, walker->referencing_obj()); + } + } MetaspaceShared::unrecoverable_writing_error(); } diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp index b6f5d2be50f22..6f646e162ecac 100644 --- a/src/hotspot/share/cds/metaspaceShared.cpp +++ b/src/hotspot/share/cds/metaspaceShared.cpp @@ -301,6 +301,7 @@ void MetaspaceShared::post_initialize(TRAPS) { } ClassLoaderExt::init_paths_start_index(info->app_class_paths_start_index()); ClassLoaderExt::init_app_module_paths_start_index(info->app_module_paths_start_index()); + ClassLoaderExt::init_num_module_paths(info->header()->num_module_paths()); } } } @@ -792,6 +793,9 @@ void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS // Do this at the very end, when no Java code will be executed. Otherwise // some new strings may be added to the intern table. StringTable::allocate_shared_strings_array(CHECK); + } else { + log_info(cds)("Not dumping heap, reset CDSConfig::_is_using_optimized_module_handling"); + CDSConfig::stop_using_optimized_module_handling(); } #endif diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index 487d69a6f4fc9..9a68e2640443f 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -582,6 +582,8 @@ void ClassLoader::setup_module_search_path(JavaThread* current, const char* path new_entry = create_class_path_entry(current, path, &st, false /*is_boot_append */, false /* from_class_path_attr */); if (new_entry != nullptr) { + // ClassLoaderExt::process_module_table() filters out non-jar entries before calling this function. + assert(new_entry->is_jar_file(), "module path entry %s is not a jar file", new_entry->name()); add_to_module_path_entries(path, new_entry); } } diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp index 997f9d76676fa..16981669deb3a 100644 --- a/src/hotspot/share/classfile/classLoaderExt.cpp +++ b/src/hotspot/share/classfile/classLoaderExt.cpp @@ -55,6 +55,7 @@ jshort ClassLoaderExt::_app_class_paths_start_index = ClassLoaderExt::max_classpath_index; jshort ClassLoaderExt::_app_module_paths_start_index = ClassLoaderExt::max_classpath_index; jshort ClassLoaderExt::_max_used_path_index = 0; +int ClassLoaderExt::_num_module_paths = 0; bool ClassLoaderExt::_has_app_classes = false; bool ClassLoaderExt::_has_platform_classes = false; bool ClassLoaderExt::_has_non_jar_in_classpath = false; @@ -89,21 +90,25 @@ void ClassLoaderExt::setup_app_search_path(JavaThread* current) { os::free(app_class_path); } +int ClassLoaderExt::compare_module_path_by_name(const char** p1, const char** p2) { + return strcmp(*p1, *p2); +} + void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable* met) { ResourceMark rm(current); - GrowableArray* module_paths = new GrowableArray(5); + GrowableArray* module_paths = new GrowableArray(5); class ModulePathsGatherer : public ModuleClosure { JavaThread* _current; - GrowableArray* _module_paths; + GrowableArray* _module_paths; public: - ModulePathsGatherer(JavaThread* current, GrowableArray* module_paths) : + ModulePathsGatherer(JavaThread* current, GrowableArray* module_paths) : _current(current), _module_paths(module_paths) {} void do_module(ModuleEntry* m) { char* uri = m->location()->as_C_string(); if (strncmp(uri, "file:", 5) == 0) { char* path = ClassLoader::uri_to_path(uri); - _module_paths->append(path); + extract_jar_files_from_path(path, _module_paths); } } }; @@ -114,6 +119,10 @@ void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable* met->modules_do(&gatherer); } + // Sort the module paths before storing into CDS archive for simpler + // checking at runtime. + module_paths->sort(compare_module_path_by_name); + for (int i = 0; i < module_paths->length(); i++) { ClassLoader::setup_module_search_path(current, module_paths->at(i)); } @@ -129,6 +138,38 @@ void ClassLoaderExt::setup_module_paths(JavaThread* current) { process_module_table(current, met); } +bool ClassLoaderExt::has_jar_suffix(const char* filename) { + // In jdk.internal.module.ModulePath.readModule(), it checks for the ".jar" suffix. + // Performing the same check here. + const char* dot = strrchr(filename, '.'); + if (dot != nullptr && strcmp(dot + 1, "jar") == 0) { + return true; + } + return false; +} + +void ClassLoaderExt::extract_jar_files_from_path(const char* path, GrowableArray* module_paths) { + DIR* dirp = os::opendir(path); + if (dirp == nullptr && errno == ENOTDIR && has_jar_suffix(path)) { + module_paths->append(path); + } else { + if (dirp != nullptr) { + struct dirent* dentry; + while ((dentry = os::readdir(dirp)) != nullptr) { + const char* file_name = dentry->d_name; + if (has_jar_suffix(file_name)) { + size_t full_name_len = strlen(path) + strlen(file_name) + strlen(os::file_separator()) + 1; + char* full_name = NEW_RESOURCE_ARRAY(char, full_name_len); + int n = os::snprintf(full_name, full_name_len, "%s%s%s", path, os::file_separator(), file_name); + assert((size_t)n == full_name_len - 1, "Unexpected number of characters in string"); + module_paths->append(full_name); + } + } + os::closedir(dirp); + } + } +} + char* ClassLoaderExt::read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size, bool clean_text) { const char* name = "META-INF/MANIFEST.MF"; diff --git a/src/hotspot/share/classfile/classLoaderExt.hpp b/src/hotspot/share/classfile/classLoaderExt.hpp index b76ce3ff33a32..c3c0b00d55e43 100644 --- a/src/hotspot/share/classfile/classLoaderExt.hpp +++ b/src/hotspot/share/classfile/classLoaderExt.hpp @@ -53,12 +53,15 @@ class ClassLoaderExt: public ClassLoader { // AllStatic static jshort _app_module_paths_start_index; // the largest path index being used during CDS dump time static jshort _max_used_path_index; + // number of module paths + static int _num_module_paths; static bool _has_app_classes; static bool _has_platform_classes; static bool _has_non_jar_in_classpath; static char* read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size, bool clean_text); + static bool has_jar_suffix(const char* filename); public: static void process_jar_manifest(JavaThread* current, ClassPathEntry* entry); @@ -68,6 +71,8 @@ class ClassLoaderExt: public ClassLoader { // AllStatic static void setup_search_paths(JavaThread* current); static void setup_module_paths(JavaThread* current); + static void extract_jar_files_from_path(const char* path, GrowableArray* module_paths); + static int compare_module_path_by_name(const char** p1, const char** p2); static char* read_manifest(JavaThread* current, ClassPathEntry* entry, jint *manifest_size) { // Remove all the new-line continuations (which wrap long lines at 72 characters, see @@ -87,6 +92,8 @@ class ClassLoaderExt: public ClassLoader { // AllStatic static jshort max_used_path_index() { return _max_used_path_index; } + static int num_module_paths() { return _num_module_paths; } + static void set_max_used_path_index(jshort used_index) { _max_used_path_index = used_index; } @@ -99,6 +106,10 @@ class ClassLoaderExt: public ClassLoader { // AllStatic _app_module_paths_start_index = module_start; } + static void init_num_module_paths(int num_module_paths) { + _num_module_paths = num_module_paths; + } + static bool is_boot_classpath(int classpath_index) { return classpath_index < _app_class_paths_start_index; } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 0df3492f92557..fe9641063b33e 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -336,6 +336,11 @@ bool Arguments::is_internal_module_property(const char* property) { return false; } +// Return true if the key matches the --module-path property name ("jdk.module.path"). +bool Arguments::is_module_path_property(const char* key) { + return (strcmp(key, MODULE_PROPERTY_PREFIX PATH) == 0); +} + // Process java launcher properties. void Arguments::process_sun_java_launcher_properties(JavaVMInitArgs* args) { // See if sun.java.launcher or sun.java.launcher.is_altjvm is defined. diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 8251db3d0d59a..e1bfc0438dc90 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -461,6 +461,7 @@ class Arguments : AllStatic { static int PropertyList_readable_count(SystemProperty* pl); static bool is_internal_module_property(const char* option); + static bool is_module_path_property(const char* key); // Miscellaneous System property value getter and setters. static void set_dll_dir(const char *value) { _sun_boot_library_path->set_value(value); } diff --git a/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java b/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java index 1f7df79009f51..84e5c50672d81 100644 --- a/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java +++ b/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java @@ -1084,5 +1084,8 @@ private static URL checkURL(URL url) { private void resetArchivedStates() { ucp = null; resourceCache = null; + if (!moduleToReader.isEmpty()) { + moduleToReader.clear(); + } } } diff --git a/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java b/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java index 7b0f4d13e4096..ab4aa3fb90734 100644 --- a/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java +++ b/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java @@ -210,13 +210,6 @@ void appendToClassPathForInstrumentation(String path) { protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { return super.defineOrCheckPackage(pn, man, url); } - - /** - * Called by the VM, during -Xshare:dump - */ - private void resetArchivedStates() { - setClassPath(null); - } } /** diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java index 04d607d06bb21..656104e2455fc 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -33,6 +33,7 @@ import java.lang.module.ModuleReference; import java.lang.module.ResolvedModule; import java.net.URI; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -139,7 +140,6 @@ public static ModuleFinder limitedFinder() { */ private static boolean canUseArchivedBootLayer() { return getProperty("jdk.module.upgrade.path") == null && - getProperty("jdk.module.path") == null && getProperty("jdk.module.patch.0") == null && // --patch-module getProperty("jdk.module.addmods.0") == null && // --add-modules getProperty("jdk.module.limitmods") == null && // --limit-modules @@ -203,7 +203,8 @@ private static ModuleLayer boot2() { SystemModules systemModules = null; ModuleFinder systemModuleFinder; - boolean haveModulePath = (appModulePath != null || upgradeModulePath != null); + boolean haveUpgradeModulePath = (upgradeModulePath != null); + boolean haveModulePath = (appModulePath != null || haveUpgradeModulePath); boolean needResolution = true; boolean mayContainSplitPackages = true; boolean mayContainIncubatorModules = true; @@ -463,7 +464,10 @@ private static ModuleLayer boot2() { // Step 8: CDS dump phase - if (CDS.isDumpingStaticArchive() && !haveModulePath && addModules.isEmpty()) { + if (CDS.isDumpingStaticArchive() + && !haveUpgradeModulePath + && addModules.isEmpty() + && allJrtOrModularJar(cf)) { assert !isPatched; // Archive module graph and maybe boot layer @@ -510,6 +514,29 @@ private static void loadModules(Configuration cf, } } + /** + * Returns true if all modules in the configuration are in the run-time image or + * modular JAR files. + */ + private static boolean allJrtOrModularJar(Configuration cf) { + return !cf.modules().stream() + .map(m -> m.reference().location().orElseThrow()) + .anyMatch(uri -> !uri.getScheme().equalsIgnoreCase("jrt") + && !isJarFile(uri)); + } + + /** + * Returns true if the given URI locates a jar file on the file system. + */ + private static boolean isJarFile(URI uri) { + if ("file".equalsIgnoreCase(uri.getScheme())) { + Path path = Path.of(uri); + return path.toString().endsWith(".jar") && Files.isRegularFile(path); + } else { + return false; + } + } + /** * Returns true if the configuration contains modules with overlapping packages. */ diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java b/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java index 346838b47d995..a5ad79eb7c603 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java @@ -91,8 +91,19 @@ static ModuleReference newJarModule(ModuleInfo.Attributes attrs, ModulePatcher patcher, Path file) { URI uri = file.toUri(); - Supplier supplier = () -> new JarModuleReader(file, uri); - HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a); + String fileString = file.toString(); + Supplier supplier = new Supplier<>() { + @Override + public ModuleReader get() { + return new JarModuleReader(fileString, uri); + } + }; + HashSupplier hasher = new HashSupplier() { + @Override + public byte[] generate(String algorithm) { + return ModuleHashes.computeHash(supplier, algorithm); + } + }; return newModule(attrs, uri, supplier, patcher, hasher); } @@ -222,9 +233,9 @@ static class JarModuleReader extends SafeCloseModuleReader { private final JarFile jf; private final URI uri; - static JarFile newJarFile(Path path) { + static JarFile newJarFile(String path) { try { - return new JarFile(new File(path.toString()), + return new JarFile(new File(path), true, // verify ZipFile.OPEN_READ, JarFile.runtimeVersion()); @@ -233,7 +244,7 @@ static JarFile newJarFile(Path path) { } } - JarModuleReader(Path path, URI uri) { + JarModuleReader(String path, URI uri) { this.jf = newJarFile(path); this.uri = uri; } diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 37bcb6883a4c6..f54dc79fcfc8f 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -438,6 +438,8 @@ hotspot_appcds_dynamic = \ -runtime/cds/appcds/complexURI \ -runtime/cds/appcds/customLoader \ -runtime/cds/appcds/dynamicArchive \ + -runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java \ + -runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java \ -runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java \ -runtime/cds/appcds/javaldr/ArrayTest.java \ -runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java \ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/MainModuleOnly.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/MainModuleOnly.java index 0dd4af2e4509e..e74229869edce 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/MainModuleOnly.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/MainModuleOnly.java @@ -213,8 +213,10 @@ public static void doTest(String topArchiveName) throws Exception { "-cp", destJar.toString(), "--module-path", MODS_DIR.toString(), "-m", TEST_MODULE1 + "/" + MAIN_CLASS) - .assertAbnormalExit(output -> { - output.shouldMatch("Error: non-empty directory.*com.simple"); + // After JDK-8328313, non-empty module path directory won't be included + // in the shared paths table. + .assertNormalExit(output -> { + output.shouldNotMatch("Error: non-empty directory.*com.simple"); }); // test module path with very long length diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/MainModuleOnly.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/MainModuleOnly.java index 50191b91e1ef5..ac9bb5adc006d 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/MainModuleOnly.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/MainModuleOnly.java @@ -194,8 +194,10 @@ public static void main(String... args) throws Exception { output = TestCommon.createArchive(destJar.toString(), appClasses, "--module-path", MODS_DIR.toString(), "-m", mainModule); - output.shouldHaveExitValue(1) - .shouldMatch("Error: non-empty directory.*com.simple"); + // After JDK-8328313, non-empty module path directory won't be included + // in the shared paths table. + output.shouldHaveExitValue(0) + .shouldNotMatch("Error: non-empty directory.*com.simple"); // test module path with very long length // diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java new file mode 100644 index 0000000000000..fe77714204670 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/ModulePathAndFMG.java @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8328313 + * @requires vm.cds & !vm.graal.enabled & vm.cds.write.archived.java.heap + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * @run driver ModulePathAndFMG + * @summary test module path changes for full module graph handling. + * + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class ModulePathAndFMG { + private static final String JAVA_HOME = System.getProperty("java.home"); + + private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir()); + + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MODS_DIR = Paths.get("mody"); + private static final Path JMOD_DIR = Paths.get("jmod_dir"); + + // the module name of the test module + private static final String MAIN_MODULE = "com.bars"; + private static final String TEST_MODULE = "com.foos"; + private static final String DUP_MODULE = "com.foos3"; + + // the module main class + private static final String MAIN_CLASS = "com.bars.Main"; + private static final String TEST_CLASS = "com.foos.Test"; + + private static String PATH_LIBS = "modylibs"; + private static String DUP_LIBS = "duplibs"; + private static Path libsDir = null; + private static Path dupDir = null; + private static Path jmodDir = null; + private static Path mainJar = null; + private static Path testJar = null; + private static Path dupJar = null; + private static Path badJar = null; + + private static String CLASS_FOUND_MESSAGE = "com.foos.Test found"; + private static String CLASS_NOT_FOUND_MESSAGE = "java.lang.ClassNotFoundException: com.foos.Test"; + private static String FIND_EXCEPTION_MESSAGE = "java.lang.module.FindException: Module com.foos not found, required by com.bars"; + private static String MODULE_NOT_RECOGNIZED = "Module format not recognized:.*modylibs.*com.bars.JAR"; + private static String OPTIMIZE_ENABLED = "] optimized module handling: enabled"; + private static String OPTIMIZE_DISABLED = "] optimized module handling: disabled"; + private static String FMG_ENABLED = "] full module graph: enabled"; + private static String FMG_DISABLED = "] full module graph: disabled"; + private static String MAIN_FROM_JAR = "class,load.*com.bars.Main.*[.]jar"; + private static String MAIN_FROM_CDS = "class,load.*com.bars.Main.*shared objects file"; + private static String MAIN_FROM_MODULE = "class,load.*com.bars.Main.*mody/com.bars"; + private static String TEST_FROM_JAR = "class,load.*com.foos.Test.*[.]jar"; + private static String TEST_FROM_CDS = "class,load.*com.foos.Test.*shared objects file"; + private static String MAP_FAILED = "Unable to use shared archive"; + private static String PATH_SEPARATOR = File.pathSeparator; + private static String appClasses[] = {MAIN_CLASS, TEST_CLASS}; + private static String prefix[] = {"-Djava.class.path=", "-Xlog:cds,class+load,class+path=info"}; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE), + null); + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(MAIN_MODULE), + MODS_DIR.resolve(MAIN_MODULE), + MODS_DIR.toString()); + + libsDir = Files.createTempDirectory(USER_DIR, PATH_LIBS); + mainJar = libsDir.resolve(MAIN_MODULE + ".jar"); + testJar = libsDir.resolve(TEST_MODULE + ".jar"); + + // modylibs contains both modules com.foos.jar, com.bars.jar + // build com.foos.jar + String classes = MODS_DIR.resolve(TEST_MODULE).toString(); + JarBuilder.createModularJar(testJar.toString(), classes, TEST_CLASS); + + // build com.bars.jar + classes = MODS_DIR.resolve(MAIN_MODULE).toString(); + JarBuilder.createModularJar(mainJar.toString(), classes, MAIN_CLASS); + + dupDir = Files.createTempDirectory(USER_DIR, DUP_LIBS); + dupJar = dupDir.resolve(DUP_MODULE + ".jar"); + Files.copy(testJar, dupJar, StandardCopyOption.REPLACE_EXISTING); + + badJar = libsDir.resolve(MAIN_MODULE + ".JAR"); + Files.copy(mainJar, badJar, StandardCopyOption.REPLACE_EXISTING); + } + + public static void buildJmod() throws Exception { + Path jmod = Paths.get(JAVA_HOME, "bin", "jmod"); + jmodDir = Files.createDirectory(Paths.get(USER_DIR.toString() + File.separator + JMOD_DIR.toString())); + OutputAnalyzer output = ProcessTools.executeProcess(jmod.toString(), + "create", + "--class-path", Paths.get(USER_DIR.toString(), MODS_DIR.toString(), TEST_MODULE).toString(), + "--module-version", "1.0", + "--main-class", TEST_CLASS, + jmodDir.toString() + File.separator + TEST_MODULE + ".jmod"); + output.shouldHaveExitValue(0); + } + + public static void main(String... args) throws Exception { + runWithModulePath(); + runWithExplodedModule(); + runWithJmodAndBadJar(); + } + + private static void tty(String... args) { + for (String s : args) { + System.out.print(s + " "); + } + System.out.print("\n"); + } + + public static void runWithModulePath() throws Exception { + // compile the modules and create the modular jar files + buildTestModule(); + // create an archive with the classes in the modules built in the + // previous step + OutputAnalyzer output = TestCommon.createArchive( + null, appClasses, + "--module-path", + libsDir.toString(), + "-m", MAIN_MODULE); + TestCommon.checkDump(output); + + tty("1. run with CDS on, with module path same as dump time"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + libsDir.toString(), // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(FMG_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + + tty("2. run with CDS on, with jar on path"); + TestCommon.run("-Xlog:cds", + "-Xlog:class+load", + "-cp", mainJar.toString() + PATH_SEPARATOR + testJar.toString(), + MAIN_CLASS) + .assertNormalExit(out -> { + out.shouldContain(CLASS_FOUND_MESSAGE) + .shouldMatch(MAIN_FROM_JAR) + .shouldMatch(TEST_FROM_JAR) + .shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldNotContain(FMG_ENABLED); + }); + + tty("3. run with CDS on, with --module-path, with jar should fail"); + TestCommon.run("-Xlog:cds", + "-Xlog:class+load", + "-p", libsDir.toString(), + "-cp", mainJar.toString(), + MAIN_CLASS) + .assertNormalExit(out -> { + out.shouldContain(CLASS_NOT_FOUND_MESSAGE) + .shouldMatch(MAIN_FROM_JAR) + .shouldNotContain(FMG_ENABLED) + .shouldNotContain(OPTIMIZE_ENABLED); + }); + + final String modularJarPath = mainJar.toString() + PATH_SEPARATOR + testJar.toString(); + + tty("4. run with CDS on, with modular jars specified --module-path, should pass"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + modularJarPath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(FMG_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldMatch(MAIN_FROM_CDS); // archived Main class is for module only + }); + + final String extraModulePath = libsDir.toString() + PATH_SEPARATOR + dupDir.toString(); + // create an archive with an extra module which is not referenced + output = TestCommon.createArchive( + null, appClasses, + "--module-path", + extraModulePath, + "-m", MAIN_MODULE); + TestCommon.checkDump(output); + + tty("5. run with CDS on, without the extra module specified in dump time, should pass"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + libsDir.toString(), // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(FMG_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + tty("6. run with CDS on, with the extra module specified in dump time"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + extraModulePath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(FMG_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + + final String extraJarPath = modularJarPath + PATH_SEPARATOR + dupJar.toString(); + + // create an archive by specifying modular jars in the --module-path with an extra module which is not referenced + output = TestCommon.createArchive( + null, appClasses, + "--module-path", + extraJarPath, + "-m", MAIN_MODULE); + TestCommon.checkDump(output); + tty("7. run with CDS on, without the extra module specified in dump time, should pass"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + modularJarPath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(FMG_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + + tty("8. run with CDS on, with the extra module specified in dump time"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + extraJarPath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(FMG_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + tty("9. same as test case 8 but with paths instead of modular jars in the --module-path"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + extraModulePath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(FMG_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldMatch(MAIN_FROM_CDS) // archived Main class is for module only + .shouldContain(CLASS_FOUND_MESSAGE); + }); + } + + public static void runWithExplodedModule() throws Exception { + // create an archive with an exploded module in the module path. + OutputAnalyzer output = TestCommon.createArchive( + null, appClasses, + "--module-path", + MODS_DIR.toString(), + "-m", MAIN_MODULE + "/" + MAIN_CLASS); + TestCommon.checkDump(output); + + tty("10. run with CDS on, with exploded module in the module path"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + MODS_DIR.toString(), // --module-path + MAIN_MODULE + "/" + MAIN_CLASS) // -m + .assertNormalExit(out -> { + out.shouldContain(FMG_DISABLED) + .shouldMatch(MAIN_FROM_MODULE) // Main class loaded from the exploded module + .shouldContain(CLASS_FOUND_MESSAGE); + }); + } + + public static void runWithJmodAndBadJar() throws Exception { + buildJmod(); + + final String modularJarPath = mainJar.toString() + PATH_SEPARATOR + testJar.toString(); + // create an archive with --module-path com.bars.jar:com.foos.jar + OutputAnalyzer output = TestCommon.createArchive( + null, appClasses, + "--module-path", + modularJarPath, + "-m", MAIN_MODULE); + TestCommon.checkDump(output); + + String runModulePath = mainJar.toString() + PATH_SEPARATOR + + jmodDir.toString() + TEST_MODULE + ".jmod"; + tty("11. run with CDS on, with module path com.bars.jar:com.foos.jmod"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + runModulePath, // --module-path + MAIN_MODULE) // -m + .assertAbnormalExit(out -> { + out.shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldNotContain(FMG_ENABLED) + .shouldContain(FIND_EXCEPTION_MESSAGE); + }); + + runModulePath += PATH_SEPARATOR + testJar.toString(); + tty("12. run with CDS on, with module path com.bars.jar:com.foos.jmod:com.foos.jar"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + runModulePath, // --module-path + MAIN_MODULE) // -m + .assertNormalExit(out -> { + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(FMG_DISABLED) + .shouldContain(FMG_ENABLED) + .shouldMatch(TEST_FROM_CDS) + .shouldMatch(MAIN_FROM_CDS) + .shouldContain(CLASS_FOUND_MESSAGE); + }); + + runModulePath = badJar.toString() + PATH_SEPARATOR + testJar.toString(); + tty("13. run with CDS on, with module path com.bars.JAR:com.foos.jar"); + TestCommon.runWithModules(prefix, + null, // --upgrade-module-path + runModulePath, // --module-path + TEST_MODULE) // -m + .assertAbnormalExit(out -> { + out.shouldContain(OPTIMIZE_DISABLED) + .shouldNotContain(OPTIMIZE_ENABLED) + .shouldContain(FMG_DISABLED) + .shouldNotContain(FMG_ENABLED) + .shouldMatch(MODULE_NOT_RECOGNIZED); + }); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java index aeb5696830df4..cf6f4cd7fd3d5 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/modulepath/OptimizeModuleHandlingTest.java @@ -24,7 +24,7 @@ /** * @test - * @requires vm.cds & !vm.graal.enabled + * @requires vm.cds & !vm.graal.enabled & vm.cds.write.archived.java.heap * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds * @run driver OptimizeModuleHandlingTest * @summary test module path changes for optimization of @@ -64,8 +64,8 @@ public class OptimizeModuleHandlingTest { private static String CLASS_FOUND_MESSAGE = "com.foos.Test found"; private static String CLASS_NOT_FOUND_MESSAGE = "java.lang.ClassNotFoundException: com.foos.Test"; - private static String OPTIMIZE_ENABLED = "optimized module handling: enabled"; - private static String OPTIMIZE_DISABLED = "optimized module handling: disabled"; + private static String OPTIMIZE_ENABLED = "] optimized module handling: enabled"; + private static String OPTIMIZE_DISABLED = "] optimized module handling: disabled"; private static String MAIN_FROM_JAR = "class,load.*com.bars.Main.*[.]jar"; private static String MAIN_FROM_CDS = "class,load.*com.bars.Main.*shared objects file"; private static String TEST_FROM_JAR = "class,load.*com.foos.Test.*[.]jar"; @@ -154,14 +154,14 @@ public static void runWithModulePath(String... extraRuntimeArgs) throws Exceptio // Following 5 - 10 test with CDS on tty("5. run with CDS on, with module path"); - String prefix[] = {"-Djava.class.path=", "-Xlog:cds", "-Xlog:class+load"}; + String prefix[] = {"-Djava.class.path=", "-Xlog:cds,class+load,class+path=info"}; TestCommon.runWithModules(prefix, null, // --upgrade-module-path libsDir.toString(), // --module-path MAIN_MODULE) // -m .assertNormalExit(out -> { - out.shouldNotContain(OPTIMIZE_ENABLED) - .shouldContain(OPTIMIZE_DISABLED) + out.shouldNotContain(OPTIMIZE_DISABLED) + .shouldContain(OPTIMIZE_ENABLED) .shouldMatch(MAIN_FROM_CDS) // // archived Main class is for module only .shouldContain(CLASS_FOUND_MESSAGE); }); @@ -174,8 +174,8 @@ public static void runWithModulePath(String... extraRuntimeArgs) throws Exceptio out.shouldContain(CLASS_FOUND_MESSAGE) .shouldMatch(MAIN_FROM_CDS) .shouldMatch(TEST_FROM_CDS) - .shouldContain(OPTIMIZE_DISABLED) - .shouldNotContain(OPTIMIZE_ENABLED); + .shouldContain(OPTIMIZE_ENABLED) + .shouldNotContain(OPTIMIZE_DISABLED); }); tty("7. run with CDS on, with jar on path"); TestCommon.run("-Xlog:cds", @@ -231,7 +231,6 @@ public static void runWithModulePath(String... extraRuntimeArgs) throws Exceptio MAIN_CLASS) .assertAbnormalExit(out -> { out.shouldNotContain(CLASS_FOUND_MESSAGE) - .shouldContain(OPTIMIZE_DISABLED) // mapping info .shouldContain("shared class paths mismatch"); }); } From 76283dd2701ca4ad5c1c99a66f3e8e3d0fe55d44 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Wed, 2 Oct 2024 16:07:10 +0000 Subject: [PATCH 104/188] 8341246: Test com/sun/tools/attach/PermissionTest.java fails access denied after JDK-8327114 Reviewed-by: kevinw, sgehwolf --- test/jdk/com/sun/tools/attach/java.policy.allow | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/jdk/com/sun/tools/attach/java.policy.allow b/test/jdk/com/sun/tools/attach/java.policy.allow index 3e63a207f61ff..1d4b714c90297 100644 --- a/test/jdk/com/sun/tools/attach/java.policy.allow +++ b/test/jdk/com/sun/tools/attach/java.policy.allow @@ -1,6 +1,4 @@ /* - * - * * Policy file used by unit tests for attach API */ grant { @@ -15,7 +13,10 @@ grant { permission java.lang.RuntimePermission "loadLibrary.attach"; permission java.util.PropertyPermission "sun.jvmstat.*", "read"; - /* to read configuration file in META-INF/services, and write/delete .attach_pid */ - permission java.io.FilePermission "<>", "read,write,delete"; + /* + * To read configuration file in META-INF/services, write/delete .attach_pid, + * and read symbolic link of /proc/self/ns/mnt. + */ + permission java.io.FilePermission "<>", "read,write,delete,readlink"; }; From c43202baf6eb7e49ec458037971a9efa392d053e Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 2 Oct 2024 16:10:48 +0000 Subject: [PATCH 105/188] 8341037: Use standard layouts in DefaultFrameIconTest.java and MenuCrash.java Reviewed-by: azvegint, prr --- test/jdk/java/awt/Frame/DefaultFrameIconTest.java | 12 +----------- test/jdk/java/awt/Frame/MenuCrash.java | 12 +----------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/test/jdk/java/awt/Frame/DefaultFrameIconTest.java b/test/jdk/java/awt/Frame/DefaultFrameIconTest.java index 3ca3b70dbd1a1..f8b48c6df2ca5 100644 --- a/test/jdk/java/awt/Frame/DefaultFrameIconTest.java +++ b/test/jdk/java/awt/Frame/DefaultFrameIconTest.java @@ -50,21 +50,11 @@ public static void main(String[] args) throws Exception { .instructions(INSTRUCTIONS) .columns(45) .testUI(DefaultFrameIconTest::createAndShowUI) - .positionTestUI(DefaultFrameIconTest::positionTestWindows) + .positionTestUIRightRow() .build() .awaitAndCheck(); } - private static void positionTestWindows(List testWindows, - PassFailJFrame.InstructionUI instructionUI) { - int gap = 5; - int x = instructionUI.getLocation().x + instructionUI.getSize().width + gap; - for (Window w : testWindows) { - w.setLocation(x, instructionUI.getLocation().y); - x += w.getWidth() + gap; - } - } - private static List createAndShowUI() { Frame testFrame = new Frame("Frame DefaultFrameIconTest"); Dialog testDialog = new Dialog(testFrame, "Dialog DefaultFrameIconTest"); diff --git a/test/jdk/java/awt/Frame/MenuCrash.java b/test/jdk/java/awt/Frame/MenuCrash.java index f41408ecdadfb..f68dd4ad00002 100644 --- a/test/jdk/java/awt/Frame/MenuCrash.java +++ b/test/jdk/java/awt/Frame/MenuCrash.java @@ -62,7 +62,7 @@ public static void main(String[] args) throws Exception { .instructions(INSTRUCTIONS) .columns(45) .testUI(MenuCrash::createAndShowUI) - .positionTestUI(MenuCrash::positionTestWindows) + .positionTestUIRightRow() .build() .awaitAndCheck(); } @@ -81,16 +81,6 @@ private static List createAndShowUI() { return List.of(frame1, frame2); } - private static void positionTestWindows(List testWindows, - PassFailJFrame.InstructionUI instructionUI) { - int gap = 5; - int x = instructionUI.getLocation().x + instructionUI.getSize().width + gap; - for (Window w : testWindows) { - w.setLocation(x, instructionUI.getLocation().y); - x += w.getWidth() + gap; - } - } - static class MenuFrame extends Frame { private final TextField field; From dc0ce1b2f2ebf457de9524adcbce2b473749e815 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Wed, 2 Oct 2024 21:58:26 +0000 Subject: [PATCH 106/188] 8341336: Fix -Wzero-as-null-pointer-constant warnings in PRODUCT-only code Reviewed-by: stefank, iwalulya, shade --- src/hotspot/share/c1/c1_LIR.hpp | 5 +++-- .../share/interpreter/templateInterpreterGenerator.hpp | 4 ++-- src/hotspot/share/oops/constantPool.hpp | 3 ++- src/hotspot/share/opto/memnode.hpp | 6 +----- src/hotspot/share/utilities/macros.hpp | 2 ++ 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index d9c3e9d3cb68f..c568caeca4b30 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -29,6 +29,7 @@ #include "c1/c1_ValueType.hpp" #include "oops/method.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" class BlockBegin; class BlockList; @@ -1122,7 +1123,7 @@ class LIR_Op: public CompilationResourceObj { } #endif - virtual const char * name() const PRODUCT_RETURN0; + virtual const char * name() const PRODUCT_RETURN_NULL; virtual void visit(LIR_OpVisitState* state); int id() const { return _id; } @@ -1400,7 +1401,7 @@ class LIR_Op1: public LIR_Op { virtual bool is_patching() { return _patch != lir_patch_none; } virtual void emit_code(LIR_Assembler* masm); virtual LIR_Op1* as_Op1() { return this; } - virtual const char * name() const PRODUCT_RETURN0; + virtual const char * name() const PRODUCT_RETURN_NULL; void set_in_opr(LIR_Opr opr) { _opr = opr; } diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp index bcccff2fe82ec..b0afcb5279522 100644 --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -74,7 +74,7 @@ class TemplateInterpreterGenerator: public AbstractInterpreterGenerator { void set_safepoints_for_all_bytes(); // Helpers for generate_and_dispatch - address generate_trace_code(TosState state) PRODUCT_RETURN0; + address generate_trace_code(TosState state) PRODUCT_RETURN_NULL; void count_bytecode() PRODUCT_RETURN; void histogram_bytecode(Template* t) PRODUCT_RETURN; void histogram_bytecode_pair(Template* t) PRODUCT_RETURN; diff --git a/src/hotspot/share/oops/constantPool.hpp b/src/hotspot/share/oops/constantPool.hpp index 7a17c62ddaf99..bcc9a08dd6ca0 100644 --- a/src/hotspot/share/oops/constantPool.hpp +++ b/src/hotspot/share/oops/constantPool.hpp @@ -37,6 +37,7 @@ #include "utilities/align.hpp" #include "utilities/bytes.hpp" #include "utilities/constantTag.hpp" +#include "utilities/macros.hpp" #include "utilities/resourceHash.hpp" // A ConstantPool is an array containing class constants as described in the @@ -781,7 +782,7 @@ class ConstantPool : public Metadata { int pre_resolve_shared_klasses(TRAPS); // Debugging - const char* printable_name_at(int cp_index) PRODUCT_RETURN0; + const char* printable_name_at(int cp_index) PRODUCT_RETURN_NULL; private: diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 85d206749f6be..323ab3dba7d65 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -124,11 +124,7 @@ class MemNode : public Node { // Raw access function, to allow copying of adr_type efficiently in // product builds and retain the debug info for debug builds. const TypePtr *raw_adr_type() const { -#ifdef ASSERT - return _adr_type; -#else - return 0; -#endif + return DEBUG_ONLY(_adr_type) NOT_DEBUG(nullptr); } // Return the barrier data of n, if available, or 0 otherwise. diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index 1034dec0d9aaa..23094c9e8c4ac 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -338,6 +338,7 @@ #define NOT_PRODUCT_ARG(arg) #define PRODUCT_RETURN {} #define PRODUCT_RETURN0 { return 0; } +#define PRODUCT_RETURN_NULL { return nullptr; } #define PRODUCT_RETURN_(code) { code } #else // PRODUCT #define PRODUCT_ONLY(code) @@ -345,6 +346,7 @@ #define NOT_PRODUCT_ARG(arg) arg, #define PRODUCT_RETURN /*next token must be ;*/ #define PRODUCT_RETURN0 /*next token must be ;*/ +#define PRODUCT_RETURN_NULL /* next token must be ;*/ #define PRODUCT_RETURN_(code) /*next token must be ;*/ #endif // PRODUCT From 57c1db5843db5f2c864318f3234767f436a836e3 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Wed, 2 Oct 2024 22:54:18 +0000 Subject: [PATCH 107/188] 8332697: ubsan: shenandoahSimpleBitMap.inline.hpp:68:23: runtime error: signed integer overflow: -9223372036854775808 - 1 cannot be represented in type 'long int' Reviewed-by: phh, kdnilsen --- .../gc/shenandoah/shenandoahSimpleBitMap.cpp | 34 +++++++++---------- .../gc/shenandoah/shenandoahSimpleBitMap.hpp | 12 +++---- .../shenandoahSimpleBitMap.inline.hpp | 15 +++++--- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp index c3e8108752fed..127e6324fb01e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp @@ -23,7 +23,7 @@ */ #include "precompiled.hpp" -#include "gc/shenandoah/shenandoahSimpleBitMap.hpp" +#include "gc/shenandoah/shenandoahSimpleBitMap.inline.hpp" ShenandoahSimpleBitMap::ShenandoahSimpleBitMap(size_t num_bits) : _num_bits(num_bits), @@ -43,8 +43,8 @@ size_t ShenandoahSimpleBitMap::count_leading_ones(idx_t start_idx) const { assert((start_idx >= 0) && (start_idx < _num_bits), "precondition"); size_t array_idx = start_idx >> LogBitsPerWord; uintx element_bits = _bitmap[array_idx]; - uintx bit_number = start_idx & right_n_bits(LogBitsPerWord); - uintx mask = ~right_n_bits(bit_number); + uintx bit_number = start_idx & (BitsPerWord - 1); + uintx mask = ~tail_mask(bit_number); size_t counted_ones = 0; while ((element_bits & mask) == mask) { // All bits numbered >= bit_number are set @@ -54,7 +54,7 @@ size_t ShenandoahSimpleBitMap::count_leading_ones(idx_t start_idx) const { // Strength reduction: array_idx = (start_idx >> LogBitsPerWord) array_idx++; element_bits = _bitmap[array_idx]; - // Constant folding: bit_number = start_idx & right_n_bits(LogBitsPerWord); + // Constant folding: bit_number = start_idx & (BitsPerWord - 1); bit_number = 0; // Constant folding: mask = ~right_n_bits(bit_number); mask = ~0; @@ -70,9 +70,9 @@ size_t ShenandoahSimpleBitMap::count_trailing_ones(idx_t last_idx) const { assert((last_idx >= 0) && (last_idx < _num_bits), "precondition"); size_t array_idx = last_idx >> LogBitsPerWord; uintx element_bits = _bitmap[array_idx]; - uintx bit_number = last_idx & right_n_bits(LogBitsPerWord); + uintx bit_number = last_idx & (BitsPerWord - 1); // All ones from bit 0 to the_bit - uintx mask = right_n_bits(bit_number + 1); + uintx mask = tail_mask(bit_number + 1); size_t counted_ones = 0; while ((element_bits & mask) == mask) { // All bits numbered <= bit_number are set @@ -81,7 +81,7 @@ size_t ShenandoahSimpleBitMap::count_trailing_ones(idx_t last_idx) const { // Dead code: do not need to compute: last_idx -= found_ones; array_idx--; element_bits = _bitmap[array_idx]; - // Constant folding: bit_number = last_idx & right_n_bits(LogBitsPerWord); + // Constant folding: bit_number = last_idx & (BitsPerWord - 1); bit_number = BitsPerWord - 1; // Constant folding: mask = right_n_bits(bit_number + 1); mask = ~0; @@ -99,7 +99,7 @@ bool ShenandoahSimpleBitMap::is_forward_consecutive_ones(idx_t start_idx, idx_t start_idx, count); assert(start_idx + count <= (idx_t) _num_bits, "precondition"); size_t array_idx = start_idx >> LogBitsPerWord; - uintx bit_number = start_idx & right_n_bits(LogBitsPerWord); + uintx bit_number = start_idx & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; uintx bits_to_examine = BitsPerWord - bit_number; element_bits >>= bit_number; @@ -128,7 +128,7 @@ bool ShenandoahSimpleBitMap::is_backward_consecutive_ones(idx_t last_idx, idx_t assert((last_idx >= 0) && (last_idx < _num_bits), "precondition"); assert(last_idx - count >= -1, "precondition"); size_t array_idx = last_idx >> LogBitsPerWord; - uintx bit_number = last_idx & right_n_bits(LogBitsPerWord); + uintx bit_number = last_idx & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; uintx bits_to_examine = bit_number + 1; element_bits <<= (BitsPerWord - bits_to_examine); @@ -161,10 +161,10 @@ idx_t ShenandoahSimpleBitMap::find_first_consecutive_set_bits(idx_t beg, idx_t e return end; } uintx array_idx = beg >> LogBitsPerWord; - uintx bit_number = beg & right_n_bits(LogBitsPerWord); + uintx bit_number = beg & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; if (bit_number > 0) { - uintx mask_out = right_n_bits(bit_number); + uintx mask_out = tail_mask(bit_number); element_bits &= ~mask_out; } @@ -222,9 +222,9 @@ idx_t ShenandoahSimpleBitMap::find_first_consecutive_set_bits(idx_t beg, idx_t e } array_idx = beg >> LogBitsPerWord; element_bits = _bitmap[array_idx]; - bit_number = beg & right_n_bits(LogBitsPerWord); + bit_number = beg & (BitsPerWord - 1); if (bit_number > 0) { - size_t mask_out = right_n_bits(bit_number); + size_t mask_out = tail_mask(bit_number); element_bits &= ~mask_out; } } @@ -242,10 +242,10 @@ idx_t ShenandoahSimpleBitMap::find_last_consecutive_set_bits(const idx_t beg, id } size_t array_idx = end >> LogBitsPerWord; - uintx bit_number = end & right_n_bits(LogBitsPerWord); + uintx bit_number = end & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; if (bit_number < BitsPerWord - 1) { - uintx mask_in = right_n_bits(bit_number + 1); + uintx mask_in = tail_mask(bit_number + 1); element_bits &= mask_in; } @@ -280,10 +280,10 @@ idx_t ShenandoahSimpleBitMap::find_last_consecutive_set_bits(const idx_t beg, id return beg; } array_idx = end >> LogBitsPerWord; - bit_number = end & right_n_bits(LogBitsPerWord); + bit_number = end & (BitsPerWord - 1); element_bits = _bitmap[array_idx]; if (bit_number < BitsPerWord - 1){ - size_t mask_in = right_n_bits(bit_number + 1); + size_t mask_in = tail_mask(bit_number + 1); element_bits &= mask_in; } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp index c22e952700204..6b95303fb3341 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp @@ -50,7 +50,7 @@ typedef ssize_t idx_t; // ShenandoahSimpleBitMap resembles CHeapBitMap but adds missing support for find_first_consecutive_set_bits() and // find_last_consecutive_set_bits. An alternative refactoring of code would subclass CHeapBitMap, but this might // break abstraction rules, because efficient implementation requires assumptions about superclass internals that -// might be violatee through future software maintenance. +// might be violated through future software maintenance. class ShenandoahSimpleBitMap { const idx_t _num_bits; const size_t _num_words; @@ -84,7 +84,7 @@ class ShenandoahSimpleBitMap { inline idx_t aligned_index(idx_t idx) const { assert((idx >= 0) && (idx < _num_bits), "precondition"); - idx_t array_idx = idx & ~right_n_bits(LogBitsPerWord); + idx_t array_idx = idx & ~(BitsPerWord - 1); return array_idx; } @@ -107,7 +107,7 @@ class ShenandoahSimpleBitMap { inline void set_bit(idx_t idx) { assert((idx >= 0) && (idx < _num_bits), "precondition"); size_t array_idx = idx >> LogBitsPerWord; - uintx bit_number = idx & right_n_bits(LogBitsPerWord); + uintx bit_number = idx & (BitsPerWord - 1); uintx the_bit = nth_bit(bit_number); _bitmap[array_idx] |= the_bit; } @@ -116,7 +116,7 @@ class ShenandoahSimpleBitMap { assert((idx >= 0) && (idx < _num_bits), "precondition"); assert(idx >= 0, "precondition"); size_t array_idx = idx >> LogBitsPerWord; - uintx bit_number = idx & right_n_bits(LogBitsPerWord); + uintx bit_number = idx & (BitsPerWord - 1); uintx the_bit = nth_bit(bit_number); _bitmap[array_idx] &= ~the_bit; } @@ -125,9 +125,9 @@ class ShenandoahSimpleBitMap { assert((idx >= 0) && (idx < _num_bits), "precondition"); assert(idx >= 0, "precondition"); size_t array_idx = idx >> LogBitsPerWord; - uintx bit_number = idx & right_n_bits(LogBitsPerWord); + uintx bit_number = idx & (BitsPerWord - 1); uintx the_bit = nth_bit(bit_number); - return (_bitmap[array_idx] & the_bit)? true: false; + return (_bitmap[array_idx] & the_bit) != 0; } // Return the index of the first set bit in the range [beg, size()), or size() if none found. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp index 3e602ed11e0c0..c047e1ed66349 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp @@ -27,15 +27,22 @@ #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" +inline uintx tail_mask(uintx bit_number) { + if (bit_number >= BitsPerWord) { + return -1; + } + return (uintx(1) << bit_number) - 1; +} + inline idx_t ShenandoahSimpleBitMap::find_first_set_bit(idx_t beg, idx_t end) const { assert((beg >= 0) && (beg < _num_bits), "precondition"); assert((end > beg) && (end <= _num_bits), "precondition"); do { size_t array_idx = beg >> LogBitsPerWord; - uintx bit_number = beg & right_n_bits(LogBitsPerWord); + uintx bit_number = beg & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; if (bit_number > 0) { - uintx mask_out = right_n_bits(bit_number); + uintx mask_out = tail_mask(bit_number); element_bits &= ~mask_out; } if (element_bits) { @@ -62,10 +69,10 @@ inline idx_t ShenandoahSimpleBitMap::find_last_set_bit(idx_t beg, idx_t end) con assert((beg >= -1) && (beg < end), "precondition"); do { idx_t array_idx = end >> LogBitsPerWord; - uintx bit_number = end & right_n_bits(LogBitsPerWord); + uint8_t bit_number = end & (BitsPerWord - 1); uintx element_bits = _bitmap[array_idx]; if (bit_number < BitsPerWord - 1){ - uintx mask_in = right_n_bits(bit_number + 1); + uintx mask_in = tail_mask(bit_number + 1); element_bits &= mask_in; } if (element_bits) { From bdfb41f977258831e4b0ceaef5d016d095ab6e7f Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 2 Oct 2024 22:55:50 +0000 Subject: [PATCH 108/188] 8309841: Jarsigner should print a warning if an entry is removed Reviewed-by: mullan, hchao --- .../sun/security/tools/jarsigner/Main.java | 16 ++++ .../security/tools/jarsigner/Resources.java | 2 + .../tools/jarsigner/RemovedFiles.java | 94 +++++++++++++++++++ .../jdk/test/lib/util/JarUtilsTest.java | 77 +++++++++++++++ test/lib/jdk/test/lib/util/JarUtils.java | 53 ++++++++++- 5 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 test/jdk/sun/security/tools/jarsigner/RemovedFiles.java create mode 100644 test/lib-test/jdk/test/lib/util/JarUtilsTest.java diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java index 78a03a4332d47..014b420e1a237 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java @@ -197,6 +197,7 @@ public ExitException(int errorCode) { private boolean hasExpiringCert = false; private boolean hasExpiringTsaCert = false; private boolean noTimestamp = true; + private boolean hasNonexistentEntries = false; // Expiration date. The value could be null if signed by a trusted cert. private Date expireDate = null; @@ -735,6 +736,7 @@ void verifyJar(String jarName) Map sigMap = new HashMap<>(); Map sigNameMap = new HashMap<>(); Map unparsableSignatures = new HashMap<>(); + Map> entriesInSF = new HashMap<>(); try { jf = new JarFile(jarName, true); @@ -782,6 +784,7 @@ void verifyJar(String jarName) break; } } + entriesInSF.put(alias, sf.getEntries().keySet()); if (!found) { unparsableSignatures.putIfAbsent(alias, String.format( @@ -881,6 +884,9 @@ void verifyJar(String jarName) sb.append('\n'); } } + for (var signed : entriesInSF.values()) { + signed.remove(name); + } } else if (showcerts && !verbose.equals("all")) { // Print no info for unsigned entries when -verbose:all, // to be consistent with old behavior. @@ -1076,6 +1082,13 @@ void verifyJar(String jarName) if (verbose != null) { System.out.println(history); } + var signed = entriesInSF.get(s); + if (!signed.isEmpty()) { + if (verbose != null) { + System.out.println(rb.getString("history.nonexistent.entries") + signed); + } + hasNonexistentEntries = true; + } } else { unparsableSignatures.putIfAbsent(s, String.format( rb.getString("history.nobk"), s)); @@ -1311,6 +1324,9 @@ private void displayMessagesAndResult(boolean isSigning) { } } + if (hasNonexistentEntries) { + warnings.add(rb.getString("nonexistent.entries.found")); + } if (externalFileAttributesDetected) { warnings.add(rb.getString("external.file.attributes.detected")); } diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java index 6a86b72ad1b10..810bd107bdebc 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java @@ -164,6 +164,7 @@ public class Resources extends java.util.ListResourceBundle { {"history.with.ts", "- Signed by \"%1$s\"\n Digest algorithm: %2$s\n Signature algorithm: %3$s, %4$s\n Timestamped by \"%6$s\" on %5$tc\n Timestamp digest algorithm: %7$s\n Timestamp signature algorithm: %8$s, %9$s"}, {"history.without.ts", "- Signed by \"%1$s\"\n Digest algorithm: %2$s\n Signature algorithm: %3$s, %4$s"}, + {"history.nonexistent.entries", " Warning: nonexistent signed entries: "}, {"history.unparsable", "- Unparsable signature-related file %s"}, {"history.nosf", "- Missing signature-related file META-INF/%s.SF"}, {"history.nobk", "- Missing block file for signature-related file META-INF/%s.SF"}, @@ -178,6 +179,7 @@ public class Resources extends java.util.ListResourceBundle { {"key.bit.disabled", "%d-bit key (disabled)"}, {"key.bit.eccurve.disabled", "%1$d-bit %2$s key (disabled)"}, {"unknown.size", "unknown size"}, + {"nonexistent.entries.found", "This jar contains signed entries for files that do not exist. See the -verbose output for more details."}, {"external.file.attributes.detected", "POSIX file permission and/or symlink attributes detected. These attributes are ignored when signing and are not protected by the signature."}, {"jarsigner.", "jarsigner: "}, diff --git a/test/jdk/sun/security/tools/jarsigner/RemovedFiles.java b/test/jdk/sun/security/tools/jarsigner/RemovedFiles.java new file mode 100644 index 0000000000000..598e25a9a709b --- /dev/null +++ b/test/jdk/sun/security/tools/jarsigner/RemovedFiles.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8309841 + * @summary Jarsigner should print a warning if an entry is removed + * @library /test/lib + */ + +import jdk.test.lib.SecurityTools; +import jdk.test.lib.util.JarUtils; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +public class RemovedFiles { + + private static final String NONEXISTENT_ENTRIES_FOUND + = "This jar contains signed entries for files that do not exist. See the -verbose output for more details."; + + public static void main(String[] args) throws Exception { + JarUtils.createJarFile( + Path.of("a.jar"), + Path.of("."), + Files.writeString(Path.of("a"), "a"), + Files.writeString(Path.of("b"), "b")); + SecurityTools.keytool("-genkeypair -storepass changeit -keystore ks -alias x -dname CN=x -keyalg ed25519"); + SecurityTools.jarsigner("-storepass changeit -keystore ks a.jar x"); + + // All is fine at the beginning. + SecurityTools.jarsigner("-verify a.jar") + .shouldNotContain(NONEXISTENT_ENTRIES_FOUND); + + // Remove an entry after signing. There will be a warning. + JarUtils.deleteEntries(Path.of("a.jar"), "a"); + SecurityTools.jarsigner("-verify a.jar") + .shouldContain(NONEXISTENT_ENTRIES_FOUND); + SecurityTools.jarsigner("-verify -verbose a.jar") + .shouldContain(NONEXISTENT_ENTRIES_FOUND) + .shouldContain("Warning: nonexistent signed entries: [a]"); + + // Remove one more entry. + JarUtils.deleteEntries(Path.of("a.jar"), "b"); + SecurityTools.jarsigner("-verify a.jar") + .shouldContain(NONEXISTENT_ENTRIES_FOUND); + SecurityTools.jarsigner("-verify -verbose a.jar") + .shouldContain(NONEXISTENT_ENTRIES_FOUND) + .shouldContain("Warning: nonexistent signed entries: [a, b]"); + + // Re-sign will not clear the warning. + SecurityTools.jarsigner("-storepass changeit -keystore ks a.jar x"); + SecurityTools.jarsigner("-verify a.jar") + .shouldContain(NONEXISTENT_ENTRIES_FOUND); + + // Unfortunately, if there is a non-file entry in manifest, there will be + // a false alarm. See https://bugs.openjdk.org/browse/JDK-8334261. + var man = new Manifest(); + man.getMainAttributes().putValue("Manifest-Version", "1.0"); + man.getEntries().computeIfAbsent("Hello", _ -> new Attributes()) + .putValue("Foo", "Bar"); + JarUtils.createJarFile(Path.of("b.jar"), + man, + Path.of("."), + Path.of("a")); + SecurityTools.jarsigner("-storepass changeit -keystore ks b.jar x"); + SecurityTools.jarsigner("-verbose -verify b.jar") + .shouldContain("Warning: nonexistent signed entries: [Hello]") + .shouldContain(NONEXISTENT_ENTRIES_FOUND); + + } +} diff --git a/test/lib-test/jdk/test/lib/util/JarUtilsTest.java b/test/lib-test/jdk/test/lib/util/JarUtilsTest.java new file mode 100644 index 0000000000000..eb9dced32569a --- /dev/null +++ b/test/lib-test/jdk/test/lib/util/JarUtilsTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8309841 + * @summary Unit Test for a common Test API in jdk.test.lib.util.JarUtils + * @library /test/lib + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.util.JarUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.stream.Collectors; + +public class JarUtilsTest { + public static void main(String[] args) throws Exception { + Files.createDirectory(Path.of("bx")); + JarUtils.createJarFile(Path.of("a.jar"), + Path.of("."), + Files.writeString(Path.of("a"), ""), + Files.writeString(Path.of("b1"), ""), + Files.writeString(Path.of("b2"), ""), + Files.writeString(Path.of("bx/x"), ""), + Files.writeString(Path.of("c"), ""), + Files.writeString(Path.of("e1"), ""), + Files.writeString(Path.of("e2"), "")); + checkContent("a", "b1", "b2", "bx/x", "c", "e1", "e2"); + + JarUtils.deleteEntries(Path.of("a.jar"), "a"); + checkContent("b1", "b2", "bx/x", "c", "e1", "e2"); + + // Note: b* covers everything starting with b, even bx/x + JarUtils.deleteEntries(Path.of("a.jar"), "b*"); + checkContent("c", "e1", "e2"); + + // d* does not match + JarUtils.deleteEntries(Path.of("a.jar"), "d*"); + checkContent("c", "e1", "e2"); + + // multiple patterns + JarUtils.deleteEntries(Path.of("a.jar"), "d*", "e*"); + checkContent("c"); + } + + static void checkContent(String... expected) throws IOException { + try (var jf = new JarFile("a.jar")) { + Asserts.assertEquals(Set.of(expected), + jf.stream().map(JarEntry::getName).collect(Collectors.toSet())); + } + } +} diff --git a/test/lib/jdk/test/lib/util/JarUtils.java b/test/lib/jdk/test/lib/util/JarUtils.java index e1b3ccac19fc5..3aa4ada5197ad 100644 --- a/test/lib/jdk/test/lib/util/JarUtils.java +++ b/test/lib/jdk/test/lib/util/JarUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -320,6 +320,57 @@ public static void updateManifest(String src, String dest, Manifest man) updateJar(src, dest, Map.of(JarFile.MANIFEST_NAME, bout.toByteArray())); } + /** + * Remove entries from a ZIP file. + * + * Each entry can be a name or a name ending with "*". + * + * @return number of removed entries + * @throws IOException if there is any I/O error + */ + public static int deleteEntries(Path jarfile, String... patterns) + throws IOException { + Path tmpfile = Files.createTempFile("jar", "jar"); + int count = 0; + + try (OutputStream out = Files.newOutputStream(tmpfile); + JarOutputStream jos = new JarOutputStream(out)) { + try (JarFile jf = new JarFile(jarfile.toString())) { + Enumeration jentries = jf.entries(); + top: while (jentries.hasMoreElements()) { + JarEntry jentry = jentries.nextElement(); + String name = jentry.getName(); + for (String pattern : patterns) { + if (pattern.endsWith("*")) { + if (name.startsWith(pattern.substring( + 0, pattern.length() - 1))) { + // Go directly to next entry. This + // one is not written into `jos` and + // therefore removed. + count++; + continue top; + } + } else { + if (name.equals(pattern)) { + // Same as above + count++; + continue top; + } + } + } + // No pattern matched, file retained + jos.putNextEntry(copyEntry(jentry)); + jf.getInputStream(jentry).transferTo(jos); + } + } + } + + // replace the original JAR file + Files.move(tmpfile, jarfile, StandardCopyOption.REPLACE_EXISTING); + + return count; + } + private static void updateEntry(JarOutputStream jos, String name, Object content) throws IOException { if (content instanceof Boolean) { From 602408e4f3848b30299ea94264e88ead5361a310 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 3 Oct 2024 02:51:23 +0000 Subject: [PATCH 109/188] 8341177: Opensource few List and a Window test Reviewed-by: prr --- .../awt/List/ActionEventWhenHitEnterTest.java | 126 ++++++++++++++++++ test/jdk/java/awt/List/ListAddPerfTest.java | 99 ++++++++++++++ ...MouseDraggedOriginatedByScrollBarTest.java | 103 ++++++++++++++ test/jdk/java/awt/Window/bug4189244.java | 120 +++++++++++++++++ 4 files changed, 448 insertions(+) create mode 100644 test/jdk/java/awt/List/ActionEventWhenHitEnterTest.java create mode 100644 test/jdk/java/awt/List/ListAddPerfTest.java create mode 100644 test/jdk/java/awt/List/MouseDraggedOriginatedByScrollBarTest.java create mode 100644 test/jdk/java/awt/Window/bug4189244.java diff --git a/test/jdk/java/awt/List/ActionEventWhenHitEnterTest.java b/test/jdk/java/awt/List/ActionEventWhenHitEnterTest.java new file mode 100644 index 0000000000000..232189ef53bbb --- /dev/null +++ b/test/jdk/java/awt/List/ActionEventWhenHitEnterTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4234245 + * @summary the actionEvent is not invoked when hit enter on list. + * @key headful + * @run main ActionEventWhenHitEnterTest + */ + +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.IllegalComponentStateException; +import java.awt.List; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; + +public class ActionEventWhenHitEnterTest + implements ActionListener, ItemListener { + + volatile boolean passed1; + volatile boolean passed2; + volatile Point pt; + List list; + Frame frame; + + public static void main(final String[] args) throws Exception { + ActionEventWhenHitEnterTest app = new ActionEventWhenHitEnterTest(); + app.doTest(); + } + + public ActionEventWhenHitEnterTest() { + list = new List(7); + for (int i = 0; i < 10; i++) { + list.add("Item " + i); + } + list.addItemListener(this); + list.addActionListener(this); + } + + public void actionPerformed(ActionEvent ae) { + passed1 = true; + System.out.println("--> Action event invoked: " + ae.getSource()); + } + + public void itemStateChanged(ItemEvent ie) { + passed2 = true; + System.out.println("--> Item state changed:" + ie.getSource()); + } + + public void doTest() throws Exception { + EventQueue.invokeAndWait(() -> { + frame = new Frame("ActionEventWhenHitEnterTest"); + frame.add(list); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + }); + + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + pt = list.getLocationOnScreen(); + }); + + if (pt.x != 0 || pt.y != 0) { + robot.mouseMove(pt.x + list.getWidth() / 2, + pt.y + list.getHeight() / 2); + robot.waitForIdle(); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + } + + robot.waitForIdle(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + + if (!passed1 || !passed2) { + throw new RuntimeException("ActionEventWhenHitEnterTest FAILED"); + } + System.out.println("Test PASSED"); + + } + +} diff --git a/test/jdk/java/awt/List/ListAddPerfTest.java b/test/jdk/java/awt/List/ListAddPerfTest.java new file mode 100644 index 0000000000000..7ff3eaf882c62 --- /dev/null +++ b/test/jdk/java/awt/List/ListAddPerfTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4117288 + * @summary JDKversion1.2beta3-J List's add() method is much slower. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ListAddPerfTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Frame; +import java.awt.List; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ListAddPerfTest { + + static Button button; + static List list; + + private static final String INSTRUCTIONS = """ + It is used to check the performance of List add operation. + + Instructions: + Click on the Remove All button. + The list should be cleared. + The button is now named "Add Items". + Click on the "Add Items" button. + 800 items should be added to the list. + Notice not only how fast or slow this is, but also how + 'smooth' it goes as well i.e. without any flashing. + + Press pass if the list performance is acceptable."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ListAddPerfTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ListAddPerfTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("ListAddPerfTest"); + frame.setLayout(new BorderLayout()); + + button = new Button("Remove All"); + button.addActionListener((ActionEvent e) -> { + if (list.getItemCount() > 0) { + list.removeAll(); + list.invalidate(); + button.setLabel("Add Items"); + } else { + for (int i = 0; i < 800; i ++) { + list.add("My number is " + i); + } + button.setLabel("Remove All"); + } + }); + + list = new List(15); + for (int i = 0; i < 800; i ++) { + list.add("My number is " + i); + } + + frame.add("North", button); + frame.add("South", list); + + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/List/MouseDraggedOriginatedByScrollBarTest.java b/test/jdk/java/awt/List/MouseDraggedOriginatedByScrollBarTest.java new file mode 100644 index 0000000000000..600d38fe39380 --- /dev/null +++ b/test/jdk/java/awt/List/MouseDraggedOriginatedByScrollBarTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6240151 + * @summary XToolkit: Dragging the List scrollbar initiates DnD + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseDraggedOriginatedByScrollBarTest +*/ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class MouseDraggedOriginatedByScrollBarTest { + + private static final String INSTRUCTIONS = """ + 1) Click and drag the scrollbar of the list. + 2) Keep dragging till the mouse pointer goes out the scrollbar. + 3) The test failed if you see messages about events. The test passed if you don't."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("MouseDraggedOriginatedByScrollBarTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MouseDraggedOriginatedByScrollBarTest::createTestUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame(); + List list = new List(4, false); + + list.add("000"); + list.add("111"); + list.add("222"); + list.add("333"); + list.add("444"); + list.add("555"); + list.add("666"); + list.add("777"); + list.add("888"); + list.add("999"); + + frame.add(list); + + list.addMouseMotionListener( + new MouseMotionAdapter(){ + @Override + public void mouseDragged(MouseEvent me){ + PassFailJFrame.log(me.toString()); + } + }); + + list.addMouseListener( + new MouseAdapter() { + public void mousePressed(MouseEvent me) { + PassFailJFrame.log(me.toString()); + } + + public void mouseReleased(MouseEvent me) { + PassFailJFrame.log(me.toString()); + } + + public void mouseClicked(MouseEvent me){ + PassFailJFrame.log(me.toString()); + } + }); + + frame.setLayout(new FlowLayout()); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/Window/bug4189244.java b/test/jdk/java/awt/Window/bug4189244.java new file mode 100644 index 0000000000000..df37d2fce0e2b --- /dev/null +++ b/test/jdk/java/awt/Window/bug4189244.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4189244 + * @summary Swing Popup menu is not being refreshed (cleared) under a Dialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @requires (os.family == "windows") + * @run main/manual bug4189244 +*/ + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; + +public class bug4189244 { + + private static final String INSTRUCTIONS = """ + This is Windows only test! + + Click right button on frame to show popup menu. + (menu should be placed inside frame otherwise bug is not reproducible) + click on any menu item (dialog will be shown). + close dialog. + if you see part of popupmenu, under dialog, before it is closed, + then test failed, else passed."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("bug4189244 Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(bug4189244::createTestUI) + .build() + .awaitAndCheck(); + } + + + private static JFrame createTestUI() { + RefreshBug panel = new RefreshBug(); + JFrame frame = new JFrame("Popup refresh bug"); + + frame.add(panel, BorderLayout.CENTER); + panel.init(); + frame.setSize(400, 400); + return frame; + } +} + +class RefreshBug extends JPanel implements ActionListener { + JPopupMenu _jPopupMenu = new JPopupMenu(); + + public void init() { + JMenuItem menuItem; + JButton jb = new JButton("Bring the popup here and select an item"); + + this.add(jb, BorderLayout.CENTER); + + for(int i = 1; i < 10; i++) { + menuItem = new JMenuItem("Item " + i); + menuItem.addActionListener(this); + _jPopupMenu.add(menuItem); + } + + MouseListener ml = new MouseAdapter() { + public void mouseReleased(MouseEvent e) { + if (e.isPopupTrigger()) { + _jPopupMenu.show(e.getComponent(), + e.getX(), e.getY()); + } + } + }; + this.addMouseListener(ml); + + jb.addMouseListener(ml); + + } + + // An action is requested by the user + public void actionPerformed(java.awt.event.ActionEvent e) { + JOptionPane.showMessageDialog(this, + "Check if there is some popup left under me\n"+ + "if not, retry and let the popup appear where i am", + "WARNING", + JOptionPane.WARNING_MESSAGE); + + } +} From 50ec169116b486a49dc2dcb4218264bd48db79cc Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 3 Oct 2024 04:16:10 +0000 Subject: [PATCH 110/188] 8341191: Open source few more AWT FileDialog tests Reviewed-by: prr, psadhukhan --- .../FileDialog/KeyboardInteractionTest.java | 87 +++++++++++++++++++ .../awt/FileDialog/PathChoiceDisposeTest.java | 76 ++++++++++++++++ .../FileDialog/PathChoiceWorkArrowsTest.java | 86 ++++++++++++++++++ .../java/awt/FileDialog/SavedDirInitTest.java | 79 +++++++++++++++++ 4 files changed, 328 insertions(+) create mode 100644 test/jdk/java/awt/FileDialog/KeyboardInteractionTest.java create mode 100644 test/jdk/java/awt/FileDialog/PathChoiceDisposeTest.java create mode 100644 test/jdk/java/awt/FileDialog/PathChoiceWorkArrowsTest.java create mode 100644 test/jdk/java/awt/FileDialog/SavedDirInitTest.java diff --git a/test/jdk/java/awt/FileDialog/KeyboardInteractionTest.java b/test/jdk/java/awt/FileDialog/KeyboardInteractionTest.java new file mode 100644 index 0000000000000..f919a8a338af8 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/KeyboardInteractionTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6259434 + * @summary PIT: Choice in FileDialog is not responding to keyboard interactions, XToolkit + * @requires (os.family == "linux") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual KeyboardInteractionTest + */ + +public class KeyboardInteractionTest { + public static void main(String[] args) throws Exception { + System.setProperty("sun.awt.disableGtkFileDialogs", "true"); + String INSTRUCTIONS = """ + 1) Click on 'Show File Dialog' button to bring up the FileDialog window. + A file dialog will come up. + 2) You will see a text field 'Enter full path or filename'. + Right next to it, you will see a button. + Transfer the focus on this button using 'TAB'. + Make sure that the popup choice is not shown. + 3) Press 'ESC'. If file dialog isn't disposed, then the test failed. + 4) Again, click on 'Show File Dialog' to bring up the file dialog. + A file dialog will come up. + 5) You will see a text field 'Enter full path or filename'. + Right next to it, you will see a button. + Click on this button. The popup choice will appear. + 6) Look at the popup choice. Change the current item in the popup + choice by the arrow keys. + If the text in the 'Enter full path or filename' text field isn't + changed, then the test failed. + 7) The test passed. + """; + + PassFailJFrame.builder() + .title("KeyboardInteractionTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(KeyboardInteractionTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("KeyboardInteractionTest Test"); + Button b = new Button("Show File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setVisible(true); + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/FileDialog/PathChoiceDisposeTest.java b/test/jdk/java/awt/FileDialog/PathChoiceDisposeTest.java new file mode 100644 index 0000000000000..267b2a807cff8 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/PathChoiceDisposeTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6240084 + * @summary Test that disposing unfurled list by the pressing ESC + * in FileDialog is working properly on XToolkit + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PathChoiceDisposeTest + */ + +public class PathChoiceDisposeTest { + public static void main(String[] args) throws Exception { + System.setProperty("sun.awt.disableGtkFileDialogs", "true"); + String INSTRUCTIONS = """ + 1) Click on 'Show File Dialog' button to bring up the FileDialog window. + 2) Open the directory selection choice by clicking button next to + 'Enter Path or Folder Name'. A drop-down will appear. + 3) Press 'ESC'. + 4) If you see that the dialog gets disposed and the popup + still remains on the screen, the test failed, otherwise passed. + """; + + PassFailJFrame.builder() + .title("PathChoiceDisposeTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(PathChoiceDisposeTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("PathChoiceDisposeTest Test"); + Button b = new Button("Show File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setVisible(true); + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/FileDialog/PathChoiceWorkArrowsTest.java b/test/jdk/java/awt/FileDialog/PathChoiceWorkArrowsTest.java new file mode 100644 index 0000000000000..17aee8abb800a --- /dev/null +++ b/test/jdk/java/awt/FileDialog/PathChoiceWorkArrowsTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6240074 + * @summary Test that file drop-down field in FileDialog is working properly on XToolkit + * @requires (os.family == "linux") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PathChoiceWorkArrowsTest + */ + +public class PathChoiceWorkArrowsTest { + public static void main(String[] args) throws Exception { + System.setProperty("sun.awt.disableGtkFileDialogs", "true"); + String INSTRUCTIONS = """ + This is only XAWT test. + + 1) Click on 'Show File Dialog' to bring up the FileDialog window. + A file dialog would come up. + 2) Click on the button next to 'Enter folder name' field. + A drop-down will appear. After this, there are 2 scenarios. + 3) Press the down arrow one by one. You will see a '/' being + appended as soon as the current entry is removed. + Keep pressing till the last entry is reached. Now the drop-down + will stop responding to arrow keys. If yes, the test failed. + 4) Press the up arrow. The cursor will directly go to the last + entry ('/') and navigation will stop there. You will see 2 + entries being selected at the same time. + If yes, the test failed. + """; + + PassFailJFrame.builder() + .title("PathChoiceWorkArrowsTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(PathChoiceWorkArrowsTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("PathChoiceWorkArrowsTest Test"); + Button b = new Button("Show File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setSize(200, 200); + fd.setLocation(200, 200); + fd.setVisible(true); + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/FileDialog/SavedDirInitTest.java b/test/jdk/java/awt/FileDialog/SavedDirInitTest.java new file mode 100644 index 0000000000000..7a3b33f55fe16 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/SavedDirInitTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6260650 + * @summary FileDialog.getDirectory() does not return null when file dialog is cancelled + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SavedDirInitTest + */ + +public class SavedDirInitTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click on 'Show File Dialog' button to bring up the FileDialog window. + 1) A file dialog will come up. + 2) Press 'Cancel' button to cancel the file dialog. + 3) The result (passed or failed) will be shown in the message window below. + """; + + PassFailJFrame.builder() + .title("SavedDirInitTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(SavedDirInitTest::createUI) + .logArea(2) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("SavedDirInitTest Test"); + Button b = new Button("Show File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setVisible(true); + if (fd.getDirectory() == null && fd.getFile() == null) { + PassFailJFrame.log("TEST PASSED"); + } else { + PassFailJFrame.log("TEST FAILED. dir = " + fd.getDirectory() + + " , file = " + fd.getFile()); + } + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} From ff3e849b8a1de3741dcd728636e1a804996f96fe Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Thu, 3 Oct 2024 05:31:10 +0000 Subject: [PATCH 111/188] 8341239: Open source closed frame tests # 3 Reviewed-by: prr --- .../jdk/java/awt/Frame/FrameMenuPackTest.java | 99 +++++++++++++++++ .../FrameResizeTest/FrameResizeTest_3.java | 86 ++++++++++++++ .../FrameResizeTest/FrameResizeTest_4.java | 76 +++++++++++++ .../FrameResizeTest/FrameResizeTest_5.java | 105 ++++++++++++++++++ 4 files changed, 366 insertions(+) create mode 100644 test/jdk/java/awt/Frame/FrameMenuPackTest.java create mode 100644 test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_3.java create mode 100644 test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_4.java create mode 100644 test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_5.java diff --git a/test/jdk/java/awt/Frame/FrameMenuPackTest.java b/test/jdk/java/awt/Frame/FrameMenuPackTest.java new file mode 100644 index 0000000000000..c034acd8eb710 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameMenuPackTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.ScrollPane; +import java.awt.Window; +import java.util.List; + +/* + * @test + * @bug 4084766 + * @summary Test for bug(s): 4084766 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameMenuPackTest + */ + +public class FrameMenuPackTest { + private static final String INSTRUCTIONS = """ + Check that both frames that appear are properly packed with + the scrollpane visible. + """; + + public static void main(String[] argv) throws Exception { + PassFailJFrame.builder() + .title("FrameMenuPackTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(FrameMenuPackTest::createAndShowUI) + .positionTestUIRightRow() + .build() + .awaitAndCheck(); + } + + private static List createAndShowUI() { + // Frame without menu, packs correctly + PackedFrame f1 = new PackedFrame(false); + f1.pack(); + + // Frame with menu, doesn't pack right + PackedFrame f2 = new PackedFrame(true); + f2.pack(); + + return List.of(f1, f2); + } + + private static class PackedFrame extends Frame { + public PackedFrame(boolean withMenu) { + super("PackedFrame"); + + MenuBar menubar; + Menu fileMenu; + MenuItem foo; + ScrollPane sp; + + sp = new ScrollPane(); + sp.add(new Label("Label in ScrollPane")); + System.out.println(sp.getMinimumSize()); + + this.setLayout(new BorderLayout()); + this.add(sp, "Center"); + this.add(new Label("Label in Frame"), "South"); + + if (withMenu) { + menubar = new MenuBar(); + fileMenu = new Menu("File"); + foo = new MenuItem("foo"); + fileMenu.add(foo); + menubar.add(fileMenu); + this.setMenuBar(menubar); + } + } + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_3.java b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_3.java new file mode 100644 index 0000000000000..6fdef005775a5 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_3.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Window; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4097207 + * @summary setSize() on a Frame does not resize its content + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizeTest_3 +*/ + +public class FrameResizeTest_3 { + + private static final String INSTRUCTIONS = """ + 1. You would see a frame titled 'TestFrame' with 2 buttons + named 'setSize(500,500)' and 'setSize(400,400)' + 2. Click any button and you would see the frame resized + 3. If the buttons get resized along with the frame + (ie., to fit the frame), press Pass else press Fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FrameResizeTest_3 Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .logArea(6) + .testUI(FrameResizeTest_3::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Window createTestUI() { + Frame frame = new Frame("TestFrame"); + frame.setLayout(new GridLayout(2, 1)); + + Button butSize500 = new Button("setSize(500,500)"); + Button butSize400 = new Button("setSize(400,400)"); + + ActionListener actionListener = e -> { + if (e.getSource() instanceof Button) { + if (e.getSource() == butSize500) { + frame.setSize(500, 500); + PassFailJFrame.log("New bounds: " + frame.getBounds()); + } else if (e.getSource() == butSize400) { + frame.setSize(400, 400); + PassFailJFrame.log("New bounds: " + frame.getBounds()); + } + } + }; + butSize500.addActionListener(actionListener); + butSize400.addActionListener(actionListener); + frame.add(butSize500); + frame.add(butSize400); + + frame.setSize(270, 200); + return frame; + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_4.java b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_4.java new file mode 100644 index 0000000000000..4428feee3355b --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_4.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* Note that although this test makes use of Swing classes, like JFrame and */ +/* JButton, it is really an AWT test, because it tests mechanism of sending */ +/* paint events. */ + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import java.awt.BorderLayout; + +/* + * @test + * @bug 4174831 + * @summary Tests that frame do not flicker on diagonal resize + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizeTest_4 + */ + +public class FrameResizeTest_4 { + private static final String INSTRUCTIONS = """ + Try enlarging the frame diagonally. + If buttons inside frame excessively repaint themselves and flicker + while you enlarge frame, the test fails. + Otherwise, it passes. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FrameResizeTest_4 Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(FrameResizeTest_4::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame f = new JFrame("FrameResizeTest_4 Flickering Frame"); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(new JButton("West"), BorderLayout.WEST); + panel.add(new JButton("East"), BorderLayout.EAST); + panel.add(new JButton("North"), BorderLayout.NORTH); + panel.add(new JButton("South"), BorderLayout.SOUTH); + panel.add(new JButton("Center"), BorderLayout.CENTER); + f.setContentPane(panel); + + f.pack(); + f.setBounds(100, 50, 300, 200); + + return f; + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_5.java b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_5.java new file mode 100644 index 0000000000000..5a43b755a5212 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizeTest/FrameResizeTest_5.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; + +/* + * @test + * @summary Test to make sure non-resizable Frames can be resized with the + * setSize() method. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizeTest_5 +*/ + +public class FrameResizeTest_5 { + private static final String INSTRUCTIONS = """ + This tests the programmatic resizability of non-resizable Frames. + Even when a Frame is set to be non-resizable, it should still be + programmatically resizable using the setSize() method. + + Initially the Frame will be resizable. Try using the "Smaller" + and "Larger" buttons to verify that the Frame resizes correctly. + Then, click the "Toggle" button to make the Frame non-resizable. + Again, verify that clicking the "Larger" and "Smaller" buttons + causes the Frame to get larger and smaller. If the Frame does + not change size, or does not re-layout correctly, the test fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FrameResizeTest_5 Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .logArea(6) + .testUI(TestFrame::new) + .build() + .awaitAndCheck(); + } + + private static class TestFrame extends Frame { + Button bLarger, bSmaller, bCheck, bToggle; + + public TestFrame() { + super("Frame Resize Test"); + setSize(200, 200); + bLarger = new Button("Larger"); + bLarger.addActionListener(e -> { + setSize(400, 400); + validate(); + }); + bSmaller = new Button("Smaller"); + bSmaller.addActionListener(e -> { + setSize(200, 100); + validate(); + }); + bCheck = new Button("Resizable?"); + bCheck.addActionListener(e -> { + if (isResizable()) { + PassFailJFrame.log("Frame is resizable"); + setResizable(true); + } else { + PassFailJFrame.log("Frame is not resizable"); + setResizable(false); + } + }); + bToggle = new Button("Toggle"); + bToggle.addActionListener(e -> { + if (isResizable()) { + PassFailJFrame.log("Frame is now not resizable"); + setResizable(false); + } else { + PassFailJFrame.log("Frame is now resizable"); + setResizable(true); + } + }); + setLayout(new GridLayout(4, 1)); + add(bSmaller); + add(bLarger); + add(bCheck); + add(bToggle); + } + } +} From c6e7e551928c04b74775b5d4c03eb31232aeb2c9 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 3 Oct 2024 07:25:42 +0000 Subject: [PATCH 112/188] 8341091: CDS: Segmented roots array misses roots Reviewed-by: adinn, iklam --- src/hotspot/share/cds/archiveHeapLoader.cpp | 7 ++-- src/hotspot/share/cds/archiveHeapWriter.cpp | 4 ++- src/hotspot/share/cds/archiveUtils.hpp | 1 - src/hotspot/share/cds/heapShared.cpp | 37 +++++++++++++-------- src/hotspot/share/cds/heapShared.hpp | 7 ++-- 5 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/hotspot/share/cds/archiveHeapLoader.cpp b/src/hotspot/share/cds/archiveHeapLoader.cpp index 6325fb6f49d73..0e7ef08064c37 100644 --- a/src/hotspot/share/cds/archiveHeapLoader.cpp +++ b/src/hotspot/share/cds/archiveHeapLoader.cpp @@ -376,13 +376,12 @@ void ArchiveHeapLoader::finish_initialization() { intptr_t bottom = is_loaded() ? _loaded_heap_bottom : _mapped_heap_bottom; // The heap roots are stored in one or more segments that are laid out consecutively. - // The byte size of each segment (except for the last one) is max_size. + // The size of each segment (except for the last one) is max_size_in_{elems,bytes}. HeapRootSegments segments = FileMapInfo::current_info()->heap_root_segments(); - int max_size = segments.max_size_in_bytes(); - HeapShared::init_root_segment_sizes(max_size); + HeapShared::init_root_segment_sizes(segments.max_size_in_elems()); intptr_t first_segment_addr = bottom + segments.base_offset(); for (size_t c = 0; c < segments.count(); c++) { - oop segment_oop = cast_to_oop(first_segment_addr + (c * max_size)); + oop segment_oop = cast_to_oop(first_segment_addr + (c * segments.max_size_in_bytes())); assert(segment_oop->is_objArray(), "Must be"); HeapShared::add_root_segment((objArrayOop)segment_oop); } diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index 853d459c691dd..710e693bfdb14 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -223,6 +223,7 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeapat(root_index++)); @@ -245,6 +245,8 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeaplength(), "Post-condition: All roots are handled"); + _heap_root_segments = segments; } diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp index 2e361ab0c4650..5a78bc26ee627 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.hpp @@ -277,7 +277,6 @@ class HeapRootSegments { memset(this, 0, sizeof(*this)); } HeapRootSegments(size_t base_offset, int roots_count, int max_size_in_bytes, int max_size_in_elems) { - assert(is_power_of_2(max_size_in_bytes), "must be"); memset(this, 0, sizeof(*this)); _base_offset = base_offset; _count = (roots_count + max_size_in_elems - 1) / max_size_in_elems; diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 1f07e972f059a..81aa7ac94dc21 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -136,8 +136,7 @@ static ArchivableStaticFieldInfo fmg_archive_subgraph_entry_fields[] = { KlassSubGraphInfo* HeapShared::_default_subgraph_info; GrowableArrayCHeap* HeapShared::_pending_roots = nullptr; GrowableArrayCHeap* HeapShared::_root_segments; -int HeapShared::_root_segment_max_size_shift; -int HeapShared::_root_segment_max_size_mask; +int HeapShared::_root_segment_max_size_elems; OopHandle HeapShared::_scratch_basic_type_mirrors[T_VOID+1]; MetaspaceObjToOopHandleTable* HeapShared::_scratch_java_mirror_table = nullptr; MetaspaceObjToOopHandleTable* HeapShared::_scratch_references_table = nullptr; @@ -244,15 +243,29 @@ objArrayOop HeapShared::root_segment(int segment_idx) { return segment; } +void HeapShared::get_segment_indexes(int idx, int& seg_idx, int& int_idx) { + assert(_root_segment_max_size_elems > 0, "sanity"); + + // Try to avoid divisions for the common case. + if (idx < _root_segment_max_size_elems) { + seg_idx = 0; + int_idx = idx; + } else { + seg_idx = idx / _root_segment_max_size_elems; + int_idx = idx % _root_segment_max_size_elems; + } + + assert(idx == seg_idx * _root_segment_max_size_elems + int_idx, + "sanity: %d index maps to %d segment and %d internal", idx, seg_idx, int_idx); +} + // Returns an objArray that contains all the roots of the archived objects oop HeapShared::get_root(int index, bool clear) { - assert(_root_segment_max_size_shift > 0, "sanity"); - assert(_root_segment_max_size_mask > 0, "sanity"); assert(index >= 0, "sanity"); assert(!CDSConfig::is_dumping_heap() && CDSConfig::is_using_archive(), "runtime only"); assert(!_root_segments->is_empty(), "must have loaded shared heap"); - int seg_idx = index >> _root_segment_max_size_shift; - int int_idx = index & _root_segment_max_size_mask; + int seg_idx, int_idx; + get_segment_indexes(index, seg_idx, int_idx); oop result = root_segment(seg_idx)->obj_at(int_idx); if (clear) { clear_root(index); @@ -264,10 +277,8 @@ void HeapShared::clear_root(int index) { assert(index >= 0, "sanity"); assert(CDSConfig::is_using_archive(), "must be"); if (ArchiveHeapLoader::is_in_use()) { - assert(_root_segment_max_size_shift > 0, "sanity"); - assert(_root_segment_max_size_mask > 0, "sanity"); - int seg_idx = index >> _root_segment_max_size_shift; - int int_idx = index & _root_segment_max_size_mask; + int seg_idx, int_idx; + get_segment_indexes(index, seg_idx, int_idx); if (log_is_enabled(Debug, cds, heap)) { oop old = root_segment(seg_idx)->obj_at(int_idx); log_debug(cds, heap)("Clearing root %d: was " PTR_FORMAT, index, p2i(old)); @@ -787,10 +798,8 @@ void HeapShared::add_root_segment(objArrayOop segment_oop) { _root_segments->push(OopHandle(Universe::vm_global(), segment_oop)); } -void HeapShared::init_root_segment_sizes(int max_size) { - assert(is_power_of_2(max_size), "must be"); - _root_segment_max_size_shift = log2i_exact(max_size); - _root_segment_max_size_mask = max_size - 1; +void HeapShared::init_root_segment_sizes(int max_size_elems) { + _root_segment_max_size_elems = max_size_elems; } void HeapShared::serialize_tables(SerializeClosure* soc) { diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index 01610ebe64e15..01d664945ee74 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -291,8 +291,7 @@ class HeapShared: AllStatic { static GrowableArrayCHeap* _pending_roots; static GrowableArrayCHeap* _root_segments; - static int _root_segment_max_size_shift; - static int _root_segment_max_size_mask; + static int _root_segment_max_size_elems; static OopHandle _scratch_basic_type_mirrors[T_VOID+1]; static MetaspaceObjToOopHandleTable* _scratch_java_mirror_table; static MetaspaceObjToOopHandleTable* _scratch_references_table; @@ -407,6 +406,8 @@ class HeapShared: AllStatic { // Run-time only static void clear_root(int index); + static void get_segment_indexes(int index, int& segment_index, int& internal_index); + static void setup_test_class(const char* test_class_name) PRODUCT_RETURN; #endif // INCLUDE_CDS_JAVA_HEAP @@ -425,7 +426,7 @@ class HeapShared: AllStatic { static void init_for_dumping(TRAPS) NOT_CDS_JAVA_HEAP_RETURN; static void write_subgraph_info_table() NOT_CDS_JAVA_HEAP_RETURN; static void add_root_segment(objArrayOop segment_oop) NOT_CDS_JAVA_HEAP_RETURN; - static void init_root_segment_sizes(int max_size) NOT_CDS_JAVA_HEAP_RETURN; + static void init_root_segment_sizes(int max_size_elems) NOT_CDS_JAVA_HEAP_RETURN; static void serialize_tables(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN; #ifndef PRODUCT From 0b467e902d591ae9feeec1669918d1588987cd1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Thu, 3 Oct 2024 08:36:33 +0000 Subject: [PATCH 113/188] 8334060: Implementation of Late Barrier Expansion for G1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roberto Castañeda Lozano Co-authored-by: Erik Österlund Co-authored-by: Siyao Liu Co-authored-by: Kim Barrett Co-authored-by: Amit Kumar Co-authored-by: Martin Doerr Co-authored-by: Feilong Jiang Co-authored-by: Sergey Nazarkin Reviewed-by: kvn, tschatzl, fyang, ayang, kbarrett --- make/hotspot/gensrc/GensrcAdlc.gmk | 7 + src/hotspot/cpu/aarch64/aarch64.ad | 24 +- src/hotspot/cpu/aarch64/cas.m4 | 4 + .../gc/g1/g1BarrierSetAssembler_aarch64.cpp | 268 ++-- .../gc/g1/g1BarrierSetAssembler_aarch64.hpp | 23 + src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad | 680 ++++++++++ src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4 | 384 ++++++ src/hotspot/cpu/arm/arm.ad | 4 + src/hotspot/cpu/arm/assembler_arm_32.hpp | 23 +- .../arm/gc/g1/g1BarrierSetAssembler_arm.cpp | 292 +++-- .../arm/gc/g1/g1BarrierSetAssembler_arm.hpp | 26 +- src/hotspot/cpu/arm/gc/g1/g1_arm.ad | 201 +++ .../arm/gc/shared/barrierSetAssembler_arm.cpp | 56 +- .../arm/gc/shared/barrierSetAssembler_arm.hpp | 24 + src/hotspot/cpu/arm/register_arm.hpp | 25 + .../ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp | 294 +++-- .../ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp | 25 + src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad | 684 ++++++++++ src/hotspot/cpu/ppc/ppc.ad | 20 +- src/hotspot/cpu/ppc/register_ppc.hpp | 9 + .../gc/g1/g1BarrierSetAssembler_riscv.cpp | 274 ++-- .../gc/g1/g1BarrierSetAssembler_riscv.hpp | 25 +- src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad | 564 ++++++++ src/hotspot/cpu/riscv/riscv.ad | 19 +- .../s390/gc/g1/g1BarrierSetAssembler_s390.cpp | 279 +++- .../s390/gc/g1/g1BarrierSetAssembler_s390.hpp | 28 +- src/hotspot/cpu/s390/gc/g1/g1_s390.ad | 457 +++++++ .../gc/shared/barrierSetAssembler_s390.cpp | 92 +- .../gc/shared/barrierSetAssembler_s390.hpp | 38 +- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 3 +- src/hotspot/cpu/s390/register_s390.hpp | 8 + src/hotspot/cpu/s390/s390.ad | 18 +- .../x86/gc/g1/g1BarrierSetAssembler_x86.cpp | 289 +++-- .../x86/gc/g1/g1BarrierSetAssembler_x86.hpp | 23 + src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad | 371 ++++++ src/hotspot/cpu/x86/x86.ad | 4 + src/hotspot/cpu/x86/x86_64.ad | 16 +- src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp | 1134 +++++------------ src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp | 126 +- .../share/gc/g1/g1BarrierSetRuntime.cpp | 8 + .../share/gc/g1/g1BarrierSetRuntime.hpp | 4 + .../share/gc/shared/c2/barrierSetC2.cpp | 4 + .../share/gc/shared/c2/barrierSetC2.hpp | 4 + .../gc/shared/c2/cardTableBarrierSetC2.cpp | 29 - .../gc/shared/c2/cardTableBarrierSetC2.hpp | 2 - src/hotspot/share/opto/buildOopMap.cpp | 7 + src/hotspot/share/opto/lcm.cpp | 8 + src/hotspot/share/opto/matcher.cpp | 20 + src/hotspot/share/opto/matcher.hpp | 2 + src/hotspot/share/opto/memnode.cpp | 5 + src/hotspot/share/opto/output.cpp | 2 + .../compiler/c2/aarch64/TestVolatiles.java | 44 +- .../AllocationMergesTests.java | 9 +- .../gcbarriers/TestG1BarrierGeneration.java | 639 ++++++++++ .../compiler/lib/ir_framework/IRNode.java | 102 ++ .../TestMachTempsAcrossSafepoints.java | 98 ++ .../src/sun/hotspot/tools/ctw/CtwRunner.java | 5 +- test/jdk/java/lang/invoke/BigArityTest.java | 2 +- 58 files changed, 6387 insertions(+), 1448 deletions(-) create mode 100644 src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad create mode 100644 src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4 create mode 100644 src/hotspot/cpu/arm/gc/g1/g1_arm.ad create mode 100644 src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad create mode 100644 src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad create mode 100644 src/hotspot/cpu/s390/gc/g1/g1_s390.ad create mode 100644 src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad create mode 100644 test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.java create mode 100644 test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk index 8dada3cec0a1d..ddb2c3e33e513 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -200,6 +200,13 @@ ifeq ($(call check-jvm-feature, compiler2), true) ))) endif + ifeq ($(call check-jvm-feature, g1gc), true) + AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/g1/g1_$(HOTSPOT_TARGET_CPU).ad \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/g1/g1_$(HOTSPOT_TARGET_CPU_ARCH).ad \ + ))) + endif + SINGLE_AD_SRCFILE := $(ADLC_SUPPORT_DIR)/all-ad-src.ad INSERT_FILENAME_AWK_SCRIPT := \ diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 39eae43a287e7..7d2a35cefd86a 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2620,7 +2620,8 @@ static bool is_vector_bitwise_not_pattern(Node* n, Node* m) { bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { if (is_vshift_con_pattern(n, m) || is_vector_bitwise_not_pattern(n, m) || - is_valid_sve_arith_imm_pattern(n, m)) { + is_valid_sve_arith_imm_pattern(n, m) || + is_encode_and_store_pattern(n, m)) { mstack.push(m, Visit); return true; } @@ -6410,7 +6411,7 @@ instruct loadP(iRegPNoSp dst, memory mem) instruct loadN(iRegNNoSp dst, memory mem) %{ match(Set dst (LoadN mem)); - predicate(!needs_acquiring_load(n)); + predicate(!needs_acquiring_load(n) && n->as_Load()->barrier_data() == 0); ins_cost(4 * INSN_COST); format %{ "ldrw $dst, $mem\t# compressed ptr" %} @@ -6839,7 +6840,7 @@ instruct storeimmP0(immP0 zero, memory mem) instruct storeN(iRegN src, memory mem) %{ match(Set mem (StoreN mem src)); - predicate(!needs_releasing_store(n)); + predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); ins_cost(INSN_COST); format %{ "strw $src, $mem\t# compressed ptr" %} @@ -6852,7 +6853,7 @@ instruct storeN(iRegN src, memory mem) instruct storeImmN0(immN0 zero, memory mem) %{ match(Set mem (StoreN mem zero)); - predicate(!needs_releasing_store(n)); + predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); ins_cost(INSN_COST); format %{ "strw zr, $mem\t# compressed ptr" %} @@ -7086,6 +7087,7 @@ instruct loadP_volatile(iRegPNoSp dst, /* sync_memory*/indirect mem) instruct loadN_volatile(iRegNNoSp dst, /* sync_memory*/indirect mem) %{ match(Set dst (LoadN mem)); + predicate(n->as_Load()->barrier_data() == 0); ins_cost(VOLATILE_REF_COST); format %{ "ldarw $dst, $mem\t# compressed ptr" %} @@ -7253,6 +7255,7 @@ instruct storeimmP0_volatile(immP0 zero, /* sync_memory*/indirect mem) instruct storeN_volatile(iRegN src, /* sync_memory*/indirect mem) %{ match(Set mem (StoreN mem src)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(VOLATILE_REF_COST); format %{ "stlrw $src, $mem\t# compressed ptr" %} @@ -7265,6 +7268,7 @@ instruct storeN_volatile(iRegN src, /* sync_memory*/indirect mem) instruct storeimmN0_volatile(immN0 zero, /* sync_memory*/indirect mem) %{ match(Set mem (StoreN mem zero)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(VOLATILE_REF_COST); format %{ "stlrw zr, $mem\t# compressed ptr" %} @@ -8061,6 +8065,7 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapN mem (Binary oldval newval))); + predicate(n->as_LoadStore()->barrier_data() == 0); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8175,7 +8180,7 @@ instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP new instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndSwapN mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); @@ -8280,6 +8285,7 @@ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL ne // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -8389,7 +8395,7 @@ instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(TEMP_DEF res, KILL cr); @@ -8501,6 +8507,7 @@ instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL ne // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); ins_cost(2 * VOLATILE_REF_COST); effect(KILL cr); @@ -8620,7 +8627,7 @@ instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL // This pattern is generated automatically from cas.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, rFlagsReg cr) %{ - predicate(needs_acquiring_load_exclusive(n)); + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); ins_cost(VOLATILE_REF_COST); effect(KILL cr); @@ -8681,6 +8688,7 @@ instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) %{ %} instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set prev (GetAndSetN mem newv)); ins_cost(2 * VOLATILE_REF_COST); format %{ "atomic_xchgw $prev, $newv, [$mem]" %} @@ -8724,7 +8732,7 @@ instruct get_and_setLAcq(indirect mem, iRegL newv, iRegLNoSp prev) %{ %} instruct get_and_setNAcq(indirect mem, iRegN newv, iRegINoSp prev) %{ - predicate(needs_acquiring_load_exclusive(n)); + predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0); match(Set prev (GetAndSetN mem newv)); ins_cost(VOLATILE_REF_COST); format %{ "atomic_xchgw_acq $prev, $newv, [$mem]" %} diff --git a/src/hotspot/cpu/aarch64/cas.m4 b/src/hotspot/cpu/aarch64/cas.m4 index f8aac0c4939fa..7e13e153db18a 100644 --- a/src/hotspot/cpu/aarch64/cas.m4 +++ b/src/hotspot/cpu/aarch64/cas.m4 @@ -45,7 +45,9 @@ define(`CAS_INSN', // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct compareAndExchange$1$6(iReg$2NoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), + $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), `dnl') match(Set res (CompareAndExchange$1 mem (Binary oldval newval))); @@ -122,7 +124,9 @@ define(`CAS_INSN3', // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE instruct weakCompareAndSwap$1$6(iRegINoSp res, indirect mem, iReg$2 oldval, iReg$2 newval, rFlagsReg cr) %{ ifelse($1$6,PAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && (n->as_LoadStore()->barrier_data() == 0));), + $1$6,NAcq,INDENT(predicate(needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() == 0);), $1,P,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), + $1,N,INDENT(predicate(n->as_LoadStore()->barrier_data() == 0);), $6,Acq,INDENT(predicate(needs_acquiring_load_exclusive(n));), `dnl') match(Set res (WeakCompareAndSwap$1 mem (Binary oldval newval))); diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp index d02038b6e9193..b978c350ce131 100644 --- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp @@ -38,7 +38,10 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> @@ -95,6 +98,54 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ pop(saved_regs, sp); } +static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register thread, const Register value, const Register temp1, const Register temp2) { + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + __ ldr(temp1, Address(thread, in_bytes(index_offset))); // temp1 := *(index address) + __ cbz(temp1, runtime); // jump to runtime if index == 0 (full buffer) + // The buffer is not full, store value into it. + __ sub(temp1, temp1, wordSize); // temp1 := next index + __ str(temp1, Address(thread, in_bytes(index_offset))); // *(index address) := next index + __ ldr(temp2, Address(thread, in_bytes(buffer_offset))); // temp2 := buffer address + __ str(value, Address(temp2, temp1)); // *(buffer address + next index) := value +} + +static void generate_pre_barrier_fast_path(MacroAssembler* masm, + const Register thread, + const Register tmp1) { + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ ldrw(tmp1, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ ldrb(tmp1, in_progress); + } +} + +static void generate_pre_barrier_slow_path(MacroAssembler* masm, + const Register obj, + const Register pre_val, + const Register thread, + const Register tmp1, + const Register tmp2, + Label& done, + Label& runtime) { + // Do we need to load the previous value? + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + } + // Is the previous value null? + __ cbz(pre_val, done); + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, + thread, pre_val, tmp1, tmp2); + __ b(done); +} + void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, @@ -115,43 +166,10 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, assert_different_registers(obj, pre_val, tmp1, tmp2); assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - - // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ ldrw(tmp1, in_progress); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ ldrb(tmp1, in_progress); - } + generate_pre_barrier_fast_path(masm, thread, tmp1); + // If marking is not active (*(mark queue active address) == 0), jump to done __ cbzw(tmp1, done); - - // Do we need to load the previous value? - if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); - } - - // Is the previous value null? - __ cbz(pre_val, done); - - // Can we store original value in the thread's buffer? - // Is index == 0? - // (The index field is typed as size_t.) - - __ ldr(tmp1, index); // tmp := *index_adr - __ cbz(tmp1, runtime); // tmp == 0? - // If yes, goto runtime - - __ sub(tmp1, tmp1, wordSize); // tmp := tmp - wordSize - __ str(tmp1, index); // *index_adr := tmp - __ ldr(tmp2, buffer); - __ add(tmp1, tmp1, tmp2); // tmp := tmp + *buffer_adr - - // Record the previous value - __ str(pre_val, Address(tmp1, 0)); - __ b(done); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, done, runtime); __ bind(runtime); @@ -182,6 +200,50 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, } +static void generate_post_barrier_fast_path(MacroAssembler* masm, + const Register store_addr, + const Register new_val, + const Register tmp1, + const Register tmp2, + Label& done, + bool new_val_may_be_null) { + // Does store cross heap regions? + __ eor(tmp1, store_addr, new_val); // tmp1 := store address ^ new value + __ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes) + __ cbz(tmp1, done); + // Crosses regions, storing null? + if (new_val_may_be_null) { + __ cbz(new_val, done); + } + // Storing region crossing non-null, is card young? + __ lsr(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base + __ load_byte_map_base(tmp2); // tmp2 := card table base address + __ add(tmp1, tmp1, tmp2); // tmp1 := card address + __ ldrb(tmp2, Address(tmp1)); // tmp2 := card + __ cmpw(tmp2, (int)G1CardTable::g1_young_card_val()); // tmp2 := card == young_card_val? +} + +static void generate_post_barrier_slow_path(MacroAssembler* masm, + const Register thread, + const Register tmp1, + const Register tmp2, + Label& done, + Label& runtime) { + __ membar(Assembler::StoreLoad); // StoreLoad membar + __ ldrb(tmp2, Address(tmp1)); // tmp2 := card + __ cbzw(tmp2, done); + // Storing a region crossing, non-null oop, card is clean. + // Dirty card and log. + STATIC_ASSERT(CardTable::dirty_card_val() == 0); + __ strb(zr, Address(tmp1)); // *(card address) := dirty_card_val + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, + thread, tmp1, tmp2, rscratch1); + __ b(done); +} + void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, @@ -194,70 +256,116 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - BarrierSet* bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); - CardTable* ct = ctbs->card_table(); - Label done; Label runtime; - // Does store cross heap regions? + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */); + // If card is young, jump to done + __ br(Assembler::EQ, done); + generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime); - __ eor(tmp1, store_addr, new_val); - __ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); - __ cbz(tmp1, done); + __ bind(runtime); + // save the live input values + RegSet saved = RegSet::of(store_addr); + __ push(saved, sp); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread); + __ pop(saved, sp); - // crosses regions, storing null? + __ bind(done); +} - __ cbz(new_val, done); +#if defined(COMPILER2) - // storing region crossing non-null, is card already dirty? +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { + SaveLiveRegisters save_registers(masm, stub); + if (c_rarg0 != arg) { + __ mov(c_rarg0, arg); + } + __ mov(c_rarg1, rthread); + __ mov(rscratch1, runtime_path); + __ blr(rscratch1); +} - const Register card_addr = tmp1; +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* stub) { + assert(thread == rthread, "must be"); + assert_different_registers(obj, pre_val, tmp1, tmp2); + assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - __ lsr(card_addr, store_addr, CardTable::card_shift()); + stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2); - // get the address of the card - __ load_byte_map_base(tmp2); - __ add(card_addr, card_addr, tmp2); - __ ldrb(tmp2, Address(card_addr)); - __ cmpw(tmp2, (int)G1CardTable::g1_young_card_val()); - __ br(Assembler::EQ, done); + generate_pre_barrier_fast_path(masm, thread, tmp1); + // If marking is active (*(mark queue active address) != 0), jump to stub (slow path) + __ cbnzw(tmp1, *stub->entry()); - assert((int)CardTable::dirty_card_val() == 0, "must be 0"); + __ bind(*stub->continuation()); +} - __ membar(Assembler::StoreLoad); +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); + Register tmp2 = stub->tmp2(); - __ ldrb(tmp2, Address(card_addr)); - __ cbzw(tmp2, done); + __ bind(*stub->entry()); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, *stub->continuation(), runtime); - // storing a region crossing, non-null oop, card is clean. - // dirty card and log. + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); + __ b(*stub->continuation()); +} - __ strb(zr, Address(card_addr)); +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* stub) { + assert(thread == rthread, "must be"); + assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, + rscratch1); + assert(store_addr != noreg && new_val != noreg && tmp1 != noreg + && tmp2 != noreg, "expecting a register"); - __ ldr(rscratch1, queue_index); - __ cbz(rscratch1, runtime); - __ sub(rscratch1, rscratch1, wordSize); - __ str(rscratch1, queue_index); + stub->initialize_registers(thread, tmp1, tmp2); - __ ldr(tmp2, buffer); - __ str(card_addr, Address(tmp2, rscratch1)); - __ b(done); + bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null); + // If card is not young, jump to stub (slow path) + __ br(Assembler::NE, *stub->entry()); - __ bind(runtime); - // save the live input values - RegSet saved = RegSet::of(store_addr); - __ push(saved, sp); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); - __ pop(saved, sp); + __ bind(*stub->continuation()); +} - __ bind(done); +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); // tmp1 holds the card address. + Register tmp2 = stub->tmp2(); + assert(stub->tmp3() == noreg, "not needed in this platform"); + + __ bind(*stub->entry()); + generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); + __ b(*stub->continuation()); } +#endif // COMPILER2 + void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp2) { bool on_oop = is_reference_type(type); diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp index 7b4bc8cdc49de..4baa18cb94544 100644 --- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp @@ -33,6 +33,8 @@ class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -69,6 +71,27 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); #endif +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* c2_stub); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif + void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp2); }; diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad new file mode 100644 index 0000000000000..081a67d68807b --- /dev/null +++ b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.ad @@ -0,0 +1,680 @@ +// +// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_aarch64.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void write_barrier_pre(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2, + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, rthread, tmp1, tmp2, stub); +} + +static void write_barrier_post(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, rthread, tmp1, tmp2, stub); +} + +%} + +// BEGIN This section of the file is automatically generated. Do not edit -------------- + +// This section is generated from g1_aarch64.m4 + + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StoreP(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(INSN_COST); + format %{ "str $src, $mem\t# ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ str($src$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StorePVolatile(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "stlr $src, $mem\t# ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ stlr($src$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_class_memory); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StoreN(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(INSN_COST); + format %{ "strw $src, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ strw($src$$Register, $mem$$Register); + if ((barrier_data() & G1C2BarrierPost) != 0) { + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ decode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + } + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StoreNVolatile(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "stlrw $src, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ stlrw($src$$Register, $mem$$Register); + if ((barrier_data() & G1C2BarrierPost) != 0) { + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ decode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + } + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_class_memory); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(INSN_COST); + format %{ "encode_heap_oop $tmp1, $src\n\t" + "strw $tmp1, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ encode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + __ strw($tmp1$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1EncodePAndStoreNVolatile(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_releasing_store(n) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "encode_heap_oop $tmp1, $src\n\t" + "stlrw $tmp1, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ encode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + __ stlrw($tmp1$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_class_memory); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $res = $mem, $oldval, $newval\t# ptr" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP and its Acq variant. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + false /* acquire */, true /* release */, false /* weak */, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# ptr" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP and its Acq variant. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + true /* acquire */, true /* release */, false /* weak */, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $res = $mem, $oldval, $newval\t# narrow oop" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + false /* acquire */, true /* release */, false /* weak */, $res$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# narrow oop" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + true /* acquire */, true /* release */, false /* weak */, $res$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapP(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $mem, $oldval, $newval\t# (ptr)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + false /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (ptr)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + true /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapN(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $mem, $oldval, $newval\t# (narrow oop)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + false /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (narrow oop)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + true /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetP(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "atomic_xchg $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchg($preval$$Register, $newval$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "atomic_xchg_acq $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgal($preval$$Register, $newval$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetN(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetN mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "atomic_xchgw $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgw($preval$$Register, $newval$$Register, $mem$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetNAcq(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && needs_acquiring_load_exclusive(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetN mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(VOLATILE_REF_COST); + format %{ "atomic_xchgw_acq $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgalw($preval$$Register, $newval$$Register, $mem$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + // This instruction does not need an acquiring counterpart because it is only + // used for reference loading (Reference::get()). The same holds for g1LoadN. + predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(4 * INSN_COST); + format %{ "ldr $dst, $mem\t# ptr" %} + ins_encode %{ + __ ldr($dst$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(iload_reg_mem); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadN mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(4 * INSN_COST); + format %{ "ldrw $dst, $mem\t# compressed ptr" %} + ins_encode %{ + __ ldrw($dst$$Register, $mem$$Register); + if ((barrier_data() & G1C2BarrierPre) != 0) { + __ decode_heap_oop($tmp1$$Register, $dst$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + } + %} + ins_pipe(iload_reg_mem); +%} + +// END This section of the file is automatically generated. Do not edit -------------- diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4 b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4 new file mode 100644 index 0000000000000..8fb1f7e8e428b --- /dev/null +++ b/src/hotspot/cpu/aarch64/gc/g1/g1_aarch64.m4 @@ -0,0 +1,384 @@ +dnl Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +dnl DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +dnl +dnl This code is free software; you can redistribute it and/or modify it +dnl under the terms of the GNU General Public License version 2 only, as +dnl published by the Free Software Foundation. +dnl +dnl This code is distributed in the hope that it will be useful, but WITHOUT +dnl ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +dnl version 2 for more details (a copy is included in the LICENSE file that +dnl accompanied this code). +dnl +dnl You should have received a copy of the GNU General Public License version +dnl 2 along with this work; if not, write to the Free Software Foundation, +dnl Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +dnl +dnl Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +dnl or visit www.oracle.com if you need additional information or have any +dnl questions. +dnl +// BEGIN This section of the file is automatically generated. Do not edit -------------- + +// This section is generated from g1_aarch64.m4 + +define(`STOREP_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StoreP$1(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Volatile,'needs_releasing_store(n)`,'!needs_releasing_store(n)`) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Volatile,VOLATILE_REF_COST,INSN_COST)); + format %{ "$2 $src, $mem\t# ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ $2($src$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(ifelse($1,Volatile,pipe_class_memory,istore_reg_mem)); +%}')dnl +STOREP_INSN(,str) +STOREP_INSN(Volatile,stlr) +dnl +define(`STOREN_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1StoreN$1(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Volatile,'needs_releasing_store(n)`,'!needs_releasing_store(n)`) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Volatile,VOLATILE_REF_COST,INSN_COST)); + format %{ "$2 $src, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ $2($src$$Register, $mem$$Register); + if ((barrier_data() & G1C2BarrierPost) != 0) { + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ decode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + } + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(ifelse($1,Volatile,pipe_class_memory,istore_reg_mem)); +%}')dnl +STOREN_INSN(,strw) +STOREN_INSN(Volatile,stlrw) +dnl +define(`ENCODESTOREN_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1EncodePAndStoreN$1(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Volatile,'needs_releasing_store(n)`,'!needs_releasing_store(n)`) && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Volatile,VOLATILE_REF_COST,INSN_COST)); + format %{ "encode_heap_oop $tmp1, $src\n\t" + "$2 $tmp1, $mem\t# compressed ptr" %} + ins_encode %{ + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ encode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + __ $2($tmp1$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(ifelse($1,Volatile,pipe_class_memory,istore_reg_mem)); +%}')dnl +ENCODESTOREN_INSN(,strw) +ENCODESTOREN_INSN(Volatile,stlrw) +dnl +define(`CAEP_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangeP$1(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "cmpxchg$2 $res = $mem, $oldval, $newval\t# ptr" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP and its Acq variant. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + $3 /* acquire */, true /* release */, false /* weak */, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%}')dnl +CAEP_INSN(,,false) +CAEP_INSN(Acq,_acq,true) +dnl +define(`CAEN_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndExchangeN$1(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "cmpxchg$2 $res = $mem, $oldval, $newval\t# narrow oop" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + $3 /* acquire */, true /* release */, false /* weak */, $res$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%}')dnl +CAEN_INSN(,,false) +CAEN_INSN(Acq,_acq,true) +dnl +define(`CASP_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapP$1(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "cmpxchg$2 $mem, $oldval, $newval\t# (ptr)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::xword, + $3 /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%}')dnl +CASP_INSN(,,false) +CASP_INSN(Acq,_acq,true) +dnl +define(`CASN_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1CompareAndSwapN$1(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "cmpxchg$2 $mem, $oldval, $newval\t# (narrow oop)\n\t" + "cset $res, EQ" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::word, + $3 /* acquire */, true /* release */, false /* weak */, noreg); + __ cset($res$$Register, Assembler::EQ); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%}')dnl +CASN_INSN(,,false) +CASN_INSN(Acq,_acq,true) +dnl +define(`XCHGP_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetP$1(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "atomic_xchg$2 $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ $3($preval$$Register, $newval$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%}')dnl +XCHGP_INSN(,,atomic_xchg) +XCHGP_INSN(Acq,_acq,atomic_xchgal) +dnl +define(`XCHGN_INSN', +` +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1GetAndSetN$1(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval, rFlagsReg cr) +%{ + predicate(UseG1GC && ifelse($1,Acq,'needs_acquiring_load_exclusive(n)`,'!needs_acquiring_load_exclusive(n)`) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetN mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(ifelse($1,Acq,VOLATILE_REF_COST,2 * VOLATILE_REF_COST)); + format %{ "$2 $preval, $newval, [$mem]" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ $3($preval$$Register, $newval$$Register, $mem$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%}')dnl +XCHGN_INSN(,atomic_xchgw,atomic_xchgw) +XCHGN_INSN(Acq,atomic_xchgw_acq,atomic_xchgalw) + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, rFlagsReg cr) +%{ + // This instruction does not need an acquiring counterpart because it is only + // used for reference loading (Reference::get()). The same holds for g1LoadN. + predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(4 * INSN_COST); + format %{ "ldr $dst, $mem\t# ptr" %} + ins_encode %{ + __ ldr($dst$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(iload_reg_mem); +%} + +// This pattern is generated automatically from g1_aarch64.m4. +// DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE +instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadN mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(4 * INSN_COST); + format %{ "ldrw $dst, $mem\t# compressed ptr" %} + ins_encode %{ + __ ldrw($dst$$Register, $mem$$Register); + if ((barrier_data() & G1C2BarrierPre) != 0) { + __ decode_heap_oop($tmp1$$Register, $dst$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + } + %} + ins_pipe(iload_reg_mem); +%} + +// END This section of the file is automatically generated. Do not edit -------------- diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 2c7de0a58a204..716f6d87230e1 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -3890,6 +3890,7 @@ instruct loadRange(iRegI dst, memoryI mem) %{ instruct loadP(iRegP dst, memoryP mem) %{ + predicate(!(UseG1GC && n->as_Load()->barrier_data() != 0)); match(Set dst (LoadP mem)); ins_cost(MEMORY_REF_COST); size(4); @@ -4356,6 +4357,7 @@ instruct movSP(store_ptr_RegP dst, SPRegP src) %{ instruct storeP(memoryP mem, store_ptr_RegP src) %{ + predicate(!(UseG1GC && n->as_Store()->barrier_data() != 0)); match(Set mem (StoreP mem src)); ins_cost(MEMORY_REF_COST); size(4); @@ -5390,6 +5392,7 @@ instruct compareAndSwapI_bool(memoryex mem, iRegI oldval, iRegI newval, iRegI re %} instruct compareAndSwapP_bool(memoryex mem, iRegP oldval, iRegP newval, iRegI res, iRegI tmp, flagsReg ccr ) %{ + predicate(!(UseG1GC && n->as_LoadStore()->barrier_data() != 0)); match(Set res (CompareAndSwapP mem (Binary oldval newval))); effect( KILL ccr, TEMP tmp); size(28); @@ -5659,6 +5662,7 @@ instruct xchgL(memoryex mem, iRegLd newval, iRegLd res, iRegI tmp, flagsReg ccr) %} instruct xchgP(memoryex mem, iRegP newval, iRegP res, iRegI tmp, flagsReg ccr) %{ + predicate(!(UseG1GC && n->as_LoadStore()->barrier_data() != 0)); match(Set res (GetAndSetP mem newval)); effect(KILL ccr, TEMP tmp, TEMP res); size(16); diff --git a/src/hotspot/cpu/arm/assembler_arm_32.hpp b/src/hotspot/cpu/arm/assembler_arm_32.hpp index dd04ad1ab3a3c..e53eefac097ef 100644 --- a/src/hotspot/cpu/arm/assembler_arm_32.hpp +++ b/src/hotspot/cpu/arm/assembler_arm_32.hpp @@ -119,8 +119,9 @@ class RegisterSet { } friend RegisterSet operator | (const RegisterSet set1, const RegisterSet set2) { - assert((set1._encoding & set2._encoding) == 0, - "encoding constraint"); +// why so strong constraint? +// assert((set1._encoding & set2._encoding) == 0, +// "encoding constraint"); return RegisterSet(set1._encoding | set2._encoding); } @@ -142,6 +143,11 @@ class RegisterSet { } return count; } + + static RegisterSet from(RegSet set) { + assert(set.size(), "RegSet must not be empty"); + return RegisterSet(set.bits()); + } }; #if R9_IS_SCRATCHED @@ -157,6 +163,10 @@ class FloatRegisterSet { public: + FloatRegisterSet() { + _encoding = 0; + } + FloatRegisterSet(FloatRegister reg) { if (reg->hi_bit() == 0) { _encoding = reg->hi_bits() << 12 | reg->lo_bit() << 22 | 1; @@ -185,6 +195,15 @@ class FloatRegisterSet { return (_encoding & 0xFFFFFF00) | ((_encoding & 0xFF) << 1); } + static FloatRegisterSet from(FloatRegSet set) { + assert(set.size(), "FloatRegSet must not be empty"); + // the vector load/store instructions operate on a set of consecutive registers. + // for the sake of simplicity, write all registers between the first and last in the set + size_t range = (*set.rbegin())->encoding() - (*set.begin())->encoding() + 1; + // push_float stores float regisgters by pairs + return FloatRegisterSet(*set.begin(), (range+1)/2); + } + }; diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp index 3c5e29aa8710f..56ae7707fbf38 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp @@ -39,8 +39,10 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif - +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> #ifdef PRODUCT @@ -106,70 +108,87 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas #endif // !R9_IS_SCRATCHED } -// G1 pre-barrier. -// Blows all volatile registers R0-R3, Rtemp, LR). -// If store_addr != noreg, then previous value is loaded from [store_addr]; -// in such case store_addr and new_val registers are preserved; -// otherwise pre_val register is preserved. -void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, - Register store_addr, - Register new_val, - Register pre_val, - Register tmp1, - Register tmp2) { - Label done; - Label runtime; - - if (store_addr != noreg) { - assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg); - } else { - assert (new_val == noreg, "should be"); - assert_different_registers(pre_val, tmp1, tmp2, noreg); - } - - Address in_progress(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); +static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register thread, const Register value, const Register temp1, const Register temp2) { + assert_different_registers(value, temp1, temp2); + // Can we store original value in the thread's buffer? + // (The index field is typed as size_t.) + __ ldr(temp1, Address(thread, in_bytes(index_offset))); // temp1 := *(index address) + __ cbz(temp1, runtime); // jump to runtime if index == 0 (full buffer) + // The buffer is not full, store value into it. + __ sub(temp1, temp1, wordSize); // temp1 := next index + __ str(temp1, Address(thread, in_bytes(index_offset))); // *(index address) := next index + __ ldr(temp2, Address(thread, in_bytes(buffer_offset))); // temp2 := buffer address + // Record the previous value + __ str(value, Address(temp2, temp1)); // *(buffer address + next index) := value + } +static void generate_pre_barrier_fast_path(MacroAssembler* masm, + const Register thread, + const Register tmp1) { + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); // Is marking active? assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code"); __ ldrb(tmp1, in_progress); - __ cbz(tmp1, done); +} +static void generate_pre_barrier_slow_path(MacroAssembler* masm, + const Register obj, + const Register pre_val, + const Register thread, + const Register tmp1, + const Register tmp2, + Label& done, + Label& runtime) { // Do we need to load the previous value? - if (store_addr != noreg) { - __ load_heap_oop(pre_val, Address(store_addr, 0)); + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj, 0)); } // Is the previous value null? __ cbz(pre_val, done); - // Can we store original value in the thread's buffer? - // Is index == 0? - // (The index field is typed as size_t.) + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, + thread, pre_val, tmp1, tmp2); + __ b(done); +} - __ ldr(tmp1, index); // tmp1 := *index_adr - __ ldr(tmp2, buffer); +// G1 pre-barrier. +// Blows all volatile registers R0-R3, LR). +// If obj != noreg, then previous value is loaded from [obj]; +// in such case obj and pre_val registers is preserved; +// otherwise pre_val register is preserved. +void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2) { + Label done; + Label runtime; - __ subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize - __ b(runtime, lt); // If negative, goto runtime + assert_different_registers(obj, pre_val, tmp1, tmp2, noreg); - __ str(tmp1, index); // *index_adr := tmp1 + generate_pre_barrier_fast_path(masm, Rthread, tmp1); + // If marking is not active (*(mark queue active address) == 0), jump to done + __ cbz(tmp1, done); - // Record the previous value - __ str(pre_val, Address(tmp2, tmp1)); - __ b(done); + generate_pre_barrier_slow_path(masm, obj, pre_val, Rthread, tmp1, tmp2, done, runtime); __ bind(runtime); // save the live input values - if (store_addr != noreg) { - // avoid raw_push to support any ordering of store_addr and new_val - __ push(RegisterSet(store_addr) | RegisterSet(new_val)); - } else { - __ push(pre_val); + RegisterSet set = RegisterSet(pre_val) | RegisterSet(R0, R3) | RegisterSet(R12); + // save the live input values + if (obj != noreg) { + // avoid raw_push to support any ordering of store_addr and pre_val + set = set | RegisterSet(obj); } + __ push(set); + if (pre_val != R0) { __ mov(R0, pre_val); } @@ -177,33 +196,17 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), R0, R1); - if (store_addr != noreg) { - __ pop(RegisterSet(store_addr) | RegisterSet(new_val)); - } else { - __ pop(pre_val); - } - + __ pop(set); __ bind(done); } -// G1 post-barrier. -// Blows all volatile registers R0-R3, Rtemp, LR). -void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, - Register store_addr, - Register new_val, - Register tmp1, - Register tmp2, - Register tmp3) { - - Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - BarrierSet* bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); - CardTable* ct = ctbs->card_table(); - Label done; - Label runtime; - +static void generate_post_barrier_fast_path(MacroAssembler* masm, + const Register store_addr, + const Register new_val, + const Register tmp1, + const Register tmp2, + Label& done, + bool new_val_may_be_null) { // Does store cross heap regions? __ eor(tmp1, store_addr, new_val); @@ -211,22 +214,31 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, __ b(done, eq); // crosses regions, storing null? - - __ cbz(new_val, done); - + if (new_val_may_be_null) { + __ cbz(new_val, done); + } // storing region crossing non-null, is card already dirty? const Register card_addr = tmp1; - __ mov_address(tmp2, (address)ct->byte_map_base()); + CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); + __ mov_address(tmp2, (address)ct->card_table()->byte_map_base()); __ add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift())); __ ldrb(tmp2, Address(card_addr)); __ cmp(tmp2, (int)G1CardTable::g1_young_card_val()); - __ b(done, eq); +} +static void generate_post_barrier_slow_path(MacroAssembler* masm, + const Register thread, + const Register tmp1, + const Register tmp2, + const Register tmp3, + Label& done, + Label& runtime) { __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2); - assert(CardTable::dirty_card_val() == 0, "adjust this code"); + // card_addr is loaded by generate_post_barrier_fast_path + const Register card_addr = tmp1; __ ldrb(tmp2, Address(card_addr)); __ cbz(tmp2, done); @@ -234,29 +246,139 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, // dirty card and log. __ strb(__ zero_register(tmp2), Address(card_addr)); + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, + thread, card_addr, tmp2, tmp3); + __ b(done); +} - __ ldr(tmp2, queue_index); - __ ldr(tmp3, buffer); - __ subs(tmp2, tmp2, wordSize); - __ b(runtime, lt); // go to runtime if now negative - - __ str(tmp2, queue_index); +// G1 post-barrier. +// Blows all volatile registers R0-R3, LR). +void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + Register tmp3) { + Label done; + Label runtime; - __ str(card_addr, Address(tmp3, tmp2)); - __ b(done); + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */); + // If card is young, jump to done + // card_addr and card are loaded by generate_post_barrier_fast_path + const Register card = tmp2; + const Register card_addr = tmp1; + __ b(done, eq); + generate_post_barrier_slow_path(masm, Rthread, card_addr, tmp2, tmp3, done, runtime); __ bind(runtime); + RegisterSet set = RegisterSet(store_addr) | RegisterSet(R0, R3) | RegisterSet(R12); + __ push(set); + if (card_addr != R0) { __ mov(R0, card_addr); } __ mov(R1, Rthread); __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), R0, R1); + __ pop(set); + __ bind(done); } +#if defined(COMPILER2) + +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path, Register tmp1) { + SaveLiveRegisters save_registers(masm, stub); + if (c_rarg0 != arg) { + __ mov(c_rarg0, arg); + } + __ mov(c_rarg1, Rthread); + __ call_VM_leaf(runtime_path, R0, R1); +} + +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* stub) { + assert(thread == Rthread, "must be"); + assert_different_registers(obj, pre_val, tmp1, tmp2); + assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); + + stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2); + + generate_pre_barrier_fast_path(masm, thread, tmp1); + // If marking is active (*(mark queue active address) != 0), jump to stub (slow path) + __ cbnz(tmp1, *stub->entry()); + + __ bind(*stub->continuation()); +} + +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); + Register tmp2 = stub->tmp2(); + + __ bind(*stub->entry()); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, *stub->continuation(), runtime); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), tmp1); + __ b(*stub->continuation()); +} + +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + Register tmp3, + G1PostBarrierStubC2* stub) { + assert(thread == Rthread, "must be"); + assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, noreg); + + stub->initialize_registers(thread, tmp1, tmp2, tmp3); + + bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null); + // If card is not young, jump to stub (slow path) + __ b(*stub->entry(), ne); + + __ bind(*stub->continuation()); +} + +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); // tmp1 holds the card address. + Register tmp2 = stub->tmp2(); + Register tmp3 = stub->tmp3(); + + __ bind(*stub->entry()); + generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, tmp3, *stub->continuation(), runtime); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp2); + __ b(*stub->continuation()); +} + +#endif // COMPILER2 + void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp2, Register tmp3) { bool on_oop = type == T_OBJECT || type == T_ARRAY; @@ -268,7 +390,7 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator if (on_oop && on_reference) { // Generate the G1 pre-barrier code to log the value of // the referent field in an SATB buffer. - g1_write_barrier_pre(masm, noreg, noreg, dst, tmp1, tmp2); + g1_write_barrier_pre(masm, noreg, dst, tmp1, tmp2); } } @@ -295,7 +417,7 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco } if (needs_pre_barrier) { - g1_write_barrier_pre(masm, store_addr, new_val, tmp1, tmp2, tmp3); + g1_write_barrier_pre(masm, store_addr, tmp3 /*pre_val*/, tmp1, tmp2); } if (is_null) { diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp index 52932faa3e4de..aefde19142e40 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp @@ -33,6 +33,8 @@ class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -43,7 +45,6 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void g1_write_barrier_pre(MacroAssembler* masm, Register store_addr, - Register new_val, Register pre_val, Register tmp1, Register tmp2); @@ -70,6 +71,29 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); #endif + +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + Register tmp3, + G1PostBarrierStubC2* c2_stub); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif + }; #endif // CPU_ARM_GC_G1_G1BARRIERSETASSEMBLER_ARM_HPP diff --git a/src/hotspot/cpu/arm/gc/g1/g1_arm.ad b/src/hotspot/cpu/arm/gc/g1/g1_arm.ad new file mode 100644 index 0000000000000..8a0a9e1aa531a --- /dev/null +++ b/src/hotspot/cpu/arm/gc/g1/g1_arm.ad @@ -0,0 +1,201 @@ +// +// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_arm.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void write_barrier_pre(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2, + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, Rthread, tmp1, tmp2, stub); +} + +static void write_barrier_post(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + Register tmp3) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Rthread, tmp1, tmp2, tmp3, stub); +} + +%} + +instruct g1StoreP(indirect mem, iRegP src, iRegP tmp1, iRegP tmp2, iRegP tmp3, flagsReg icc) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL icc); + ins_cost(2 * (MEMORY_REF_COST + BRANCH_COST)); + format %{ "sd $src, $mem\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ str($src$$Register, Address($mem$$Register)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + $tmp3$$Register /* tmp3 */); + %} + ins_pipe(istore_mem_reg); +%} + +instruct g1CompareAndSwapP(iRegI res, indirect mem, iRegP newval, iRegP tmp1, iRegP tmp2, iRegP tmp3, iRegP oldval, flagsReg ccr ) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + effect(KILL ccr, TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(4 * (MEMORY_REF_COST + BRANCH_COST)); + format %{ "loop: \n\t" + "LDREX $tmp1, $mem\t! If $oldval==[$mem] Then store $newval into [$mem]\n\t" + "CMP $tmp1, $oldval\n\t" + "STREX.eq $tmp1, $newval, $mem\n\t" + "MOV.ne $tmp1, 0 \n\t" + "EORS.eq $tmp1,$tmp1, 1 \n\t" + "B.eq loop \n\t" + "MOV $res, $tmp1" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + Label loop; + __ bind(loop); + __ ldrex($tmp1$$Register,$mem$$Address); + __ cmp($tmp1$$Register, $oldval$$Register); + __ strex($tmp1$$Register, $newval$$Register, $mem$$Address, eq); + __ mov($tmp1$$Register, 0, ne); + __ eors($tmp1$$Register, $tmp1$$Register, 1, eq); + __ b(loop, eq); + __ mov($res$$Register, $tmp1$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + $tmp3$$Register /* tmp3 */); + %} + ins_pipe(long_memory_op); +%} + + +instruct g1GetAndSetP(indirect mem, iRegP newval, iRegP tmp1, iRegP tmp2, iRegP tmp3, iRegP preval, flagsReg ccr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(KILL ccr, TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(4 * (MEMORY_REF_COST + BRANCH_COST)); + format %{ "loop: \n\t" + "LDREX $preval, $mem\n\t" + "STREX $tmp1, $newval, $mem\n\t" + "CMP $tmp1, 0 \n\t" + "B.ne loop \n\t" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + Label loop; + __ bind(loop); + __ ldrex($preval$$Register,$mem$$Address); + __ strex($tmp1$$Register, $newval$$Register, $mem$$Address); + __ cmp($tmp1$$Register, 0); + __ b(loop, ne); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + $tmp3$$Register /* tmp3 */); + %} + ins_pipe(long_memory_op); +%} + +instruct g1LoadP(iRegP dst, indirect mem, iRegP tmp1, iRegP tmp2, flagsReg icc) +%{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL icc); + ins_cost(MEMORY_REF_COST + BRANCH_COST); + format %{ "ld $dst, $mem\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + __ ldr($dst$$Register, Address($mem$$Register)); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(iload_mem); +%} diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp index ea19730673cb6..c13a259a1b960 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp @@ -31,6 +31,10 @@ #include "runtime/javaThread.hpp" #include "runtime/stubRoutines.hpp" +#ifdef COMPILER2 +#include "gc/shared/c2/barrierSetC2.hpp" +#endif // COMPILER2 + #define __ masm-> void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, @@ -206,7 +210,57 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { #ifdef COMPILER2 OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) { - Unimplemented(); // This must be implemented to support late barrier expansion. + if (!OptoReg::is_reg(opto_reg)) { + return OptoReg::Bad; + } + + const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if (!vm_reg->is_valid()){ + // skip APSR and FPSCR + return OptoReg::Bad; + } + + return opto_reg; } +void SaveLiveRegisters::initialize(BarrierStubC2* stub) { + // Record registers that needs to be saved/restored + RegMaskIterator rmi(stub->preserve_set()); + while (rmi.has_next()) { + const OptoReg::Name opto_reg = rmi.next(); + if (OptoReg::is_reg(opto_reg)) { + const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if (vm_reg->is_Register()) { + gp_regs += RegSet::of(vm_reg->as_Register()); + } else if (vm_reg->is_FloatRegister()) { + fp_regs += FloatRegSet::of(vm_reg->as_FloatRegister()); + } else { + fatal("Unknown register type"); + } + } + } + // Remove C-ABI SOE registers that will be updated + gp_regs -= RegSet::range(R4, R11) + RegSet::of(R13, R15); + + // Remove C-ABI SOE fp registers + fp_regs -= FloatRegSet::range(S16, S31); +} + +SaveLiveRegisters::SaveLiveRegisters(MacroAssembler* masm, BarrierStubC2* stub) + : masm(masm), + gp_regs(), + fp_regs() { + // Figure out what registers to save/restore + initialize(stub); + + // Save registers + if (gp_regs.size() > 0) __ push(RegisterSet::from(gp_regs)); + if (fp_regs.size() > 0) __ fpush(FloatRegisterSet::from(fp_regs)); +} + +SaveLiveRegisters::~SaveLiveRegisters() { + // Restore registers + if (fp_regs.size() > 0) __ fpop(FloatRegisterSet::from(fp_regs)); + if (gp_regs.size() > 0) __ pop(RegisterSet::from(gp_regs)); +} #endif // COMPILER2 diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp index 60021390ea26f..054d172f46340 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp @@ -31,7 +31,9 @@ #ifdef COMPILER2 #include "code/vmreg.hpp" #include "opto/optoreg.hpp" +#include "opto/regmask.hpp" +class BarrierStubC2; class Node; #endif // COMPILER2 @@ -69,4 +71,26 @@ class BarrierSetAssembler: public CHeapObj { #endif // COMPILER2 }; +#ifdef COMPILER2 +// This class saves and restores the registers that need to be preserved across +// the runtime call represented by a given C2 barrier stub. Use as follows: +// { +// SaveLiveRegisters save(masm, stub); +// .. +// __ bl(...); +// .. +// } +class SaveLiveRegisters { +private: + MacroAssembler* const masm; + RegSet gp_regs; + FloatRegSet fp_regs; + +public: + void initialize(BarrierStubC2* stub); + SaveLiveRegisters(MacroAssembler* masm, BarrierStubC2* stub); + ~SaveLiveRegisters(); +}; + +#endif // COMPILER2 #endif // CPU_ARM_GC_SHARED_BARRIERSETASSEMBLER_ARM_HPP diff --git a/src/hotspot/cpu/arm/register_arm.hpp b/src/hotspot/cpu/arm/register_arm.hpp index 9f486d2a62586..d8961fd293578 100644 --- a/src/hotspot/cpu/arm/register_arm.hpp +++ b/src/hotspot/cpu/arm/register_arm.hpp @@ -303,6 +303,31 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { static const int max_fpr; }; +typedef AbstractRegSet RegSet; +typedef AbstractRegSet FloatRegSet; + +template <> +inline Register AbstractRegSet::first() { + if (_bitset == 0) { return noreg; } + return as_Register(count_trailing_zeros(_bitset)); +} + + +template <> +inline FloatRegister AbstractRegSet::first() { + uint32_t first = _bitset & -_bitset; + return first ? as_FloatRegister(exact_log2(first)) : fnoreg; +} + +template <> +inline FloatRegister AbstractRegSet::last() { + if (_bitset == 0) { return fnoreg; } + int last = max_size() - 1 - count_leading_zeros(_bitset); + return as_FloatRegister(last); +} + + + class VFPSystemRegisterImpl; typedef VFPSystemRegisterImpl* VFPSystemRegister; class VFPSystemRegisterImpl : public AbstractRegisterImpl { diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp index 7d230d301c22b..39693bdf925bf 100644 --- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp @@ -41,10 +41,20 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> +static void generate_marking_inactive_test(MacroAssembler* masm) { + int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbz(R0, active_offset, R16_thread); // tmp1 := *(mark queue active address) + __ cmpwi(CCR0, R0, 0); +} + void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register from, Register to, Register count, Register preserve1, Register preserve2) { @@ -58,13 +68,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm Label filtered; // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ lwz(R0, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread); - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbz(R0, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread); - } - __ cmpdi(CCR0, R0, 0); + generate_marking_inactive_test(masm); __ beq(CCR0, filtered); __ save_LR(R0); @@ -109,35 +113,48 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ restore_LR(R0); } +static void generate_queue_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register value, const Register temp) { + assert_different_registers(value, temp); + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + __ ld(temp, in_bytes(index_offset), R16_thread); // temp := *(index address) + __ cmpdi(CCR0, temp, 0); // jump to runtime if index == 0 (full buffer) + __ beq(CCR0, runtime); + // The buffer is not full, store value into it. + __ ld(R0, in_bytes(buffer_offset), R16_thread); // R0 := buffer address + __ addi(temp, temp, -wordSize); // temp := next index + __ std(temp, in_bytes(index_offset), R16_thread); // *(index address) := next index + __ stdx(value, temp, R0); // *(buffer address + next index) := value +} + void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, DecoratorSet decorators, Register obj, RegisterOrConstant ind_or_offs, Register pre_val, Register tmp1, Register tmp2, MacroAssembler::PreservationLevel preservation_level) { + assert_different_registers(pre_val, tmp1, tmp2); + bool not_null = (decorators & IS_NOT_NULL) != 0, preloaded = obj == noreg; Register nv_save = noreg; - if (preloaded) { + // Determine necessary runtime invocation preservation measures + const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR; + const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS; + const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS; + int nbytes_save = 0; + + if (pre_val->is_volatile() && preloaded && !preserve_gp_registers) { // We are not loading the previous value so make // sure that we don't trash the value in pre_val // with the code below. - assert_different_registers(pre_val, tmp1, tmp2); - if (pre_val->is_volatile()) { - nv_save = !tmp1->is_volatile() ? tmp1 : tmp2; - assert(!nv_save->is_volatile(), "need one nv temp register if pre_val lives in volatile register"); - } + nv_save = !tmp1->is_volatile() ? tmp1 : tmp2; + assert(!nv_save->is_volatile(), "need one nv temp register if pre_val lives in volatile register"); } Label runtime, filtered; - // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ lwz(tmp1, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread); - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbz(tmp1, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()), R16_thread); - } - __ cmpdi(CCR0, tmp1, 0); + generate_marking_inactive_test(masm); __ beq(CCR0, filtered); // Do we need to load the previous value? @@ -175,28 +192,12 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator // Can we store original value in the thread's buffer? // Is index == 0? // (The index field is typed as size_t.) - const Register Rbuffer = tmp1, Rindex = tmp2; - - __ ld(Rindex, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()), R16_thread); - __ cmpdi(CCR0, Rindex, 0); - __ beq(CCR0, runtime); // If index == 0, goto runtime. - __ ld(Rbuffer, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()), R16_thread); - - __ addi(Rindex, Rindex, -wordSize); // Decrement index. - __ std(Rindex, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()), R16_thread); - - // Record the previous value. - __ stdx(pre_val, Rbuffer, Rindex); + generate_queue_insertion(masm, G1ThreadLocalData::satb_mark_queue_index_offset(), G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, pre_val, tmp1); __ b(filtered); __ bind(runtime); - // Determine necessary runtime invocation preservation measures - const bool needs_frame = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR; - const bool preserve_gp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_REGS; - const bool preserve_fp_registers = preservation_level >= MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS; - int nbytes_save = 0; - // May need to preserve LR. Also needed if current frame is not compatible with C calling convention. if (needs_frame) { if (preserve_gp_registers) { @@ -210,11 +211,11 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator __ push_frame_reg_args(nbytes_save, tmp2); } - if (pre_val->is_volatile() && preloaded && !preserve_gp_registers) { + if (nv_save != noreg) { __ mr(nv_save, pre_val); // Save pre_val across C call if it was preloaded. } __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, R16_thread); - if (pre_val->is_volatile() && preloaded && !preserve_gp_registers) { + if (nv_save != noreg) { __ mr(pre_val, nv_save); // restore } @@ -230,6 +231,26 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator __ bind(filtered); } +static void generate_region_crossing_test(MacroAssembler* masm, const Register store_addr, const Register new_val) { + __ xorr(R0, store_addr, new_val); // tmp1 := store address ^ new value + __ srdi_(R0, R0, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes) +} + +static Address generate_card_young_test(MacroAssembler* masm, const Register store_addr, const Register tmp1, const Register tmp2) { + CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); + __ load_const_optimized(tmp1, (address)(ct->card_table()->byte_map_base()), tmp2); + __ srdi(tmp2, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base + __ lbzx(R0, tmp1, tmp2); // tmp1 := card address + __ cmpwi(CCR0, R0, (int)G1CardTable::g1_young_card_val()); + return Address(tmp1, tmp2); // return card address +} + +static void generate_card_dirty_test(MacroAssembler* masm, Address card_addr) { + __ membar(Assembler::StoreLoad); // Must reload after StoreLoad membar due to concurrent refinement + __ lbzx(R0, card_addr.base(), card_addr.index()); // tmp2 := card + __ cmpwi(CCR0, R0, (int)G1CardTable::dirty_card_val()); // tmp2 := card == dirty_card_val? +} + void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, DecoratorSet decorators, Register store_addr, Register new_val, Register tmp1, Register tmp2, Register tmp3, @@ -241,9 +262,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); - // Does store cross heap regions? - __ xorr(tmp1, store_addr, new_val); - __ srdi_(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); + generate_region_crossing_test(masm, store_addr, new_val); __ beq(CCR0, filtered); // Crosses regions, storing null? @@ -257,43 +276,22 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato __ beq(CCR0, filtered); } - // Storing region crossing non-null, is card already dirty? - const Register Rcard_addr = tmp1; - Register Rbase = tmp2; - __ load_const_optimized(Rbase, (address)(ct->card_table()->byte_map_base()), /*temp*/ tmp3); - - __ srdi(Rcard_addr, store_addr, CardTable::card_shift()); - - // Get the address of the card. - __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr); - __ cmpwi(CCR0, tmp3, (int)G1CardTable::g1_young_card_val()); + Address card_addr = generate_card_young_test(masm, store_addr, tmp1, tmp2); __ beq(CCR0, filtered); - __ membar(Assembler::StoreLoad); - __ lbzx(/*card value*/ tmp3, Rbase, Rcard_addr); // Reload after membar. - __ cmpwi(CCR0, tmp3 /* card value */, (int)G1CardTable::dirty_card_val()); + generate_card_dirty_test(masm, card_addr); __ beq(CCR0, filtered); - // Storing a region crossing, non-null oop, card is clean. - // Dirty card and log. - __ li(tmp3, (int)G1CardTable::dirty_card_val()); - //release(); // G1: oops are allowed to get visible after dirty marking. - __ stbx(tmp3, Rbase, Rcard_addr); - - __ add(Rcard_addr, Rbase, Rcard_addr); // This is the address which needs to get enqueued. - Rbase = noreg; // end of lifetime + __ li(R0, (int)G1CardTable::dirty_card_val()); + __ stbx(R0, card_addr.base(), card_addr.index()); // *(card address) := dirty_card_val - const Register Rqueue_index = tmp2, - Rqueue_buf = tmp3; - __ ld(Rqueue_index, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()), R16_thread); - __ cmpdi(CCR0, Rqueue_index, 0); - __ beq(CCR0, runtime); // index == 0 then jump to runtime - __ ld(Rqueue_buf, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()), R16_thread); + Register Rcard_addr = tmp3; + __ add(Rcard_addr, card_addr.base(), card_addr.index()); // This is the address which needs to get enqueued. - __ addi(Rqueue_index, Rqueue_index, -wordSize); // decrement index - __ std(Rqueue_index, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()), R16_thread); - - __ stdx(Rcard_addr, Rqueue_buf, Rqueue_index); // store card + generate_queue_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, Rcard_addr, tmp1); __ b(filtered); __ bind(runtime); @@ -392,6 +390,142 @@ void G1BarrierSetAssembler::resolve_jobject(MacroAssembler* masm, Register value __ bind(done); } +#ifdef COMPILER2 + +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { + SaveLiveRegisters save_registers(masm, stub); + __ call_VM_leaf(runtime_path, arg, R16_thread); +} + +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* stub) { + assert_different_registers(obj, tmp1, tmp2, R0); + assert_different_registers(pre_val, tmp1, R0); + assert(!UseCompressedOops || tmp2 != noreg, "tmp2 needed with CompressedOops"); + + stub->initialize_registers(obj, pre_val, R16_thread, tmp1, tmp2); + + generate_marking_inactive_test(masm); + __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *stub->entry()); + + __ bind(*stub->continuation()); +} + +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register tmp1 = stub->tmp1(); + + __ bind(*stub->entry()); + + if (obj != noreg) { + // Note: C2 currently doesn't use implicit null checks with barriers. + // Otherwise, obj could be null and the following instruction would raise a SIGSEGV. + if (UseCompressedOops) { + __ lwz(pre_val, 0, obj); + } else { + __ ld(pre_val, 0, obj); + } + } + __ cmpdi(CCR0, pre_val, 0); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), *stub->continuation()); + + Register pre_val_decoded = pre_val; + if (UseCompressedOops) { + pre_val_decoded = __ decode_heap_oop_not_null(stub->tmp2(), pre_val); + } + + generate_queue_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, pre_val_decoded, tmp1); + __ b(*stub->continuation()); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, pre_val_decoded, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); + __ b(*stub->continuation()); +} + +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* stub, + bool decode_new_val) { + assert_different_registers(store_addr, new_val, tmp1, R0); + assert_different_registers(store_addr, tmp1, tmp2, R0); + + stub->initialize_registers(R16_thread, tmp1, tmp2); + + bool null_check_required = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; + Register new_val_decoded = new_val; + + if (decode_new_val) { + assert(UseCompressedOops, "or should not be here"); + if (null_check_required && CompressedOops::base() != nullptr) { + // We prefer doing the null check after the region crossing check. + // Only compressed oop modes with base != null require a null check here. + __ cmpwi(CCR0, new_val, 0); + __ beq(CCR0, *stub->continuation()); + null_check_required = false; + } + new_val_decoded = __ decode_heap_oop_not_null(tmp2, new_val); + } + + generate_region_crossing_test(masm, store_addr, new_val_decoded); + __ beq(CCR0, *stub->continuation()); + + // crosses regions, storing null? + if (null_check_required) { + __ cmpdi(CCR0, new_val_decoded, 0); + __ beq(CCR0, *stub->continuation()); + } + + Address card_addr = generate_card_young_test(masm, store_addr, tmp1, tmp2); + assert(card_addr.base() == tmp1 && card_addr.index() == tmp2, "needed by post barrier stub"); + __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *stub->entry()); + + __ bind(*stub->continuation()); +} + +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Address card_addr(stub->tmp1(), stub->tmp2()); // See above. + + __ bind(*stub->entry()); + + generate_card_dirty_test(masm, card_addr); + __ bc_far_optimized(Assembler::bcondCRbiIs1, __ bi0(CCR0, Assembler::equal), *stub->continuation()); + + __ li(R0, (int)G1CardTable::dirty_card_val()); + __ stbx(R0, card_addr.base(), card_addr.index()); // *(card address) := dirty_card_val + + Register Rcard_addr = stub->tmp1(); + __ add(Rcard_addr, card_addr.base(), card_addr.index()); // This is the address which needs to get enqueued. + + generate_queue_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, Rcard_addr, stub->tmp2()); + __ b(*stub->continuation()); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, Rcard_addr, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); + __ b(*stub->continuation()); +} + +#endif // COMPILER2 + #ifdef COMPILER1 #undef __ @@ -470,13 +604,7 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* __ std(tmp2, -24, R1_SP); // Is marking still active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ lwz(tmp, satb_q_active_byte_offset, R16_thread); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbz(tmp, satb_q_active_byte_offset, R16_thread); - } - __ cmpdi(CCR0, tmp, 0); + generate_marking_inactive_test(sasm); __ beq(CCR0, marking_not_active); __ bind(restart); diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp index d9a252ff6eaee..1c9fe8a5d106f 100644 --- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.hpp @@ -30,10 +30,16 @@ #include "gc/shared/modRefBarrierSetAssembler.hpp" #include "utilities/macros.hpp" +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif + class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -59,6 +65,25 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { MacroAssembler::PreservationLevel preservation_level); public: +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* c2_stub, + bool decode_new_val); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif #ifdef COMPILER1 void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); diff --git a/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad b/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad new file mode 100644 index 0000000000000..f4163242cad7b --- /dev/null +++ b/src/hotspot/cpu/ppc/gc/g1/g1_ppc.ad @@ -0,0 +1,684 @@ +// +// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2024 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. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_ppc.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void pre_write_barrier(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2 = noreg, // only needed with CompressedOops when pre_val needs to be preserved + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, tmp1, (tmp2 != noreg) ? tmp2 : pre_val, stub); +} + +static void post_write_barrier(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2, + bool decode_new_val = false) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, tmp1, tmp2, stub, decode_new_val); +} + +%} + +instruct g1StoreP(indirect mem, iRegPsrc src, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "std $mem, $src\t# ptr" %} + ins_encode %{ + pre_write_barrier(masm, this, + $mem$$Register, + $tmp1$$Register, + $tmp2$$Register, + noreg, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ std($src$$Register, 0, $mem$$Register); + post_write_barrier(masm, this, + $mem$$Register, + $src$$Register /* new_val */, + $tmp1$$Register, + $tmp2$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1StoreN(indirect mem, iRegNsrc src, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "stw $mem, $src\t# ptr" %} + ins_encode %{ + pre_write_barrier(masm, this, + $mem$$Register, + $tmp1$$Register, + $tmp2$$Register, + noreg, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ stw($src$$Register, 0, $mem$$Register); + post_write_barrier(masm, this, + $mem$$Register, + $src$$Register /* new_val */, + $tmp1$$Register, + $tmp2$$Register, + true /* decode_new_val */); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1EncodePAndStoreN(indirect mem, iRegPsrc src, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "encode_heap_oop $src\n\t" + "stw $mem, $src\t# ptr" %} + ins_encode %{ + pre_write_barrier(masm, this, + $mem$$Register, + $tmp1$$Register, + $tmp2$$Register, + noreg, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + Register encoded_oop = noreg; + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + encoded_oop = __ encode_heap_oop($tmp2$$Register, $src$$Register); + } else { + encoded_oop = __ encode_heap_oop_not_null($tmp2$$Register, $src$$Register); + } + __ stw(encoded_oop, 0, $mem$$Register); + post_write_barrier(masm, this, + $mem$$Register, + $src$$Register /* new_val */, + $tmp1$$Register, + $tmp2$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndExchangeP(iRegPdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndExchangeNode*)n)->order() != MemNode::acquire && ((CompareAndExchangeNode*)n)->order() != MemNode::seqcst)); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "cmpxchgd $newval, $mem" %} + ins_encode %{ + Label no_update; + __ cmpxchgd(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndExchangeP_acq(iRegPdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndExchangeNode*)n)->order() == MemNode::acquire || ((CompareAndExchangeNode*)n)->order() == MemNode::seqcst)); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "cmpxchgd acq $newval, $mem" %} + ins_encode %{ + Label no_update; + __ cmpxchgd(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register); + __ bind(no_update); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndExchangeN(iRegNdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndExchangeNode*)n)->order() != MemNode::acquire && ((CompareAndExchangeNode*)n)->order() != MemNode::seqcst)); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "cmpxchgw $newval, $mem" %} + ins_encode %{ + Label no_update; + __ cmpxchgw(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register, + true /* decode_new_val */); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndExchangeN_acq(iRegNdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndExchangeNode*)n)->order() == MemNode::acquire || ((CompareAndExchangeNode*)n)->order() == MemNode::seqcst)); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "cmpxchgw acq $newval, $mem" %} + ins_encode %{ + Label no_update; + __ cmpxchgw(CCR0, $res$$Register, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register, + true /* decode_new_val */); + __ bind(no_update); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndSwapP(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst)); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "CMPXCHGD $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */); + __ li($res$$Register, 1); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndSwapP_acq(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "CMPXCHGD acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */); + __ li($res$$Register, 1); + __ bind(no_update); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndSwapN(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst)); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "CMPXCHGW $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */, + true /* decode_new_val */); + __ li($res$$Register, 1); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1CompareAndSwapN_acq(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "CMPXCHGW acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */, + true /* decode_new_val */); + __ li($res$$Register, 1); + __ bind(no_update); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct weakG1CompareAndSwapP(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst)); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "weak CMPXCHGD $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */); + __ li($res$$Register, 1); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct weakG1CompareAndSwapP_acq(iRegIdst res, indirect mem, iRegPsrc oldval, iRegPsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "weak CMPXCHGD acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgd(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */); + __ li($res$$Register, 1); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + __ bind(no_update); // weak version requires no memory barrier on failure + %} + ins_pipe(pipe_class_default); +%} + +instruct weakG1CompareAndSwapN(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst)); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "weak CMPXCHGW $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */, + true /* decode_new_val */); + __ li($res$$Register, 1); + __ bind(no_update); + %} + ins_pipe(pipe_class_default); +%} + +instruct weakG1CompareAndSwapN_acq(iRegIdst res, indirect mem, iRegNsrc oldval, iRegNsrc newval, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0 && + (((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst)); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP_DEF res, TEMP tmp, KILL cr0); + format %{ "weak CMPXCHGW acq $res, $mem, $oldval, $newval; as bool; ptr" %} + ins_encode %{ + Label no_update; + __ li($res$$Register, 0); + __ cmpxchgw(CCR0, R0, $oldval$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), + noreg, &no_update, true, true); + // Pass oldval to SATB which is the only value which can get overwritten. + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg, + $oldval$$Register /* pre_val */, + $tmp$$Register, + $res$$Register /* temp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp$$Register, + $res$$Register /* temp */, + true /* decode_new_val */); + __ li($res$$Register, 1); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + // isync would be sufficient in case of CompareAndExchangeAcquire, but we currently don't optimize for that. + __ sync(); + } + __ bind(no_update); // weak version requires no memory barrier on failure + %} + ins_pipe(pipe_class_default); +%} + +instruct g1GetAndSetP(iRegPdst res, indirect mem, iRegPsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (GetAndSetP mem newval)); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "GetAndSetP $newval, $mem" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + __ getandsetd($res$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::cmpxchgx_hint_atomic_update()); + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg /* obj */, + $res$$Register /* res */, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct g1GetAndSetN(iRegNdst res, indirect mem, iRegNsrc newval, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (GetAndSetN mem newval)); + effect(TEMP_DEF res, TEMP tmp1, TEMP tmp2, KILL cr0); + format %{ "GetAndSetN $newval, $mem" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + __ getandsetw($res$$Register, $newval$$Register, $mem$$Register, + MacroAssembler::cmpxchgx_hint_atomic_update()); + // Can be done after cmpxchg because there's no safepoint here. + pre_write_barrier(masm, this, + noreg /* obj */, + $res$$Register /* res */, + $tmp1$$Register, + $tmp2$$Register, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + post_write_barrier(masm, this, + $mem$$Register, + $newval$$Register, + $tmp1$$Register, + $tmp2$$Register, + true /* decode_new_val */); + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + __ isync(); + } else { + __ sync(); + } + %} + ins_pipe(pipe_class_default); +%} + +instruct g1LoadP(iRegPdst dst, memoryAlg4 mem, iRegPdst tmp, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_Load()->is_unordered() && n->as_Load()->barrier_data() != 0); + // This instruction does not need an acquiring counterpart because it is only + // used for reference loading (Reference::get()). + match(Set dst (LoadP mem)); + effect(TEMP_DEF dst, TEMP tmp, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "ld $dst, $mem\t# ptr" %} + ins_encode %{ + __ ld($dst$$Register, $mem$$disp, $mem$$base$$Register); + pre_write_barrier(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp$$Register); + %} + ins_pipe(pipe_class_default); +%} + +instruct g1LoadN(iRegNdst dst, memoryAlg4 mem, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR0 cr0) +%{ + predicate(UseG1GC && n->as_Load()->is_unordered() && n->as_Load()->barrier_data() != 0); + // This instruction does not need an acquiring counterpart because it is only + // used for reference loading (Reference::get()). + match(Set dst (LoadN mem)); + effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2, KILL cr0); + ins_cost(2 * MEMORY_REF_COST); + format %{ "lwz $dst, $mem\t# ptr" %} + ins_encode %{ + __ lwz($dst$$Register, $mem$$disp, $mem$$base$$Register); + pre_write_barrier(masm, this, + noreg /* obj */, + $dst$$Register, + $tmp1$$Register, + $tmp2$$Register); + %} + ins_pipe(pipe_class_default); +%} diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index ca9abfa3719b4..d15f9929671ba 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -1000,6 +1000,10 @@ int MachNode::compute_padding(int current_offset) const { // Should the matcher clone input 'm' of node 'n'? bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { + if (is_encode_and_store_pattern(n, m)) { + mstack.push(m, Visit); + return true; + } return false; } @@ -5407,7 +5411,7 @@ instruct loadRange(iRegIdst dst, memory mem) %{ // Load Compressed Pointer instruct loadN(iRegNdst dst, memory mem) %{ match(Set dst (LoadN mem)); - predicate(n->as_Load()->is_unordered() || followed_by_acquire(n)); + predicate((n->as_Load()->is_unordered() || followed_by_acquire(n)) && n->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); format %{ "LWZ $dst, $mem \t// load compressed ptr" %} @@ -5419,6 +5423,7 @@ instruct loadN(iRegNdst dst, memory mem) %{ // Load Compressed Pointer acquire. instruct loadN_ac(iRegNdst dst, memory mem) %{ match(Set dst (LoadN mem)); + predicate(n->as_Load()->barrier_data() == 0); ins_cost(3*MEMORY_REF_COST); format %{ "LWZ $dst, $mem \t// load acquire compressed ptr\n\t" @@ -5432,7 +5437,7 @@ instruct loadN_ac(iRegNdst dst, memory mem) %{ // Load Compressed Pointer and decode it if narrow_oop_shift == 0. instruct loadN2P_unscaled(iRegPdst dst, memory mem) %{ match(Set dst (DecodeN (LoadN mem))); - predicate(_kids[0]->_leaf->as_Load()->is_unordered() && CompressedOops::shift() == 0); + predicate(_kids[0]->_leaf->as_Load()->is_unordered() && CompressedOops::shift() == 0 && _kids[0]->_leaf->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); format %{ "LWZ $dst, $mem \t// DecodeN (unscaled)" %} @@ -6423,6 +6428,7 @@ instruct reinterpretX(vecX dst) %{ // Store Compressed Oop instruct storeN(memory dst, iRegN_P2N src) %{ match(Set dst (StoreN dst src)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); format %{ "STW $src, $dst \t// compressed oop" %} @@ -7477,6 +7483,7 @@ instruct compareAndSwapI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc instruct compareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndSwapN mem_ptr (Binary src1 src2))); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ @@ -7676,7 +7683,7 @@ instruct weakCompareAndSwapI_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, instruct weakCompareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (WeakCompareAndSwapN mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "weak CMPXCHGW $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ @@ -7690,7 +7697,7 @@ instruct weakCompareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iReg instruct weakCompareAndSwapN_acq_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (WeakCompareAndSwapN mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst); + predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); // TEMP_DEF to avoid jump format %{ "weak CMPXCHGW acq $res, $mem_ptr, $src1, $src2; as bool" %} ins_encode %{ @@ -7939,7 +7946,7 @@ instruct compareAndExchangeI_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, instruct compareAndExchangeN_regP_regN_regN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeN mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst); + predicate(((CompareAndSwapNode*)n)->order() != MemNode::acquire && ((CompareAndSwapNode*)n)->order() != MemNode::seqcst && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); format %{ "CMPXCHGW $res, $mem_ptr, $src1, $src2; as narrow oop" %} ins_encode %{ @@ -7953,7 +7960,7 @@ instruct compareAndExchangeN_regP_regN_regN(iRegNdst res, iRegPdst mem_ptr, iReg instruct compareAndExchangeN_acq_regP_regN_regN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src1, iRegNsrc src2, flagsRegCR0 cr0) %{ match(Set res (CompareAndExchangeN mem_ptr (Binary src1 src2))); - predicate(((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst); + predicate((((CompareAndSwapNode*)n)->order() == MemNode::acquire || ((CompareAndSwapNode*)n)->order() == MemNode::seqcst) && n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); format %{ "CMPXCHGW acq $res, $mem_ptr, $src1, $src2; as narrow oop" %} ins_encode %{ @@ -8262,6 +8269,7 @@ instruct getAndSetP(iRegPdst res, iRegPdst mem_ptr, iRegPsrc src, flagsRegCR0 cr instruct getAndSetN(iRegNdst res, iRegPdst mem_ptr, iRegNsrc src, flagsRegCR0 cr0) %{ match(Set res (GetAndSetN mem_ptr src)); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(TEMP_DEF res, TEMP cr0); format %{ "GetAndSetN $res, $mem_ptr, $src" %} ins_encode %{ diff --git a/src/hotspot/cpu/ppc/register_ppc.hpp b/src/hotspot/cpu/ppc/register_ppc.hpp index 302d49884fae3..b7ba4f053b5d6 100644 --- a/src/hotspot/cpu/ppc/register_ppc.hpp +++ b/src/hotspot/cpu/ppc/register_ppc.hpp @@ -27,6 +27,7 @@ #define CPU_PPC_REGISTER_PPC_HPP #include "asm/register.hpp" +#include "utilities/count_trailing_zeros.hpp" // forward declaration class VMRegImpl; @@ -555,4 +556,12 @@ constexpr Register R29_TOC = R29; constexpr Register R11_scratch1 = R11; constexpr Register R12_scratch2 = R12; +template <> +inline Register AbstractRegSet::first() { + if (_bitset == 0) { return noreg; } + return as_Register(count_trailing_zeros(_bitset)); +} + +typedef AbstractRegSet RegSet; + #endif // CPU_PPC_REGISTER_PPC_HPP diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp index 062f80290626f..7036c44d99dc9 100644 --- a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,10 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> @@ -96,6 +99,55 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ pop_reg(saved_regs, sp); } +static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register thread, const Register value, const Register tmp1, const Register tmp2) { + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + __ ld(tmp1, Address(thread, in_bytes(index_offset))); // tmp1 := *(index address) + __ beqz(tmp1, runtime); // jump to runtime if index == 0 (full buffer) + // The buffer is not full, store value into it. + __ sub(tmp1, tmp1, wordSize); // tmp1 := next index + __ sd(tmp1, Address(thread, in_bytes(index_offset))); // *(index address) := next index + __ ld(tmp2, Address(thread, in_bytes(buffer_offset))); // tmp2 := buffer address + __ add(tmp2, tmp2, tmp1); + __ sd(value, Address(tmp2)); // *(buffer address + next index) := value +} + +static void generate_pre_barrier_fast_path(MacroAssembler* masm, + const Register thread, + const Register tmp1) { + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ lwu(tmp1, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbu(tmp1, in_progress); + } +} + +static void generate_pre_barrier_slow_path(MacroAssembler* masm, + const Register obj, + const Register pre_val, + const Register thread, + const Register tmp1, + const Register tmp2, + Label& done, + Label& runtime) { + // Do we need to load the previous value? + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + } + // Is the previous value null? + __ beqz(pre_val, done, true); + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, + thread, pre_val, tmp1, tmp2); + __ j(done); +} + void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, @@ -116,43 +168,10 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, assert_different_registers(obj, pre_val, tmp1, tmp2); assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - - // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { // 4-byte width - __ lwu(tmp1, in_progress); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ lbu(tmp1, in_progress); - } + generate_pre_barrier_fast_path(masm, thread, tmp1); + // If marking is not active (*(mark queue active address) == 0), jump to done __ beqz(tmp1, done); - - // Do we need to load the previous value? - if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); - } - - // Is the previous value null? - __ beqz(pre_val, done); - - // Can we store original value in the thread's buffer? - // Is index == 0? - // (The index field is typed as size_t.) - - __ ld(tmp1, index); // tmp := *index_adr - __ beqz(tmp1, runtime); // tmp == 0? - // If yes, goto runtime - - __ sub(tmp1, tmp1, wordSize); // tmp := tmp - wordSize - __ sd(tmp1, index); // *index_adr := tmp - __ ld(tmp2, buffer); - __ add(tmp1, tmp1, tmp2); // tmp := tmp + *buffer_adr - - // Record the previous value - __ sd(pre_val, Address(tmp1, 0)); - __ j(done); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, done, runtime); __ bind(runtime); @@ -171,6 +190,49 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, } +static void generate_post_barrier_fast_path(MacroAssembler* masm, + const Register store_addr, + const Register new_val, + const Register tmp1, + const Register tmp2, + Label& done, + bool new_val_may_be_null) { + // Does store cross heap regions? + __ xorr(tmp1, store_addr, new_val); // tmp1 := store address ^ new value + __ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); // tmp1 := ((store address ^ new value) >> LogOfHRGrainBytes) + __ beqz(tmp1, done); + // Crosses regions, storing null? + if (new_val_may_be_null) { + __ beqz(new_val, done); + } + // Storing region crossing non-null, is card young? + __ srli(tmp1, store_addr, CardTable::card_shift()); // tmp1 := card address relative to card table base + __ load_byte_map_base(tmp2); // tmp2 := card table base address + __ add(tmp1, tmp1, tmp2); // tmp1 := card address + __ lbu(tmp2, Address(tmp1)); // tmp2 := card +} + +static void generate_post_barrier_slow_path(MacroAssembler* masm, + const Register thread, + const Register tmp1, + const Register tmp2, + Label& done, + Label& runtime) { + __ membar(MacroAssembler::StoreLoad); // StoreLoad membar + __ lbu(tmp2, Address(tmp1)); // tmp2 := card + __ beqz(tmp2, done, true); + // Storing a region crossing, non-null oop, card is clean. + // Dirty card and log. + STATIC_ASSERT(CardTable::dirty_card_val() == 0); + __ sb(zr, Address(tmp1)); // *(card address) := dirty_card_val + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, + thread, tmp1, tmp2, t0); + __ j(done); +} + void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, @@ -179,73 +241,119 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register tmp2) { assert(thread == xthread, "must be"); assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, t0); - assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && - tmp2 != noreg, "expecting a register"); - - Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - BarrierSet* bs = BarrierSet::barrier_set(); - CardTableBarrierSet* ctbs = barrier_set_cast(bs); + assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, + "expecting a register"); Label done; Label runtime; - // Does store cross heap regions? + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, done, true /* new_val_may_be_null */); + // If card is young, jump to done (tmp2 holds the card value) + __ mv(t0, (int)G1CardTable::g1_young_card_val()); + __ beq(tmp2, t0, done); // card == young_card_val? + generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, done, runtime); - __ xorr(tmp1, store_addr, new_val); - __ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); - __ beqz(tmp1, done); + __ bind(runtime); + // save the live input values + RegSet saved = RegSet::of(store_addr); + __ push_reg(saved, sp); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp1, thread); + __ pop_reg(saved, sp); - // crosses regions, storing null? + __ bind(done); +} - __ beqz(new_val, done); +#if defined(COMPILER2) - // storing region crossing non-null, is card already dirty? +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { + SaveLiveRegisters save_registers(masm, stub); + if (c_rarg0 != arg) { + __ mv(c_rarg0, arg); + } + __ mv(c_rarg1, xthread); + __ mv(t0, runtime_path); + __ jalr(t0); +} - const Register card_addr = tmp1; +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* stub) { + assert(thread == xthread, "must be"); + assert_different_registers(obj, pre_val, tmp1, tmp2); + assert(pre_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); - __ srli(card_addr, store_addr, CardTable::card_shift()); + stub->initialize_registers(obj, pre_val, thread, tmp1, tmp2); - // get the address of the card - __ load_byte_map_base(tmp2); - __ add(card_addr, card_addr, tmp2); - __ lbu(tmp2, Address(card_addr)); - __ mv(t0, (int)G1CardTable::g1_young_card_val()); - __ beq(tmp2, t0, done); + generate_pre_barrier_fast_path(masm, thread, tmp1); + // If marking is active (*(mark queue active address) != 0), jump to stub (slow path) + __ bnez(tmp1, *stub->entry(), true); - assert((int)CardTable::dirty_card_val() == 0, "must be 0"); + __ bind(*stub->continuation()); +} - __ membar(MacroAssembler::StoreLoad); +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); + Register tmp2 = stub->tmp2(); - __ lbu(tmp2, Address(card_addr)); - __ beqz(tmp2, done); + __ bind(*stub->entry()); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp1, tmp2, *stub->continuation(), runtime); - // storing a region crossing, non-null oop, card is clean. - // dirty card and log. + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); + __ j(*stub->continuation()); +} - __ sb(zr, Address(card_addr)); +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* stub) { + assert(thread == xthread, "must be"); + assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, t0); + assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, + "expecting a register"); - __ ld(t0, queue_index); - __ beqz(t0, runtime); - __ sub(t0, t0, wordSize); - __ sd(t0, queue_index); + stub->initialize_registers(thread, tmp1, tmp2); - __ ld(tmp2, buffer); - __ add(t0, tmp2, t0); - __ sd(card_addr, Address(t0, 0)); - __ j(done); + bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp1, tmp2, *stub->continuation(), new_val_may_be_null); + // If card is not young, jump to stub (slow path) (tmp2 holds the card value) + __ mv(t0, (int)G1CardTable::g1_young_card_val()); + __ bne(tmp2, t0, *stub->entry(), true); - __ bind(runtime); - // save the live input values - RegSet saved = RegSet::of(store_addr); - __ push_reg(saved, sp); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); - __ pop_reg(saved, sp); + __ bind(*stub->continuation()); +} - __ bind(done); +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); // tmp1 holds the card address. + Register tmp2 = stub->tmp2(); + + __ bind(*stub->entry()); + generate_post_barrier_slow_path(masm, thread, tmp1, tmp2, *stub->continuation(), runtime); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); + __ j(*stub->continuation()); } +#endif // COMPILER2 + void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp2) { bool on_oop = is_reference_type(type); diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp index 96568994079dd..c7bee2ef6f3a8 100644 --- a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, 2024, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,8 @@ class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -72,6 +74,27 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); #endif +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + Register tmp2, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* c2_stub); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif + void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp2); }; diff --git a/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad new file mode 100644 index 0000000000000..1dc5834dbdc89 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/g1/g1_riscv.ad @@ -0,0 +1,564 @@ +// +// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2024, Huawei Technologies Co., Ltd. All rights reserved. +// 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. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_riscv.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void write_barrier_pre(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp1, + Register tmp2, + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, xthread, tmp1, tmp2, stub); +} + +static void write_barrier_post(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, xthread, tmp1, tmp2, stub); +} + +%} + +instruct g1StoreP(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(STORE_COST); + format %{ "sd $src, $mem\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ sd($src$$Register, Address($mem$$Register)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +instruct g1StoreN(indirect mem, iRegN src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(STORE_COST); + format %{ "sw $src, $mem\t# compressed ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + __ sw($src$$Register, Address($mem$$Register)); + if ((barrier_data() & G1C2BarrierPost) != 0) { + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ decode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ decode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + } + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(STORE_COST); + format %{ "encode_heap_oop $tmp1, $src\n\t" + "sw $tmp1, $mem\t# compressed ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ encode_heap_oop($tmp1$$Register, $src$$Register); + } else { + __ encode_heap_oop_not_null($tmp1$$Register, $src$$Register); + } + __ sw($tmp1$$Register, Address($mem$$Register)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(istore_reg_mem); +%} + +instruct g1CompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $res = $mem, $oldval, $newval\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP and its Acq variant. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP and its Acq variant. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $res = $mem, $oldval, $newval\t# narrow oop" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $res = $mem, $oldval, $newval\t# narrow oop" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndSwapP(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $mem, $oldval, $newval\t# (ptr)\n\t" + "mv $res, $res == $oldval" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegP oldval) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (ptr)\n\t" + "mv $res, $res == $oldval" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndSwapN(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "cmpxchg $mem, $oldval, $newval\t# (narrow oop)\n\t" + "mv $res, $res == $oldval" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1CompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegN oldval) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(VOLATILE_REF_COST); + format %{ "cmpxchg_acq $mem, $oldval, $newval\t# (narrow oop)\n\t" + "mv $res, $res == $oldval" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($oldval$$Register, $mem$$Register); + assert_different_registers($newval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_slow); +%} + +instruct g1GetAndSetP(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "atomic_xchg $preval, $newval, [$mem]" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchg($preval$$Register, $newval$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +instruct g1GetAndSetPAcq(indirect mem, iRegP newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp preval) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetP mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2); + ins_cost(VOLATILE_REF_COST); + format %{ "atomic_xchg_acq $preval, $newval, [$mem]" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $preval$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgal($preval$$Register, $newval$$Register, $mem$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +instruct g1GetAndSetN(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetN mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(2 * VOLATILE_REF_COST); + format %{ "atomic_xchgwu $preval, $newval, [$mem]" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgwu($preval$$Register, $newval$$Register, $mem$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +instruct g1GetAndSetNAcq(indirect mem, iRegN newval, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3, iRegNNoSp preval) +%{ + predicate(UseG1GC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + match(Set preval (GetAndSetN mem newval)); + effect(TEMP preval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(VOLATILE_REF_COST); + format %{ "atomic_xchgwu_acq $preval, $newval, [$mem]" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */, + RegSet::of($mem$$Register, $preval$$Register, $newval$$Register) /* preserve */); + __ atomic_xchgalwu($preval$$Register, $newval$$Register, $mem$$Register); + __ decode_heap_oop($tmp1$$Register, $newval$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_serial); +%} + +instruct g1LoadP(iRegPNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2) +%{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2); + ins_cost(LOAD_COST + BRANCH_COST); + format %{ "ld $dst, $mem\t# ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + __ ld($dst$$Register, Address($mem$$Register)); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(iload_reg_mem); +%} + +instruct g1LoadN(iRegNNoSp dst, indirect mem, iRegPNoSp tmp1, iRegPNoSp tmp2, iRegPNoSp tmp3) +%{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadN mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, TEMP tmp3); + ins_cost(LOAD_COST + BRANCH_COST); + format %{ "lwu $dst, $mem\t# compressed ptr" %} + ins_encode %{ + guarantee($mem$$disp == 0, "impossible encoding"); + __ lwu($dst$$Register, Address($mem$$Register)); + if ((barrier_data() & G1C2BarrierPre) != 0) { + __ decode_heap_oop($tmp1$$Register, $dst$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + } + %} + ins_pipe(iload_reg_mem); +%} diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 05f55fd0da7af..563dfd4cde972 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -2224,7 +2224,8 @@ bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { assert_cond(m != nullptr); if (is_vshift_con_pattern(n, m) || // ShiftV src (ShiftCntV con) is_vector_bitwise_not_pattern(n, m) || - is_vector_scalar_bitwise_pattern(n, m)) { + is_vector_scalar_bitwise_pattern(n, m) || + is_encode_and_store_pattern(n, m)) { mstack.push(m, Visit); return true; } @@ -4785,6 +4786,7 @@ instruct loadP(iRegPNoSp dst, memory mem) // Load Compressed Pointer instruct loadN(iRegNNoSp dst, memory mem) %{ + predicate(n->as_Load()->barrier_data() == 0); match(Set dst (LoadN mem)); ins_cost(LOAD_COST); @@ -5220,6 +5222,7 @@ instruct storeimmP0(immP0 zero, memory mem) // Store Compressed Pointer instruct storeN(iRegN src, memory mem) %{ + predicate(n->as_Store()->barrier_data() == 0); match(Set mem (StoreN mem src)); ins_cost(STORE_COST); @@ -5234,6 +5237,7 @@ instruct storeN(iRegN src, memory mem) instruct storeImmN0(immN0 zero, memory mem) %{ + predicate(n->as_Store()->barrier_data() == 0); match(Set mem (StoreN mem zero)); ins_cost(STORE_COST); @@ -5424,6 +5428,7 @@ instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndSwapN mem (Binary oldval newval))); ins_cost(LOAD_COST + STORE_COST + ALU_COST * 8 + BRANCH_COST * 4); @@ -5545,7 +5550,7 @@ instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP new instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndSwapN mem (Binary oldval newval))); @@ -5653,6 +5658,7 @@ instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL ne instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 3); @@ -5786,7 +5792,7 @@ instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndExchangeN mem (Binary oldval newval))); @@ -5914,6 +5920,7 @@ instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL ne instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 4); @@ -6045,7 +6052,7 @@ instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0); match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); @@ -6117,6 +6124,8 @@ instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set prev (GetAndSetN mem newv)); ins_cost(ALU_COST); @@ -6182,7 +6191,7 @@ instruct get_and_setLAcq(indirect mem, iRegL newv, iRegLNoSp prev) instruct get_and_setNAcq(indirect mem, iRegN newv, iRegINoSp prev) %{ - predicate(needs_acquiring_load_reserved(n)); + predicate(needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == 0); match(Set prev (GetAndSetN mem newv)); diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp index 37631298920ca..544c82d34a769 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018, 2023 SAP SE. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024 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 @@ -42,11 +42,47 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> -#define BLOCK_COMMENT(str) if (PrintAssembly) __ block_comment(str) +#define BLOCK_COMMENT(str) __ block_comment(str) + +static void generate_pre_barrier_fast_path(MacroAssembler* masm, + const Register thread, + const Register tmp1) { + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ load_and_test_int(tmp1, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ load_and_test_byte(tmp1, in_progress); + } +} + +static void generate_queue_test_and_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register Z_thread, const Register value, const Register temp) { + BLOCK_COMMENT("generate_queue_test_and_insertion {"); + + assert_different_registers(temp, value); + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + + __ load_and_test_long(temp, Address(Z_thread, in_bytes(index_offset))); // temp := *(index address) + __ branch_optimized(Assembler::bcondEqual, runtime); // jump to runtime if index == 0 (full buffer) + + // The buffer is not full, store value into it. + __ add2reg(temp, -wordSize); // temp := next index + __ z_stg(temp, in_bytes(index_offset), Z_thread); // *(index address) := next index + + __ z_ag(temp, Address(Z_thread, in_bytes(buffer_offset))); // temp := buffer address + next index + __ z_stg(value, 0, temp); // *(buffer address + next index) := value + BLOCK_COMMENT("} generate_queue_test_and_insertion"); +} void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count) { @@ -59,13 +95,8 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm assert_different_registers(addr, Z_R0_scratch); // would be destroyed by push_frame() assert_different_registers(count, Z_R0_scratch); // would be destroyed by push_frame() Register Rtmp1 = Z_R0_scratch; - const int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ load_and_test_int(Rtmp1, Address(Z_thread, active_offset)); - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ load_and_test_byte(Rtmp1, Address(Z_thread, active_offset)); - } + + generate_pre_barrier_fast_path(masm, Z_thread, Rtmp1); __ z_bre(filtered); // Activity indicator is zero, so there is no marking going on currently. RegisterSaver::save_live_registers(masm, RegisterSaver::arg_registers); // Creates frame. @@ -100,6 +131,181 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas } } +#if defined(COMPILER2) + +#undef __ +#define __ masm-> + +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register pre_val, const address runtime_path) { + BLOCK_COMMENT("generate_c2_barrier_runtime_call {"); + SaveLiveRegisters save_registers(masm, stub); + __ call_VM_leaf(runtime_path, pre_val, Z_thread); + BLOCK_COMMENT("} generate_c2_barrier_runtime_call"); +} + +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + G1PreBarrierStubC2* stub) { + + BLOCK_COMMENT("g1_write_barrier_pre_c2 {"); + + assert(thread == Z_thread, "must be"); + assert_different_registers(obj, pre_val, tmp1); + assert(pre_val != noreg && tmp1 != noreg, "expecting a register"); + + stub->initialize_registers(obj, pre_val, thread, tmp1, noreg); + + generate_pre_barrier_fast_path(masm, thread, tmp1); + __ branch_optimized(Assembler::bcondNotEqual, *stub->entry()); // Activity indicator is zero, so there is no marking going on currently. + + __ bind(*stub->continuation()); + + BLOCK_COMMENT("} g1_write_barrier_pre_c2"); +} + +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + + BLOCK_COMMENT("generate_c2_pre_barrier_stub {"); + + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); + + __ bind(*stub->entry()); + + BLOCK_COMMENT("generate_pre_val_not_null_test {"); + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj), noreg, noreg, AS_RAW); + } + __ z_ltgr(pre_val, pre_val); + __ branch_optimized(Assembler::bcondEqual, *stub->continuation()); + BLOCK_COMMENT("} generate_pre_val_not_null_test"); + + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, + Z_thread, pre_val, tmp1); + + __ branch_optimized(Assembler::bcondAlways, *stub->continuation()); + + __ bind(runtime); + + generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); + + __ branch_optimized(Assembler::bcondAlways, *stub->continuation()); + + BLOCK_COMMENT("} generate_c2_pre_barrier_stub"); +} + +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* stub) { + BLOCK_COMMENT("g1_write_barrier_post_c2 {"); + + assert(thread == Z_thread, "must be"); + assert_different_registers(store_addr, new_val, thread, tmp1, tmp2, Z_R1_scratch); + + assert(store_addr != noreg && new_val != noreg && tmp1 != noreg && tmp2 != noreg, "expecting a register"); + + stub->initialize_registers(thread, tmp1, tmp2); + + BLOCK_COMMENT("generate_region_crossing_test {"); + if (VM_Version::has_DistinctOpnds()) { + __ z_xgrk(tmp1, store_addr, new_val); + } else { + __ z_lgr(tmp1, store_addr); + __ z_xgr(tmp1, new_val); + } + __ z_srag(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); + __ branch_optimized(Assembler::bcondEqual, *stub->continuation()); + BLOCK_COMMENT("} generate_region_crossing_test"); + + // crosses regions, storing null? + if ((stub->barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ z_ltgr(new_val, new_val); + __ branch_optimized(Assembler::bcondEqual, *stub->continuation()); + } + + BLOCK_COMMENT("generate_card_young_test {"); + CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); + // calculate address of card + __ load_const_optimized(tmp2, (address)ct->card_table()->byte_map_base()); // Card table base. + __ z_srlg(tmp1, store_addr, CardTable::card_shift()); // Index into card table. + __ z_algr(tmp1, tmp2); // Explicit calculation needed for cli. + + // Filter young. + __ z_cli(0, tmp1, G1CardTable::g1_young_card_val()); + + BLOCK_COMMENT("} generate_card_young_test"); + + // From here on, tmp1 holds the card address. + __ branch_optimized(Assembler::bcondNotEqual, *stub->entry()); + + __ bind(*stub->continuation()); + + BLOCK_COMMENT("} g1_write_barrier_post_c2"); +} + +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + + BLOCK_COMMENT("generate_c2_post_barrier_stub {"); + + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + + Register thread = stub->thread(); + Register tmp1 = stub->tmp1(); // tmp1 holds the card address. + Register tmp2 = stub->tmp2(); + Register Rcard_addr = tmp1; + + __ bind(*stub->entry()); + + BLOCK_COMMENT("generate_card_clean_test {"); + __ z_sync(); // Required to support concurrent cleaning. + __ z_cli(0, Rcard_addr, 0); // Reload after membar. + __ branch_optimized(Assembler::bcondEqual, *stub->continuation()); + BLOCK_COMMENT("} generate_card_clean_test"); + + BLOCK_COMMENT("generate_dirty_card {"); + // Storing a region crossing, non-null oop, card is clean. + // Dirty card and log. + STATIC_ASSERT(CardTable::dirty_card_val() == 0); + __ z_mvi(0, Rcard_addr, CardTable::dirty_card_val()); + BLOCK_COMMENT("} generate_dirty_card"); + + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, + Z_thread, tmp1, tmp2); + + __ branch_optimized(Assembler::bcondAlways, *stub->continuation()); + + __ bind(runtime); + + generate_c2_barrier_runtime_call(masm, stub, tmp1, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); + + __ branch_optimized(Assembler::bcondAlways, *stub->continuation()); + + BLOCK_COMMENT("} generate_c2_post_barrier_stub"); +} + +#endif //COMPILER2 + void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, const Address& src, Register dst, Register tmp1, Register tmp2, Label *L_handle_null) { bool on_oop = is_reference_type(type); @@ -136,9 +342,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator const Register Robj = obj ? obj->base() : noreg, Roff = obj ? obj->index() : noreg; - const int active_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - const int buffer_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - const int index_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); assert_different_registers(Rtmp1, Rtmp2, Z_R0_scratch); // None of the Rtmp must be Z_R0!! assert_different_registers(Robj, Z_R0_scratch); // Used for addressing. Furthermore, push_frame destroys Z_R0!! assert_different_registers(Rval, Z_R0_scratch); // push_frame destroys Z_R0!! @@ -147,14 +350,7 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator BLOCK_COMMENT("g1_write_barrier_pre {"); - // Is marking active? - // Note: value is loaded for test purposes only. No further use here. - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ load_and_test_int(Rtmp1, Address(Z_thread, active_offset)); - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ load_and_test_byte(Rtmp1, Address(Z_thread, active_offset)); - } + generate_pre_barrier_fast_path(masm, Z_thread, Rtmp1); __ z_bre(filtered); // Activity indicator is zero, so there is no marking going on currently. assert(Rpre_val != noreg, "must have a real register"); @@ -194,24 +390,14 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Decorator // We can store the original value in the thread's buffer // only if index > 0. Otherwise, we need runtime to handle. // (The index field is typed as size_t.) - Register Rbuffer = Rtmp1, Rindex = Rtmp2; - assert_different_registers(Rbuffer, Rindex, Rpre_val); - - __ z_lg(Rbuffer, buffer_offset, Z_thread); - __ load_and_test_long(Rindex, Address(Z_thread, index_offset)); - __ z_bre(callRuntime); // If index == 0, goto runtime. - - __ add2reg(Rindex, -wordSize); // Decrement index. - __ z_stg(Rindex, index_offset, Z_thread); - - // Record the previous value. - __ z_stg(Rpre_val, 0, Rbuffer, Rindex); + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + callRuntime, + Z_thread, Rpre_val, Rtmp2); __ z_bru(filtered); // We are done. - Rbuffer = noreg; // end of life - Rindex = noreg; // end of life - __ bind(callRuntime); // Save some registers (inputs and result) over runtime call @@ -326,23 +512,16 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato Register Rcard_addr_x = Rcard_addr; Register Rqueue_index = (Rtmp2 != Z_R0_scratch) ? Rtmp2 : Rtmp1; - Register Rqueue_buf = (Rtmp3 != Z_R0_scratch) ? Rtmp3 : Rtmp1; - const int qidx_off = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()); - const int qbuf_off = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()); - if ((Rcard_addr == Rqueue_buf) || (Rcard_addr == Rqueue_index)) { + if (Rcard_addr == Rqueue_index) { Rcard_addr_x = Z_R0_scratch; // Register shortage. We have to use Z_R0. } __ lgr_if_needed(Rcard_addr_x, Rcard_addr); - __ load_and_test_long(Rqueue_index, Address(Z_thread, qidx_off)); - __ z_bre(callRuntime); // Index == 0 then jump to runtime. - - __ z_lg(Rqueue_buf, qbuf_off, Z_thread); - - __ add2reg(Rqueue_index, -wordSize); // Decrement index. - __ z_stg(Rqueue_index, qidx_off, Z_thread); - - __ z_stg(Rcard_addr_x, 0, Rqueue_index, Rqueue_buf); // Store card. + generate_queue_test_and_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + callRuntime, + Z_thread, Rcard_addr_x, Rqueue_index); __ z_bru(filtered); __ bind(callRuntime); diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp index cc1d51d2fa13e..0f0bdd8b83cfd 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2018 SAP SE. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024 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 @@ -34,6 +34,8 @@ class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -62,7 +64,27 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); -#endif +#endif // COMPILER1 + +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp1, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp1, + Register tmp2, + G1PostBarrierStubC2* c2_stub); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif // COMPILER2 virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, const Address& src, Register dst, Register tmp1, Register tmp2, Label *L_handle_null = nullptr); diff --git a/src/hotspot/cpu/s390/gc/g1/g1_s390.ad b/src/hotspot/cpu/s390/gc/g1/g1_s390.ad new file mode 100644 index 0000000000000..31f60c4aeff0b --- /dev/null +++ b/src/hotspot/cpu/s390/gc/g1/g1_s390.ad @@ -0,0 +1,457 @@ +// +// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +// Copyright 2024 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. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_s390.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void write_barrier_pre(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp1, + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, Z_thread, tmp1, stub); +} + +static void write_barrier_post(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, Z_thread, tmp1, tmp2, stub); +} + +%} // source + +// store pointer +instruct g1StoreP(indirect dst, memoryRegP src, iRegL tmp1, iRegL tmp2, flagsReg cr) %{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set dst (StoreP dst src)); + effect(TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(MEMORY_REF_COST); + format %{ "STG $src,$dst\t # ptr" %} + ins_encode %{ + __ block_comment("g1StoreP {"); + write_barrier_pre(masm, this, + $dst$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($dst$$Register, $src$$Register) /* preserve */); + + __ z_stg($src$$Register, Address($dst$$Register)); + + write_barrier_post(masm, this, + $dst$$Register, /* store_addr */ + $src$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + __ block_comment("} g1StoreP"); + %} + ins_pipe(pipe_class_dummy); +%} + +// Store Compressed Pointer +instruct g1StoreN(indirect mem, iRegN_P2N src, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(MEMORY_REF_COST); + format %{ "STY $src,$mem\t # (cOop)" %} + ins_encode %{ + __ block_comment("g1StoreN {"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + + __ z_sty($src$$Register, Address($mem$$Register)); + + if ((barrier_data() & G1C2BarrierPost) != 0) { + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ oop_decoder($tmp1$$Register, $src$$Register, true /* maybe_null */); + } else { + __ oop_decoder($tmp1$$Register, $src$$Register, false /* maybe_null */); + } + } + + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + __ block_comment("} g1StoreN"); + %} + + ins_pipe(pipe_class_dummy); +%} + +instruct g1CompareAndSwapN(indirect mem_ptr, rarg5RegN oldval, iRegN_P2N newval, iRegI res, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); + effect(USE mem_ptr, TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, USE_KILL oldval, KILL cr); + format %{ "$res = CompareAndSwapN $oldval,$newval,$mem_ptr" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem_ptr$$Register); + assert_different_registers($newval$$Register, $mem_ptr$$Register); + __ block_comment("g1compareAndSwapN {"); + + Register Rcomp = reg_to_register_object($oldval$$reg); + Register Rnew = reg_to_register_object($newval$$reg); + Register Raddr = reg_to_register_object($mem_ptr$$reg); + Register Rres = reg_to_register_object($res$$reg); + + write_barrier_pre(masm, this, + Raddr /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of(Raddr, Rcomp, Rnew) /* preserve */, + RegSet::of(Rres) /* no_preserve */); + + __ z_cs(Rcomp, Rnew, 0, Raddr); + + assert_different_registers(Rres, Raddr); + if (VM_Version::has_LoadStoreConditional()) { + __ load_const_optimized(Z_R0_scratch, 0L); // false (failed) + __ load_const_optimized(Rres, 1L); // true (succeed) + __ z_locgr(Rres, Z_R0_scratch, Assembler::bcondNotEqual); + } else { + Label done; + __ load_const_optimized(Rres, 0L); // false (failed) + __ z_brne(done); // Assume true to be the common case. + __ load_const_optimized(Rres, 1L); // true (succeed) + __ bind(done); + } + + __ oop_decoder($tmp3$$Register, Rnew, true /* maybe_null */); + + write_barrier_post(masm, this, + Raddr /* store_addr */, + $tmp3$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + __ block_comment("} g1compareAndSwapN"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1CompareAndExchangeN(iRegP mem_ptr, rarg5RegN oldval, iRegN_P2N newval, iRegN res, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeN mem_ptr (Binary oldval newval))); + effect(USE mem_ptr, TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, USE_KILL oldval, KILL cr); + format %{ "$res = CompareAndExchangeN $oldval,$newval,$mem_ptr" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem_ptr$$Register); + assert_different_registers($newval$$Register, $mem_ptr$$Register); + __ block_comment("g1CompareAndExchangeN {"); + write_barrier_pre(masm, this, + $mem_ptr$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($mem_ptr$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + + Register Rcomp = reg_to_register_object($oldval$$reg); + Register Rnew = reg_to_register_object($newval$$reg); + Register Raddr = reg_to_register_object($mem_ptr$$reg); + + Register Rres = reg_to_register_object($res$$reg); + assert_different_registers(Rres, Raddr); + + __ z_lgr(Rres, Rcomp); // previous contents + __ z_csy(Rres, Rnew, 0, Raddr); // Try to store new value. + + __ oop_decoder($tmp1$$Register, Rnew, true /* maybe_null */); + + write_barrier_post(masm, this, + Raddr /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + __ block_comment("} g1CompareAndExchangeN"); + %} + ins_pipe(pipe_class_dummy); +%} + +// Load narrow oop +instruct g1LoadN(iRegN dst, indirect mem, iRegP tmp1, iRegP tmp2, flagsReg cr) %{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadN mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(MEMORY_REF_COST); + format %{ "LoadN $dst,$mem\t # (cOop)" %} + ins_encode %{ + __ block_comment("g1LoadN {"); + __ z_llgf($dst$$Register, Address($mem$$Register)); + if ((barrier_data() & G1C2BarrierPre) != 0) { + __ oop_decoder($tmp1$$Register, $dst$$Register, true); + write_barrier_pre(masm, this, + noreg /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register ); + } + __ block_comment("} g1LoadN"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1GetAndSetN(indirect mem, iRegN dst, iRegI tmp, iRegL tmp1, iRegL tmp2, iRegL tmp3, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set dst (GetAndSetN mem dst)); + effect(KILL cr, TEMP tmp, TEMP tmp1, TEMP tmp2, TEMP tmp3); // USE_DEF dst by match rule. + format %{ "XCHGN $dst,[$mem]\t # EXCHANGE (coop, atomic), temp $tmp" %} + ins_encode %{ + __ block_comment("g1GetAndSetN {"); + assert_different_registers($mem$$Register, $dst$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($mem$$Register, $dst$$Register) /* preserve */); + + Register Rdst = reg_to_register_object($dst$$reg); + Register Rtmp = reg_to_register_object($tmp$$reg); + guarantee(Rdst != Rtmp, "Fix match rule to use TEMP_DEF"); + Label retry; + + // Iterate until swap succeeds. + __ z_llgf(Rtmp, Address($mem$$Register)); // current contents + __ bind(retry); + // Calculate incremented value. + __ z_csy(Rtmp, Rdst, Address($mem$$Register)); // Try to store new value. + __ z_brne(retry); // Yikes, concurrent update, need to retry. + + __ oop_decoder($tmp1$$Register, $dst$$Register, true /* maybe_null */); + + __ z_lgr(Rdst, Rtmp); // Exchanged value from memory is return value. + + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + + __ block_comment("} g1GetAndSetN"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1CompareAndSwapP(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, iRegI res, iRegL tmp1, iRegL tmp2, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, USE mem_ptr, USE_KILL oldval, KILL cr); + format %{ "$res = CompareAndSwapP $oldval,$newval,$mem_ptr" %} + ins_encode %{ + __ block_comment("g1CompareAndSwapP {"); + assert_different_registers($oldval$$Register, $mem_ptr$$Register); + assert_different_registers($newval$$Register, $mem_ptr$$Register); + + Register Rcomp = reg_to_register_object($oldval$$reg); + Register Rnew = reg_to_register_object($newval$$reg); + Register Raddr = reg_to_register_object($mem_ptr$$reg); + Register Rres = reg_to_register_object($res$$reg); + + write_barrier_pre(masm, this, + noreg /* obj */, + Rcomp /* pre_val */, + $tmp1$$Register /* tmp1 */, + RegSet::of(Raddr, Rcomp, Rnew) /* preserve */, + RegSet::of(Rres) /* no_preserve */); + + __ z_csg(Rcomp, Rnew, 0, Raddr); + + if (VM_Version::has_LoadStoreConditional()) { + __ load_const_optimized(Z_R0_scratch, 0L); // false (failed) + __ load_const_optimized(Rres, 1L); // true (succeed) + __ z_locgr(Rres, Z_R0_scratch, Assembler::bcondNotEqual); + } else { + Label done; + __ load_const_optimized(Rres, 0L); // false (failed) + __ z_brne(done); // Assume true to be the common case. + __ load_const_optimized(Rres, 1L); // true (succeed) + __ bind(done); + } + + write_barrier_post(masm, this, + Raddr /* store_addr */, + Rnew /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + __ block_comment("} g1CompareAndSwapP"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1CompareAndExchangeP(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, iRegP res, iRegL tmp1, iRegL tmp2, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndExchangeP mem_ptr (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, USE mem_ptr, USE_KILL oldval, KILL cr); + format %{ "$res = CompareAndExchangeP $oldval,$newval,$mem_ptr" %} + ins_encode %{ + __ block_comment("g1CompareAndExchangeP {"); + assert_different_registers($oldval$$Register, $mem_ptr$$Register); + assert_different_registers($newval$$Register, $mem_ptr$$Register); + + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($mem_ptr$$Register, $oldval$$Register, $newval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + + __ z_lgr($res$$Register, $oldval$$Register); // previous content + + __ z_csg($oldval$$Register, $newval$$Register, 0, $mem_ptr$$reg); + + write_barrier_post(masm, this, + $mem_ptr$$Register /* store_addr */, + $newval$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + __ block_comment("} g1CompareAndExchangeP"); + %} + ins_pipe(pipe_class_dummy); +%} + +// Load Pointer +instruct g1LoadP(iRegP dst, memory mem, iRegL tmp1, flagsReg cr) %{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp1, KILL cr); + ins_cost(MEMORY_REF_COST); + format %{ "LG $dst,$mem\t # ptr" %} + ins_encode %{ + __ block_comment("g1LoadP {"); + __ z_lg($dst$$Register, $mem$$Address); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp1$$Register ); + __ block_comment("} g1LoadP"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1GetAndSetP(indirect mem, iRegP dst, iRegL tmp, iRegL tmp1, iRegL tmp2, flagsReg cr) %{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set dst (GetAndSetP mem dst)); + effect(KILL cr, TEMP tmp, TEMP tmp1, TEMP tmp2); // USE_DEF dst by match rule. + format %{ "XCHGP $dst,[$mem]\t # EXCHANGE (oop, atomic), temp $tmp" %} + ins_encode %{ + __ block_comment("g1GetAndSetP {"); + + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp$$Register /* pre_val (as a temporary register) */, + $tmp1$$Register /* tmp1 */, + RegSet::of($mem$$Register, $dst$$Register) /* preserve */); + + __ z_lgr($tmp1$$Register, $dst$$Register); + Register Rdst = reg_to_register_object($dst$$reg); + Register Rtmp = reg_to_register_object($tmp$$reg); + guarantee(Rdst != Rtmp, "Fix match rule to use TEMP_DEF"); + Label retry; + + // Iterate until swap succeeds. + __ z_lg(Rtmp, Address($mem$$Register)); // current contents + __ bind(retry); + // Calculate incremented value. + __ z_csg(Rtmp, Rdst, Address($mem$$Register)); // Try to store new value. + __ z_brne(retry); // Yikes, concurrent update, need to retry. + __ z_lgr(Rdst, Rtmp); // Exchanged value from memory is return value. + + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp$$Register /* tmp2 */); + __ block_comment("} g1GetAndSetP"); + %} + ins_pipe(pipe_class_dummy); +%} + +instruct g1EncodePAndStoreN(indirect mem, iRegP src, iRegL tmp1, iRegL tmp2, flagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, KILL cr); + // ins_cost(INSN_COST); + format %{ "encode_heap_oop $tmp1, $src\n\t" + "st $tmp1, $mem\t# compressed ptr" %} + ins_encode %{ + __ block_comment("g1EncodePAndStoreN {"); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp1 */, + RegSet::of($mem$$Register, $src$$Register) /* preserve */); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ oop_encoder($tmp1$$Register, $src$$Register, true /* maybe_null */); + } else { + __ oop_encoder($tmp1$$Register, $src$$Register, false /* maybe_null */); + } + __ z_st($tmp1$$Register, Address($mem$$Register)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp1$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + __ block_comment("} g1EncodePAndStoreN"); + %} + ins_pipe(pipe_class_dummy); +%} diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp index 28892da6ca4c1..d826b4a06f336 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.cpp @@ -33,6 +33,9 @@ #include "runtime/jniHandles.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/macros.hpp" +#ifdef COMPILER2 +#include "gc/shared/c2/barrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> @@ -194,8 +197,93 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { #ifdef COMPILER2 -OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) { - Unimplemented(); // This must be implemented to support late barrier expansion. +OptoReg::Name BarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) const { + if (!OptoReg::is_reg(opto_reg)) { + return OptoReg::Bad; + } + + VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if ((vm_reg->is_Register() || vm_reg ->is_FloatRegister()) && (opto_reg & 1) != 0) { + return OptoReg::Bad; + } + + return opto_reg; +} + +#undef __ +#define __ _masm-> + +SaveLiveRegisters::SaveLiveRegisters(MacroAssembler *masm, BarrierStubC2 *stub) + : _masm(masm), _reg_mask(stub->preserve_set()) { + + const int register_save_size = iterate_over_register_mask(ACTION_COUNT_ONLY) * BytesPerWord; + + _frame_size = align_up(register_save_size, frame::alignment_in_bytes) + frame::z_abi_160_size; // FIXME: this could be restricted to argument only + + __ save_return_pc(); + __ push_frame(_frame_size, Z_R14); // FIXME: check if Z_R1_scaratch can do a job here; + + __ z_lg(Z_R14, _z_common_abi(return_pc) + _frame_size, Z_SP); + + iterate_over_register_mask(ACTION_SAVE, _frame_size); +} + +SaveLiveRegisters::~SaveLiveRegisters() { + iterate_over_register_mask(ACTION_RESTORE, _frame_size); + + __ pop_frame(); + + __ restore_return_pc(); +} + +int SaveLiveRegisters::iterate_over_register_mask(IterationAction action, int offset) { + int reg_save_index = 0; + RegMaskIterator live_regs_iterator(_reg_mask); + + while(live_regs_iterator.has_next()) { + const OptoReg::Name opto_reg = live_regs_iterator.next(); + + // Filter out stack slots (spilled registers, i.e., stack-allocated registers). + if (!OptoReg::is_reg(opto_reg)) { + continue; + } + + const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if (vm_reg->is_Register()) { + Register std_reg = vm_reg->as_Register(); + + if (std_reg->encoding() >= Z_R2->encoding() && std_reg->encoding() <= Z_R15->encoding()) { + reg_save_index++; + + if (action == ACTION_SAVE) { + __ z_stg(std_reg, offset - reg_save_index * BytesPerWord, Z_SP); + } else if (action == ACTION_RESTORE) { + __ z_lg(std_reg, offset - reg_save_index * BytesPerWord, Z_SP); + } else { + assert(action == ACTION_COUNT_ONLY, "Sanity"); + } + } + } else if (vm_reg->is_FloatRegister()) { + FloatRegister fp_reg = vm_reg->as_FloatRegister(); + if (fp_reg->encoding() >= Z_F0->encoding() && fp_reg->encoding() <= Z_F15->encoding() + && fp_reg->encoding() != Z_F1->encoding()) { + reg_save_index++; + + if (action == ACTION_SAVE) { + __ z_std(fp_reg, offset - reg_save_index * BytesPerWord, Z_SP); + } else if (action == ACTION_RESTORE) { + __ z_ld(fp_reg, offset - reg_save_index * BytesPerWord, Z_SP); + } else { + assert(action == ACTION_COUNT_ONLY, "Sanity"); + } + } + } else if (false /* vm_reg->is_VectorRegister() */){ + fatal("Vector register support is not there yet!"); + } else { + fatal("Register type is not known"); + } + } + return reg_save_index; } #endif // COMPILER2 diff --git a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp index de1de8a51a7f1..fb61adc55b500 100644 --- a/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/gc/shared/barrierSetAssembler_s390.hpp @@ -32,7 +32,9 @@ #ifdef COMPILER2 #include "code/vmreg.hpp" #include "opto/optoreg.hpp" +#include "opto/regmask.hpp" +class BarrierStubC2; class Node; #endif // COMPILER2 @@ -62,8 +64,42 @@ class BarrierSetAssembler: public CHeapObj { #ifdef COMPILER2 OptoReg::Name refine_register(const Node* node, - OptoReg::Name opto_reg); + OptoReg::Name opto_reg) const; #endif // COMPILER2 }; +#ifdef COMPILER2 + +// This class saves and restores the registers that need to be preserved across +// the runtime call represented by a given C2 barrier stub. Use as follows: +// { +// SaveLiveRegisters save(masm, stub); +// .. +// __ call_VM_leaf(...); +// .. +// } + +class SaveLiveRegisters { + MacroAssembler* _masm; + RegMask _reg_mask; + Register _result_reg; + int _frame_size; + + public: + SaveLiveRegisters(MacroAssembler *masm, BarrierStubC2 *stub); + + ~SaveLiveRegisters(); + + private: + enum IterationAction : int { + ACTION_SAVE, + ACTION_RESTORE, + ACTION_COUNT_ONLY + }; + + int iterate_over_register_mask(IterationAction action, int offset = 0); +}; + +#endif // COMPILER2 + #endif // CPU_S390_GC_SHARED_BARRIERSETASSEMBLER_S390_HPP diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index af281345b1477..e192bbab0deb8 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -2127,8 +2127,9 @@ unsigned int MacroAssembler::push_frame_abi160(unsigned int bytes) { // Pop current C frame. void MacroAssembler::pop_frame() { - BLOCK_COMMENT("pop_frame:"); + BLOCK_COMMENT("pop_frame {"); Assembler::z_lg(Z_SP, _z_abi(callers_sp), Z_SP); + BLOCK_COMMENT("} pop_frame"); } // Pop current C frame and restore return PC register (Z_R14). diff --git a/src/hotspot/cpu/s390/register_s390.hpp b/src/hotspot/cpu/s390/register_s390.hpp index 931e899257e92..18af232e56970 100644 --- a/src/hotspot/cpu/s390/register_s390.hpp +++ b/src/hotspot/cpu/s390/register_s390.hpp @@ -448,4 +448,12 @@ constexpr Register Z_R0_scratch = Z_R0; constexpr Register Z_R1_scratch = Z_R1; constexpr FloatRegister Z_fscratch_1 = Z_F1; +typedef AbstractRegSet RegSet; + +template <> +inline Register AbstractRegSet::first() { + if (_bitset == 0) { return noreg; } + return as_Register(count_trailing_zeros(_bitset)); +} + #endif // CPU_S390_REGISTER_S390_HPP diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 1bc9484215005..8181e96ecfc55 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -1644,6 +1644,10 @@ const RegMask Matcher::method_handle_invoke_SP_save_mask() { // Should the matcher clone input 'm' of node 'n'? bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { + if (is_encode_and_store_pattern(n, m)) { + mstack.push(m, Visit); + return true; + } return false; } @@ -3913,6 +3917,7 @@ instruct loadL_unaligned(iRegL dst, memory mem) %{ // Load Pointer instruct loadP(iRegP dst, memory mem) %{ match(Set dst (LoadP mem)); + predicate(n->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "LG $dst,$mem\t # ptr" %} @@ -3924,6 +3929,7 @@ instruct loadP(iRegP dst, memory mem) %{ // LoadP + CastP2L instruct castP2X_loadP(iRegL dst, memory mem) %{ match(Set dst (CastP2X (LoadP mem))); + predicate(n->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "LG $dst,$mem\t # ptr + p2x" %} @@ -4286,6 +4292,7 @@ instruct storeL(memory mem, iRegL src) %{ // Store Pointer instruct storeP(memory dst, memoryRegP src) %{ match(Set dst (StoreP dst src)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "STG $src,$dst\t # ptr" %} @@ -4388,6 +4395,7 @@ instruct memInitL(memoryRS mem, immL16 src) %{ // Move Immediate to 8-byte memory. instruct memInitP(memoryRS mem, immP16 src) %{ match(Set mem (StoreP mem src)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(6); format %{ "MVGHI $mem,$src\t # direct mem init 8" %} @@ -4417,6 +4425,7 @@ instruct negL_reg_reg(iRegL dst, immL_0 zero, iRegL src, flagsReg cr) %{ // Load narrow oop instruct loadN(iRegN dst, memory mem) %{ match(Set dst (LoadN mem)); + predicate(n->as_Load()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "LoadN $dst,$mem\t # (cOop)" %} @@ -4480,7 +4489,7 @@ instruct loadConNKlass(iRegN dst, immNKlass src) %{ instruct decodeLoadN(iRegP dst, memory mem) %{ match(Set dst (DecodeN (LoadN mem))); - predicate(false && (CompressedOops::base()==nullptr)&&(CompressedOops::shift()==0)); + predicate(false && (CompressedOops::base()==nullptr) && (CompressedOops::shift()==0)); ins_cost(MEMORY_REF_COST); size(Z_DISP3_SIZE); format %{ "DecodeLoadN $dst,$mem\t # (cOop Load+Decode)" %} @@ -4735,6 +4744,7 @@ instruct encodeP_NN_Ex(iRegN dst, iRegP src, flagsReg cr) %{ // Store Compressed Pointer instruct storeN(memory mem, iRegN_P2N src) %{ match(Set mem (StoreN mem src)); + predicate(n->as_Store()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(Z_DISP_SIZE); format %{ "ST $src,$mem\t # (cOop)" %} @@ -5146,6 +5156,7 @@ instruct compareAndSwapL_bool(iRegP mem_ptr, rarg5RegL oldval, iRegL newval, iRe instruct compareAndSwapP_bool(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, iRegI res, flagsReg cr) %{ match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(USE mem_ptr, USE_KILL oldval, KILL cr); size(18); format %{ "$res = CompareAndSwapP $oldval,$newval,$mem_ptr" %} @@ -5156,6 +5167,7 @@ instruct compareAndSwapP_bool(iRegP mem_ptr, rarg5RegP oldval, iRegP_N2P newval, instruct compareAndSwapN_bool(iRegP mem_ptr, rarg5RegN oldval, iRegN_P2N newval, iRegI res, flagsReg cr) %{ match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(USE mem_ptr, USE_KILL oldval, KILL cr); size(16); format %{ "$res = CompareAndSwapN $oldval,$newval,$mem_ptr" %} @@ -5443,6 +5455,7 @@ instruct xchgL_reg_mem(memoryRSY mem, iRegL dst, iRegL tmp, flagsReg cr) %{ %} instruct xchgN_reg_mem(memoryRSY mem, iRegN dst, iRegI tmp, flagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set dst (GetAndSetN mem dst)); effect(KILL cr, TEMP tmp); // USE_DEF dst by match rule. format %{ "XCHGN $dst,[$mem]\t # EXCHANGE (coop, atomic), temp $tmp" %} @@ -5452,6 +5465,7 @@ instruct xchgN_reg_mem(memoryRSY mem, iRegN dst, iRegI tmp, flagsReg cr) %{ instruct xchgP_reg_mem(memoryRSY mem, iRegP dst, iRegL tmp, flagsReg cr) %{ match(Set dst (GetAndSetP mem dst)); + predicate(n->as_LoadStore()->barrier_data() == 0); effect(KILL cr, TEMP tmp); // USE_DEF dst by match rule. format %{ "XCHGP $dst,[$mem]\t # EXCHANGE (oop, atomic), temp $tmp" %} ins_encode(z_enc_SwapL(mem, dst, tmp)); @@ -5926,7 +5940,7 @@ instruct addP_regN_reg_imm20(iRegP dst, iRegP_N2P src1, iRegL src2, immL20 con) instruct addP_mem_imm(memoryRSY mem, immL8 src, flagsReg cr) %{ match(Set mem (StoreP mem (AddP (LoadP mem) src))); effect(KILL cr); - predicate(VM_Version::has_MemWithImmALUOps()); + predicate(VM_Version::has_MemWithImmALUOps() && n->as_LoadStore()->barrier_data() == 0); ins_cost(MEMORY_REF_COST); size(6); format %{ "AGSI $mem,$src\t # direct mem add 8 (ptr)" %} diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index b52be627776b8..b6be4012519a0 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -38,7 +38,10 @@ #include "c1/c1_LIRAssembler.hpp" #include "c1/c1_MacroAssembler.hpp" #include "gc/g1/c1/g1BarrierSetC1.hpp" -#endif +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#endif // COMPILER2 #define __ masm-> @@ -160,6 +163,56 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator } } +static void generate_queue_insertion(MacroAssembler* masm, ByteSize index_offset, ByteSize buffer_offset, Label& runtime, + const Register thread, const Register value, const Register temp) { + // This code assumes that buffer index is pointer sized. + STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t)); + // Can we store a value in the given thread's buffer? + // (The index field is typed as size_t.) + __ movptr(temp, Address(thread, in_bytes(index_offset))); // temp := *(index address) + __ testptr(temp, temp); // index == 0? + __ jcc(Assembler::zero, runtime); // jump to runtime if index == 0 (full buffer) + // The buffer is not full, store value into it. + __ subptr(temp, wordSize); // temp := next index + __ movptr(Address(thread, in_bytes(index_offset)), temp); // *(index address) := next index + __ addptr(temp, Address(thread, in_bytes(buffer_offset))); // temp := buffer address + next index + __ movptr(Address(temp, 0), value); // *(buffer address + next index) := value +} + +static void generate_pre_barrier_fast_path(MacroAssembler* masm, + const Register thread) { + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ cmpl(in_progress, 0); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ cmpb(in_progress, 0); + } +} + +static void generate_pre_barrier_slow_path(MacroAssembler* masm, + const Register obj, + const Register pre_val, + const Register thread, + const Register tmp, + Label& done, + Label& runtime) { + // Do we need to load the previous value? + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + } + // Is the previous value null? + __ cmpptr(pre_val, NULL_WORD); + __ jcc(Assembler::equal, done); + generate_queue_insertion(masm, + G1ThreadLocalData::satb_mark_queue_index_offset(), + G1ThreadLocalData::satb_mark_queue_buffer_offset(), + runtime, + thread, pre_val, tmp); + __ jmp(done); +} + void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, Register obj, Register pre_val, @@ -185,43 +238,10 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, assert(pre_val != rax, "check this code"); } - Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); - Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); - - // Is marking active? - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - __ cmpl(in_progress, 0); - } else { - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); - __ cmpb(in_progress, 0); - } - __ jcc(Assembler::equal, done); - - // Do we need to load the previous value? - if (obj != noreg) { - __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); - } - - // Is the previous value null? - __ cmpptr(pre_val, NULL_WORD); + generate_pre_barrier_fast_path(masm, thread); + // If marking is not active (*(mark queue active address) == 0), jump to done __ jcc(Assembler::equal, done); - - // Can we store original value in the thread's buffer? - // Is index == 0? - // (The index field is typed as size_t.) - - __ movptr(tmp, index); // tmp := *index_adr - __ cmpptr(tmp, 0); // tmp == 0? - __ jcc(Assembler::equal, runtime); // If yes, goto runtime - - __ subptr(tmp, wordSize); // tmp := tmp - wordSize - __ movptr(index, tmp); // *index_adr := tmp - __ addptr(tmp, buffer); // tmp := tmp + *buffer_adr - - // Record the previous value - __ movptr(Address(tmp, 0), pre_val); - __ jmp(done); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, done, runtime); __ bind(runtime); @@ -263,6 +283,54 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, __ bind(done); } +static void generate_post_barrier_fast_path(MacroAssembler* masm, + const Register store_addr, + const Register new_val, + const Register tmp, + const Register tmp2, + Label& done, + bool new_val_may_be_null) { + CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); + // Does store cross heap regions? + __ movptr(tmp, store_addr); // tmp := store address + __ xorptr(tmp, new_val); // tmp := store address ^ new value + __ shrptr(tmp, G1HeapRegion::LogOfHRGrainBytes); // ((store address ^ new value) >> LogOfHRGrainBytes) == 0? + __ jcc(Assembler::equal, done); + // Crosses regions, storing null? + if (new_val_may_be_null) { + __ cmpptr(new_val, NULL_WORD); // new value == null? + __ jcc(Assembler::equal, done); + } + // Storing region crossing non-null, is card young? + __ movptr(tmp, store_addr); // tmp := store address + __ shrptr(tmp, CardTable::card_shift()); // tmp := card address relative to card table base + // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT + // a valid address and therefore is not properly handled by the relocation code. + __ movptr(tmp2, (intptr_t)ct->card_table()->byte_map_base()); // tmp2 := card table base address + __ addptr(tmp, tmp2); // tmp := card address + __ cmpb(Address(tmp, 0), G1CardTable::g1_young_card_val()); // *(card address) == young_card_val? +} + +static void generate_post_barrier_slow_path(MacroAssembler* masm, + const Register thread, + const Register tmp, + const Register tmp2, + Label& done, + Label& runtime) { + __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); // StoreLoad membar + __ cmpb(Address(tmp, 0), G1CardTable::dirty_card_val()); // *(card address) == dirty_card_val? + __ jcc(Assembler::equal, done); + // Storing a region crossing, non-null oop, card is clean. + // Dirty card and log. + __ movb(Address(tmp, 0), G1CardTable::dirty_card_val()); // *(card address) := dirty_card_val + generate_queue_insertion(masm, + G1ThreadLocalData::dirty_card_queue_index_offset(), + G1ThreadLocalData::dirty_card_queue_buffer_offset(), + runtime, + thread, tmp, tmp2); + __ jmp(done); +} + void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register store_addr, Register new_val, @@ -273,74 +341,125 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, assert(thread == r15_thread, "must be"); #endif // _LP64 - Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); - Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); - - CardTableBarrierSet* ct = - barrier_set_cast(BarrierSet::barrier_set()); - Label done; Label runtime; - // Does store cross heap regions? - - __ movptr(tmp, store_addr); - __ xorptr(tmp, new_val); - __ shrptr(tmp, G1HeapRegion::LogOfHRGrainBytes); + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp, tmp2, done, true /* new_val_may_be_null */); + // If card is young, jump to done __ jcc(Assembler::equal, done); + generate_post_barrier_slow_path(masm, thread, tmp, tmp2, done, runtime); - // crosses regions, storing null? + __ bind(runtime); + // save the live input values + RegSet saved = RegSet::of(store_addr NOT_LP64(COMMA thread)); + __ push_set(saved); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), tmp, thread); + __ pop_set(saved); - __ cmpptr(new_val, NULL_WORD); - __ jcc(Assembler::equal, done); + __ bind(done); +} - // storing region crossing non-null, is card already dirty? +#if defined(COMPILER2) - const Register card_addr = tmp; - const Register cardtable = tmp2; +static void generate_c2_barrier_runtime_call(MacroAssembler* masm, G1BarrierStubC2* stub, const Register arg, const address runtime_path) { +#ifdef _LP64 + SaveLiveRegisters save_registers(masm, stub); + if (c_rarg0 != arg) { + __ mov(c_rarg0, arg); + } + __ mov(c_rarg1, r15_thread); + // rax is a caller-saved, non-argument-passing register, so it does not + // interfere with c_rarg0 or c_rarg1. If it contained any live value before + // entering this stub, it is saved at this point, and restored after the + // call. If it did not contain any live value, it is free to be used. In + // either case, it is safe to use it here as a call scratch register. + __ call(RuntimeAddress(runtime_path), rax); +#else + Unimplemented(); +#endif // _LP64 +} - __ movptr(card_addr, store_addr); - __ shrptr(card_addr, CardTable::card_shift()); - // Do not use ExternalAddress to load 'byte_map_base', since 'byte_map_base' is NOT - // a valid address and therefore is not properly handled by the relocation code. - __ movptr(cardtable, (intptr_t)ct->card_table()->byte_map_base()); - __ addptr(card_addr, cardtable); +void G1BarrierSetAssembler::g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp, + G1PreBarrierStubC2* stub) { +#ifdef _LP64 + assert(thread == r15_thread, "must be"); +#endif // _LP64 + assert(pre_val != noreg, "check this code"); + if (obj != noreg) { + assert_different_registers(obj, pre_val, tmp); + } - __ cmpb(Address(card_addr, 0), G1CardTable::g1_young_card_val()); - __ jcc(Assembler::equal, done); + stub->initialize_registers(obj, pre_val, thread, tmp); - __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad)); - __ cmpb(Address(card_addr, 0), G1CardTable::dirty_card_val()); - __ jcc(Assembler::equal, done); + generate_pre_barrier_fast_path(masm, thread); + // If marking is active (*(mark queue active address) != 0), jump to stub (slow path) + __ jcc(Assembler::notEqual, *stub->entry()); + __ bind(*stub->continuation()); +} - // storing a region crossing, non-null oop, card is clean. - // dirty card and log. +void G1BarrierSetAssembler::generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register obj = stub->obj(); + Register pre_val = stub->pre_val(); + Register thread = stub->thread(); + Register tmp = stub->tmp1(); + assert(stub->tmp2() == noreg, "not needed in this platform"); - __ movb(Address(card_addr, 0), G1CardTable::dirty_card_val()); + __ bind(*stub->entry()); + generate_pre_barrier_slow_path(masm, obj, pre_val, thread, tmp, *stub->continuation(), runtime); - // The code below assumes that buffer index is pointer sized. - STATIC_ASSERT(in_bytes(G1DirtyCardQueue::byte_width_of_index()) == sizeof(intptr_t)); + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, pre_val, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry)); + __ jmp(*stub->continuation()); +} - __ movptr(tmp2, queue_index); - __ testptr(tmp2, tmp2); - __ jcc(Assembler::zero, runtime); - __ subptr(tmp2, wordSize); - __ movptr(queue_index, tmp2); - __ addptr(tmp2, buffer); - __ movptr(Address(tmp2, 0), card_addr); - __ jmp(done); +void G1BarrierSetAssembler::g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp, + Register tmp2, + G1PostBarrierStubC2* stub) { +#ifdef _LP64 + assert(thread == r15_thread, "must be"); +#endif // _LP64 - __ bind(runtime); - // save the live input values - RegSet saved = RegSet::of(store_addr NOT_LP64(COMMA thread)); - __ push_set(saved); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); - __ pop_set(saved); + stub->initialize_registers(thread, tmp, tmp2); - __ bind(done); + bool new_val_may_be_null = (stub->barrier_data() & G1C2BarrierPostNotNull) == 0; + generate_post_barrier_fast_path(masm, store_addr, new_val, tmp, tmp2, *stub->continuation(), new_val_may_be_null); + // If card is not young, jump to stub (slow path) + __ jcc(Assembler::notEqual, *stub->entry()); + + __ bind(*stub->continuation()); +} + +void G1BarrierSetAssembler::generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + Label runtime; + Register thread = stub->thread(); + Register tmp = stub->tmp1(); // tmp holds the card address. + Register tmp2 = stub->tmp2(); + assert(stub->tmp3() == noreg, "not needed in this platform"); + + __ bind(*stub->entry()); + generate_post_barrier_slow_path(masm, thread, tmp, tmp2, *stub->continuation(), runtime); + + __ bind(runtime); + generate_c2_barrier_runtime_call(masm, stub, tmp, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)); + __ jmp(*stub->continuation()); } +#endif // COMPILER2 + void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { bool in_heap = (decorators & IN_HEAP) != 0; diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp index a5695f5657a4a..4dbb1efd885ea 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp @@ -32,6 +32,9 @@ class LIR_Assembler; class StubAssembler; class G1PreBarrierStub; class G1PostBarrierStub; +class G1BarrierStubC2; +class G1PreBarrierStubC2; +class G1PostBarrierStubC2; class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { protected: @@ -65,6 +68,26 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp_thread); + +#ifdef COMPILER2 + void g1_write_barrier_pre_c2(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp, + G1PreBarrierStubC2* c2_stub); + void generate_c2_pre_barrier_stub(MacroAssembler* masm, + G1PreBarrierStubC2* stub) const; + void g1_write_barrier_post_c2(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp, + Register tmp2, + G1PostBarrierStubC2* c2_stub); + void generate_c2_post_barrier_stub(MacroAssembler* masm, + G1PostBarrierStubC2* stub) const; +#endif // COMPILER2 }; #endif // CPU_X86_GC_G1_G1BARRIERSETASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad new file mode 100644 index 0000000000000..8c1559f90f46d --- /dev/null +++ b/src/hotspot/cpu/x86/gc/g1/g1_x86_64.ad @@ -0,0 +1,371 @@ +// +// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +// +// This code is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License version 2 only, as +// published by the Free Software Foundation. +// +// This code is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// version 2 for more details (a copy is included in the LICENSE file that +// accompanied this code). +// +// You should have received a copy of the GNU General Public License version +// 2 along with this work; if not, write to the Free Software Foundation, +// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +// or visit www.oracle.com if you need additional information or have any +// questions. +// + +source_hpp %{ + +#include "gc/g1/c2/g1BarrierSetC2.hpp" +#include "gc/shared/gc_globals.hpp" + +%} + +source %{ + +#include "gc/g1/g1BarrierSetAssembler_x86.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" + +static void write_barrier_pre(MacroAssembler* masm, + const MachNode* node, + Register obj, + Register pre_val, + Register tmp, + RegSet preserve = RegSet(), + RegSet no_preserve = RegSet()) { + if (!G1PreBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PreBarrierStubC2* const stub = G1PreBarrierStubC2::create(node); + for (RegSetIterator reg = preserve.begin(); *reg != noreg; ++reg) { + stub->preserve(*reg); + } + for (RegSetIterator reg = no_preserve.begin(); *reg != noreg; ++reg) { + stub->dont_preserve(*reg); + } + g1_asm->g1_write_barrier_pre_c2(masm, obj, pre_val, r15_thread, tmp, stub); +} + +static void write_barrier_post(MacroAssembler* masm, + const MachNode* node, + Register store_addr, + Register new_val, + Register tmp1, + Register tmp2) { + if (!G1PostBarrierStubC2::needs_barrier(node)) { + return; + } + Assembler::InlineSkippedInstructionsCounter skip_counter(masm); + G1BarrierSetAssembler* g1_asm = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + G1PostBarrierStubC2* const stub = G1PostBarrierStubC2::create(node); + g1_asm->g1_write_barrier_post_c2(masm, store_addr, new_val, r15_thread, tmp1, tmp2, stub); +} + +%} + +instruct g1StoreP(memory mem, any_RegP src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreP mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(125); // XXX + format %{ "movq $mem, $src\t# ptr" %} + ins_encode %{ + // Materialize the store address internally (as opposed to defining 'mem' as + // an indirect memory operand) to reduce the overhead of LCM when processing + // large basic blocks with many stores. Such basic blocks arise, for + // instance, from static initializations of large String arrays. + // The same holds for g1StoreN and g1EncodePAndStoreN. + __ lea($tmp1$$Register, $mem$$Address); + write_barrier_pre(masm, this, + $tmp1$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); + __ movq(Address($tmp1$$Register, 0), $src$$Register); + write_barrier_post(masm, this, + $tmp1$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp3$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct g1StoreN(memory mem, rRegN src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem src)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(125); // XXX + format %{ "movl $mem, $src\t# ptr" %} + ins_encode %{ + __ lea($tmp1$$Register, $mem$$Address); + write_barrier_pre(masm, this, + $tmp1$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); + __ movl(Address($tmp1$$Register, 0), $src$$Register); + if ((barrier_data() & G1C2BarrierPost) != 0) { + __ movl($tmp2$$Register, $src$$Register); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ decode_heap_oop($tmp2$$Register); + } else { + __ decode_heap_oop_not_null($tmp2$$Register); + } + } + write_barrier_post(masm, this, + $tmp1$$Register /* store_addr */, + $tmp2$$Register /* new_val */, + $tmp3$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct g1EncodePAndStoreN(memory mem, any_RegP src, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Store()->barrier_data() != 0); + match(Set mem (StoreN mem (EncodeP src))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + ins_cost(125); // XXX + format %{ "encode_heap_oop $src\n\t" + "movl $mem, $src\t# ptr" %} + ins_encode %{ + __ lea($tmp1$$Register, $mem$$Address); + write_barrier_pre(masm, this, + $tmp1$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($tmp1$$Register, $src$$Register) /* preserve */); + __ movq($tmp2$$Register, $src$$Register); + if ((barrier_data() & G1C2BarrierPostNotNull) == 0) { + __ encode_heap_oop($tmp2$$Register); + } else { + __ encode_heap_oop_not_null($tmp2$$Register); + } + __ movl(Address($tmp1$$Register, 0), $tmp2$$Register); + write_barrier_post(masm, this, + $tmp1$$Register /* store_addr */, + $src$$Register /* new_val */, + $tmp3$$Register /* tmp1 */, + $tmp2$$Register /* tmp2 */); + %} + ins_pipe(ialu_mem_reg); +%} + +instruct g1CompareAndExchangeP(indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set oldval (CompareAndExchangeP mem (Binary oldval newval))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + format %{ "lock\n\t" + "cmpxchgq $newval, $mem" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + // Pass $oldval to the pre-barrier (instead of loading from $mem), because + // $oldval is the only value that can be overwritten. + // The same holds for g1CompareAndSwapP. + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */); + __ movq($tmp1$$Register, $newval$$Register); + __ lock(); + __ cmpxchgq($tmp1$$Register, Address($mem$$Register, 0)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1CompareAndExchangeN(indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set oldval (CompareAndExchangeN mem (Binary oldval newval))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + format %{ "lock\n\t" + "cmpxchgq $newval, $mem" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */); + __ movl($tmp1$$Register, $newval$$Register); + __ lock(); + __ cmpxchgl($tmp1$$Register, Address($mem$$Register, 0)); + __ decode_heap_oop($tmp1$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1CompareAndSwapP(rRegI res, indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegP oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL oldval, KILL cr); + format %{ "lock\n\t" + "cmpxchgq $newval, $mem\n\t" + "sete $res\n\t" + "movzbl $res, $res" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $oldval$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ movq($tmp1$$Register, $newval$$Register); + __ lock(); + __ cmpxchgq($tmp1$$Register, Address($mem$$Register, 0)); + __ setb(Assembler::equal, $res$$Register); + __ movzbl($res$$Register, $res$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1CompareAndSwapN(rRegI res, indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rax_RegN oldval, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + effect(TEMP res, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL oldval, KILL cr); + format %{ "lock\n\t" + "cmpxchgq $newval, $mem\n\t" + "sete $res\n\t" + "movzbl $res, $res" %} + ins_encode %{ + assert_different_registers($oldval$$Register, $mem$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register, $oldval$$Register) /* preserve */, + RegSet::of($res$$Register) /* no_preserve */); + __ movl($tmp1$$Register, $newval$$Register); + __ lock(); + __ cmpxchgl($tmp1$$Register, Address($mem$$Register, 0)); + __ setb(Assembler::equal, $res$$Register); + __ movzbl($res$$Register, $res$$Register); + __ decode_heap_oop($tmp1$$Register); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1GetAndSetP(indirect mem, rRegP newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set newval (GetAndSetP mem newval)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + format %{ "xchgq $newval, $mem" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + __ movq($tmp1$$Register, $newval$$Register); + __ xchgq($newval$$Register, Address($mem$$Register, 0)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1GetAndSetN(indirect mem, rRegN newval, rRegP tmp1, rRegP tmp2, rRegP tmp3, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_LoadStore()->barrier_data() != 0); + match(Set newval (GetAndSetN mem newval)); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + format %{ "xchgq $newval, $mem" %} + ins_encode %{ + assert_different_registers($mem$$Register, $newval$$Register); + write_barrier_pre(masm, this, + $mem$$Register /* obj */, + $tmp2$$Register /* pre_val */, + $tmp3$$Register /* tmp */, + RegSet::of($mem$$Register, $newval$$Register) /* preserve */); + __ movl($tmp1$$Register, $newval$$Register); + __ decode_heap_oop($tmp1$$Register); + __ xchgl($newval$$Register, Address($mem$$Register, 0)); + write_barrier_post(masm, this, + $mem$$Register /* store_addr */, + $tmp1$$Register /* new_val */, + $tmp2$$Register /* tmp1 */, + $tmp3$$Register /* tmp2 */); + %} + ins_pipe(pipe_cmpxchg); +%} + +instruct g1LoadP(rRegP dst, memory mem, rRegP tmp, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadP mem)); + effect(TEMP dst, TEMP tmp, KILL cr); + ins_cost(125); // XXX + format %{ "movq $dst, $mem\t# ptr" %} + ins_encode %{ + __ movq($dst$$Register, $mem$$Address); + write_barrier_pre(masm, this, + noreg /* obj */, + $dst$$Register /* pre_val */, + $tmp$$Register /* tmp */); + %} + ins_pipe(ialu_reg_mem); // XXX +%} + +instruct g1LoadN(rRegN dst, memory mem, rRegP tmp1, rRegP tmp2, rFlagsReg cr) +%{ + predicate(UseG1GC && n->as_Load()->barrier_data() != 0); + match(Set dst (LoadN mem)); + effect(TEMP dst, TEMP tmp1, TEMP tmp2, KILL cr); + ins_cost(125); // XXX + format %{ "movl $dst, $mem\t# compressed ptr" %} + ins_encode %{ + __ movl($dst$$Register, $mem$$Address); + __ movl($tmp1$$Register, $dst$$Register); + __ decode_heap_oop($tmp1$$Register); + write_barrier_pre(masm, this, + noreg /* obj */, + $tmp1$$Register /* pre_val */, + $tmp2$$Register /* tmp */); + %} + ins_pipe(ialu_reg_mem); // XXX +%} diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 2b29dd14e4b27..b55a1208cf2df 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -2457,6 +2457,10 @@ bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { mstack.push(m, Visit); // m = ShiftCntV return true; } + if (is_encode_and_store_pattern(n, m)) { + mstack.push(m, Visit); + return true; + } return false; } diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 1b271683bd60d..fee265473befe 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -4341,6 +4341,7 @@ instruct loadP(rRegP dst, memory mem) // Load Compressed Pointer instruct loadN(rRegN dst, memory mem) %{ + predicate(n->as_Load()->barrier_data() == 0); match(Set dst (LoadN mem)); ins_cost(125); // XXX @@ -5126,6 +5127,7 @@ instruct storeImmP(memory mem, immP31 src) // Store Compressed Pointer instruct storeN(memory mem, rRegN src) %{ + predicate(n->as_Store()->barrier_data() == 0); match(Set mem (StoreN mem src)); ins_cost(125); // XXX @@ -5150,7 +5152,7 @@ instruct storeNKlass(memory mem, rRegN src) instruct storeImmN0(memory mem, immN0 zero) %{ - predicate(CompressedOops::base() == nullptr); + predicate(CompressedOops::base() == nullptr && n->as_Store()->barrier_data() == 0); match(Set mem (StoreN mem zero)); ins_cost(125); // XXX @@ -5163,6 +5165,7 @@ instruct storeImmN0(memory mem, immN0 zero) instruct storeImmN(memory mem, immN src) %{ + predicate(n->as_Store()->barrier_data() == 0); match(Set mem (StoreN mem src)); ins_cost(150); // XXX @@ -7162,6 +7165,7 @@ instruct compareAndSwapN(rRegI res, memory mem_ptr, rax_RegN oldval, rRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); @@ -7249,6 +7253,7 @@ instruct compareAndExchangeN( memory mem_ptr, rax_RegN oldval, rRegN newval, rFlagsReg cr) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set oldval (CompareAndExchangeN mem_ptr (Binary oldval newval))); effect(KILL cr); @@ -7470,6 +7475,7 @@ instruct xchgP( memory mem, rRegP newval) %{ %} instruct xchgN( memory mem, rRegN newval) %{ + predicate(n->as_LoadStore()->barrier_data() == 0); match(Set newval (GetAndSetN mem newval)); format %{ "XCHGL $newval,$mem]" %} ins_encode %{ @@ -11659,6 +11665,7 @@ instruct compN_rReg(rFlagsRegU cr, rRegN op1, rRegN op2) instruct compN_rReg_mem(rFlagsRegU cr, rRegN src, memory mem) %{ + predicate(n->in(2)->as_Load()->barrier_data() == 0); match(Set cr (CmpN src (LoadN mem))); format %{ "cmpl $src, $mem\t# compressed ptr" %} @@ -11680,6 +11687,7 @@ instruct compN_rReg_imm(rFlagsRegU cr, rRegN op1, immN op2) %{ instruct compN_mem_imm(rFlagsRegU cr, memory mem, immN src) %{ + predicate(n->in(2)->as_Load()->barrier_data() == 0); match(Set cr (CmpN src (LoadN mem))); format %{ "cmpl $mem, $src\t# compressed ptr" %} @@ -11720,7 +11728,8 @@ instruct testN_reg(rFlagsReg cr, rRegN src, immN0 zero) %{ instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) %{ - predicate(CompressedOops::base() != nullptr); + predicate(CompressedOops::base() != nullptr && + n->in(1)->as_Load()->barrier_data() == 0); match(Set cr (CmpN (LoadN mem) zero)); ins_cost(500); // XXX @@ -11733,7 +11742,8 @@ instruct testN_mem(rFlagsReg cr, memory mem, immN0 zero) instruct testN_mem_reg0(rFlagsReg cr, memory mem, immN0 zero) %{ - predicate(CompressedOops::base() == nullptr); + predicate(CompressedOops::base() == nullptr && + n->in(1)->as_Load()->barrier_data() == 0); match(Set cr (CmpN (LoadN mem) zero)); format %{ "cmpl R12, $mem\t# compressed ptr (R12_heapbase==0)" %} diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 13b993546cde4..8e17d1d2a7a4e 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -24,49 +24,32 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" +#include "code/vmreg.inline.hpp" #include "gc/g1/c2/g1BarrierSetC2.hpp" #include "gc/g1/g1BarrierSet.hpp" +#include "gc/g1/g1BarrierSetAssembler.hpp" #include "gc/g1/g1BarrierSetRuntime.hpp" #include "gc/g1/g1CardTable.hpp" #include "gc/g1/g1ThreadLocalData.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "opto/arraycopynode.hpp" +#include "opto/block.hpp" #include "opto/compile.hpp" #include "opto/escape.hpp" #include "opto/graphKit.hpp" #include "opto/idealKit.hpp" +#include "opto/machnode.hpp" #include "opto/macro.hpp" +#include "opto/memnode.hpp" +#include "opto/node.hpp" +#include "opto/output.hpp" +#include "opto/regalloc.hpp" #include "opto/rootnode.hpp" +#include "opto/runtime.hpp" #include "opto/type.hpp" +#include "utilities/growableArray.hpp" #include "utilities/macros.hpp" -const TypeFunc *G1BarrierSetC2::write_ref_field_pre_entry_Type() { - const Type **fields = TypeTuple::fields(2); - fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value - fields[TypeFunc::Parms+1] = TypeRawPtr::NOTNULL; // thread - const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields); - - // create result type (range) - fields = TypeTuple::fields(0); - const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields); - - return TypeFunc::make(domain, range); -} - -const TypeFunc *G1BarrierSetC2::write_ref_field_post_entry_Type() { - const Type **fields = TypeTuple::fields(2); - fields[TypeFunc::Parms+0] = TypeRawPtr::NOTNULL; // Card addr - fields[TypeFunc::Parms+1] = TypeRawPtr::NOTNULL; // thread - const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields); - - // create result type (range) - fields = TypeTuple::fields(0); - const TypeTuple *range = TypeTuple::make(TypeFunc::Parms, fields); - - return TypeFunc::make(domain, range); -} - -#define __ ideal. /* * Determine if the G1 pre-barrier can be removed. The pre-barrier is * required by SATB to make sure all objects live at the start of the @@ -84,8 +67,6 @@ const TypeFunc *G1BarrierSetC2::write_ref_field_post_entry_Type() { * The compiler needs to determine that the object in which a field is about * to be written is newly allocated, and that no prior store to the same field * has happened since the allocation. - * - * Returns true if the pre-barrier can be removed */ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, PhaseValues* phase, @@ -97,34 +78,28 @@ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, AllocateNode* alloc = AllocateNode::Ideal_allocation(base); if (offset == Type::OffsetBot) { - return false; // cannot unalias unless there are precise offsets + return false; // Cannot unalias unless there are precise offsets. } - if (alloc == nullptr) { - return false; // No allocation found + return false; // No allocation found. } intptr_t size_in_bytes = type2aelembytes(bt); - - Node* mem = kit->memory(adr_idx); // start searching here... + Node* mem = kit->memory(adr_idx); // Start searching here. for (int cnt = 0; cnt < 50; cnt++) { - if (mem->is_Store()) { - Node* st_adr = mem->in(MemNode::Address); intptr_t st_offset = 0; Node* st_base = AddPNode::Ideal_base_and_offset(st_adr, phase, st_offset); if (st_base == nullptr) { - break; // inscrutable pointer + break; // Inscrutable pointer. } - - // Break we have found a store with same base and offset as ours so break if (st_base == base && st_offset == offset) { + // We have found a store with same base and offset as ours. break; } - if (st_offset != offset && st_offset != Type::OffsetBot) { const int MAX_STORE = BytesPerLong; if (st_offset >= offset + size_in_bytes || @@ -136,20 +111,18 @@ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, // in the same sequence of RawMem effects. We sometimes initialize // a whole 'tile' of array elements with a single jint or jlong.) mem = mem->in(MemNode::Memory); - continue; // advance through independent store memory + continue; // Advance through independent store memory. } } - if (st_base != base && MemNode::detect_ptr_independence(base, alloc, st_base, AllocateNode::Ideal_allocation(st_base), phase)) { - // Success: The bases are provably independent. + // Success: the bases are provably independent. mem = mem->in(MemNode::Memory); - continue; // advance through independent store memory + continue; // Advance through independent store memory. } } else if (mem->is_Proj() && mem->in(0)->is_Initialize()) { - InitializeNode* st_init = mem->in(0)->as_Initialize(); AllocateNode* st_alloc = st_init->allocation(); @@ -157,7 +130,7 @@ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, // The alloc variable is guaranteed to not be null here from earlier check. if (alloc == st_alloc) { // Check that the initialization is storing null so that no previous store - // has been moved up and directly write a reference + // has been moved up and directly write a reference. Node* captured_store = st_init->find_captured_store(offset, type2aelembytes(T_OBJECT), phase); @@ -166,164 +139,55 @@ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, } } } - // Unless there is an explicit 'continue', we must bail out here, // because 'mem' is an inscrutable memory state (e.g., a call). break; } - return false; } -// G1 pre/post barriers -void G1BarrierSetC2::pre_barrier(GraphKit* kit, - bool do_load, - Node* ctl, - Node* obj, - Node* adr, - uint alias_idx, - Node* val, - const TypeOopPtr* val_type, - Node* pre_val, - BasicType bt) const { - // Some sanity checks - // Note: val is unused in this routine. - - if (do_load) { - // We need to generate the load of the previous value - assert(obj != nullptr, "must have a base"); - assert(adr != nullptr, "where are loading from?"); - assert(pre_val == nullptr, "loaded already?"); - assert(val_type != nullptr, "need a type"); - - if (use_ReduceInitialCardMarks() - && g1_can_remove_pre_barrier(kit, &kit->gvn(), adr, bt, alias_idx)) { - return; - } - - } else { - // In this case both val_type and alias_idx are unused. - assert(pre_val != nullptr, "must be loaded already"); - // Nothing to be done if pre_val is null. - if (pre_val->bottom_type() == TypePtr::NULL_PTR) return; - assert(pre_val->bottom_type()->basic_type() == T_OBJECT, "or we shouldn't be here"); - } - assert(bt == T_OBJECT, "or we shouldn't be here"); - - IdealKit ideal(kit, true); - - Node* tls = __ thread(); // ThreadLocalStorage - - Node* no_base = __ top(); - Node* zero = __ ConI(0); - Node* zeroX = __ ConX(0); - - float likely = PROB_LIKELY(0.999); - float unlikely = PROB_UNLIKELY(0.999); - - BasicType active_type = in_bytes(SATBMarkQueue::byte_width_of_active()) == 4 ? T_INT : T_BYTE; - assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 4 || in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "flag width"); - - // Offsets into the thread - const int marking_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - const int index_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()); - const int buffer_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - - // Now the actual pointers into the thread - Node* marking_adr = __ AddP(no_base, tls, __ ConX(marking_offset)); - Node* buffer_adr = __ AddP(no_base, tls, __ ConX(buffer_offset)); - Node* index_adr = __ AddP(no_base, tls, __ ConX(index_offset)); - - // Now some of the values - Node* marking = __ load(__ ctrl(), marking_adr, TypeInt::INT, active_type, Compile::AliasIdxRaw); - - // if (!marking) - __ if_then(marking, BoolTest::ne, zero, unlikely); { - BasicType index_bt = TypeX_X->basic_type(); - assert(sizeof(size_t) == type2aelembytes(index_bt), "Loading G1 SATBMarkQueue::_index with wrong size."); - Node* index = __ load(__ ctrl(), index_adr, TypeX_X, index_bt, Compile::AliasIdxRaw); - - if (do_load) { - // load original value - pre_val = __ load(__ ctrl(), adr, val_type, bt, alias_idx, false, MemNode::unordered, LoadNode::Pinned); - } - - // if (pre_val != nullptr) - __ if_then(pre_val, BoolTest::ne, kit->null()); { - Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw); - - // is the queue for this thread full? - __ if_then(index, BoolTest::ne, zeroX, likely); { - - // decrement the index - Node* next_index = kit->gvn().transform(new SubXNode(index, __ ConX(sizeof(intptr_t)))); - - // Now get the buffer location we will log the previous value into and store it - Node *log_addr = __ AddP(no_base, buffer, next_index); - __ store(__ ctrl(), log_addr, pre_val, T_OBJECT, Compile::AliasIdxRaw, MemNode::unordered); - // update the index - __ store(__ ctrl(), index_adr, next_index, index_bt, Compile::AliasIdxRaw, MemNode::unordered); - - } __ else_(); { - - // logging buffer is full, call the runtime - const TypeFunc *tf = write_ref_field_pre_entry_Type(); - __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), "write_ref_field_pre_entry", pre_val, tls); - } __ end_if(); // (!index) - } __ end_if(); // (pre_val != nullptr) - } __ end_if(); // (!marking) - - // Final sync IdealKit and GraphKit. - kit->final_sync(ideal); -} - /* - * G1 similar to any GC with a Young Generation requires a way to keep track of - * references from Old Generation to Young Generation to make sure all live + * G1, similar to any GC with a Young Generation, requires a way to keep track + * of references from Old Generation to Young Generation to make sure all live * objects are found. G1 also requires to keep track of object references * between different regions to enable evacuation of old regions, which is done - * as part of mixed collections. References are tracked in remembered sets and - * is continuously updated as reference are written to with the help of the - * post-barrier. + * as part of mixed collections. References are tracked in remembered sets, + * which are continuously updated as references are written to with the help of + * the post-barrier. * - * To reduce the number of updates to the remembered set the post-barrier - * filters updates to fields in objects located in the Young Generation, - * the same region as the reference, when the null is being written or - * if the card is already marked as dirty by an earlier write. + * To reduce the number of updates to the remembered set, the post-barrier + * filters out updates to fields in objects located in the Young Generation, the + * same region as the reference, when null is being written, or if the card is + * already marked as dirty by an earlier write. * * Under certain circumstances it is possible to avoid generating the - * post-barrier completely if it is possible during compile time to prove - * the object is newly allocated and that no safepoint exists between the - * allocation and the store. - * - * In the case of slow allocation the allocation code must handle the barrier - * as part of the allocation in the case the allocated object is not located - * in the nursery; this would happen for humongous objects. + * post-barrier completely, if it is possible during compile time to prove the + * object is newly allocated and that no safepoint exists between the allocation + * and the store. This can be seen as a compile-time version of the + * above-mentioned Young Generation filter. * - * Returns true if the post barrier can be removed + * In the case of a slow allocation, the allocation code must handle the barrier + * as part of the allocation if the allocated object is not located in the + * nursery; this would happen for humongous objects. */ bool G1BarrierSetC2::g1_can_remove_post_barrier(GraphKit* kit, - PhaseValues* phase, Node* store, + PhaseValues* phase, Node* store_ctrl, Node* adr) const { intptr_t offset = 0; Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset); AllocateNode* alloc = AllocateNode::Ideal_allocation(base); if (offset == Type::OffsetBot) { - return false; // cannot unalias unless there are precise offsets + return false; // Cannot unalias unless there are precise offsets. } - if (alloc == nullptr) { - return false; // No allocation found + return false; // No allocation found. } - // Start search from Store node - Node* mem = store->in(MemNode::Control); + Node* mem = store_ctrl; // Start search from Store node. if (mem->is_Proj() && mem->in(0)->is_Initialize()) { - InitializeNode* st_init = mem->in(0)->as_Initialize(); AllocateNode* st_alloc = st_init->allocation(); - // Make sure we are looking at the same allocation if (alloc == st_alloc) { return true; @@ -333,725 +197,361 @@ bool G1BarrierSetC2::g1_can_remove_post_barrier(GraphKit* kit, return false; } -// -// Update the card table and add card address to the queue -// -void G1BarrierSetC2::g1_mark_card(GraphKit* kit, - IdealKit& ideal, - Node* card_adr, - Node* oop_store, - uint oop_alias_idx, - Node* index, - Node* index_adr, - Node* buffer, - const TypeFunc* tf) const { - Node* zero = __ ConI(0); - Node* zeroX = __ ConX(0); - Node* no_base = __ top(); - BasicType card_bt = T_BYTE; - // Smash zero into card. MUST BE ORDERED WRT TO STORE - __ storeCM(__ ctrl(), card_adr, zero, oop_store, oop_alias_idx, card_bt, Compile::AliasIdxRaw); - - // Now do the queue work - __ if_then(index, BoolTest::ne, zeroX); { - - Node* next_index = kit->gvn().transform(new SubXNode(index, __ ConX(sizeof(intptr_t)))); - Node* log_addr = __ AddP(no_base, buffer, next_index); - - // Order, see storeCM. - __ store(__ ctrl(), log_addr, card_adr, T_ADDRESS, Compile::AliasIdxRaw, MemNode::unordered); - __ store(__ ctrl(), index_adr, next_index, TypeX_X->basic_type(), Compile::AliasIdxRaw, MemNode::unordered); - - } __ else_(); { - __ make_leaf_call(tf, CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), "write_ref_field_post_entry", card_adr, __ thread()); - } __ end_if(); - +Node* G1BarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const { + DecoratorSet decorators = access.decorators(); + bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; + bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; + bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0; + // If we are reading the value of the referent field of a Reference object, we + // need to record the referent in an SATB log buffer using the pre-barrier + // mechanism. Also we need to add a memory barrier to prevent commoning reads + // from this field across safepoints, since GC can change its value. + bool need_read_barrier = ((on_weak || on_phantom) && !no_keepalive); + if (access.is_oop() && need_read_barrier) { + access.set_barrier_data(G1C2BarrierPre); + } + return CardTableBarrierSetC2::load_at_resolved(access, val_type); } -void G1BarrierSetC2::post_barrier(GraphKit* kit, - Node* ctl, - Node* oop_store, - Node* obj, - Node* adr, - uint alias_idx, - Node* val, - BasicType bt, - bool use_precise) const { - // If we are writing a null then we need no post barrier +void G1BarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const { + eliminate_gc_barrier_data(node); +} - if (val != nullptr && val->is_Con() && val->bottom_type() == TypePtr::NULL_PTR) { - // Must be null - const Type* t = val->bottom_type(); - assert(t == Type::TOP || t == TypePtr::NULL_PTR, "must be null"); - // No post barrier if writing null - return; +void G1BarrierSetC2::eliminate_gc_barrier_data(Node* node) const { + if (node->is_LoadStore()) { + LoadStoreNode* loadstore = node->as_LoadStore(); + loadstore->set_barrier_data(0); + } else if (node->is_Mem()) { + MemNode* mem = node->as_Mem(); + mem->set_barrier_data(0); } +} - if (use_ReduceInitialCardMarks() && obj == kit->just_allocated_object(kit->control())) { - // We can skip marks on a freshly-allocated object in Eden. - // Keep this code in sync with CardTableBarrierSet::on_slowpath_allocation_exit. - // That routine informs GC to take appropriate compensating steps, - // upon a slow-path allocation, so as to make this card-mark - // elision safe. +static void refine_barrier_by_new_val_type(const Node* n) { + if (n->Opcode() != Op_StoreP && + n->Opcode() != Op_StoreN) { return; } - - if (use_ReduceInitialCardMarks() - && g1_can_remove_post_barrier(kit, &kit->gvn(), oop_store, adr)) { + MemNode* store = n->as_Mem(); + const Node* newval = n->in(MemNode::ValueIn); + assert(newval != nullptr, ""); + const Type* newval_bottom = newval->bottom_type(); + TypePtr::PTR newval_type = newval_bottom->make_ptr()->ptr(); + uint8_t barrier_data = store->barrier_data(); + if (!newval_bottom->isa_oopptr() && + !newval_bottom->isa_narrowoop() && + newval_type != TypePtr::Null) { + // newval is neither an OOP nor null, so there is no barrier to refine. + assert(barrier_data == 0, "non-OOP stores should have no barrier data"); return; } - - if (!use_precise) { - // All card marks for a (non-array) instance are in one place: - adr = obj; + if (barrier_data == 0) { + // No barrier to refine. + return; } - // (Else it's an array (or unknown), and we want more precise card marks.) - assert(adr != nullptr, ""); - - IdealKit ideal(kit, true); - - Node* tls = __ thread(); // ThreadLocalStorage - - Node* no_base = __ top(); - float likely = PROB_LIKELY_MAG(3); - float unlikely = PROB_UNLIKELY_MAG(3); - Node* young_card = __ ConI((jint)G1CardTable::g1_young_card_val()); - Node* dirty_card = __ ConI((jint)G1CardTable::dirty_card_val()); - Node* zeroX = __ ConX(0); - - const TypeFunc *tf = write_ref_field_post_entry_Type(); - - // Offsets into the thread - const int index_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()); - const int buffer_offset = in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()); - - // Pointers into the thread - - Node* buffer_adr = __ AddP(no_base, tls, __ ConX(buffer_offset)); - Node* index_adr = __ AddP(no_base, tls, __ ConX(index_offset)); - - // Now some values - // Use ctrl to avoid hoisting these values past a safepoint, which could - // potentially reset these fields in the JavaThread. - Node* index = __ load(__ ctrl(), index_adr, TypeX_X, TypeX_X->basic_type(), Compile::AliasIdxRaw); - Node* buffer = __ load(__ ctrl(), buffer_adr, TypeRawPtr::NOTNULL, T_ADDRESS, Compile::AliasIdxRaw); - - // Convert the store obj pointer to an int prior to doing math on it - // Must use ctrl to prevent "integerized oop" existing across safepoint - Node* cast = __ CastPX(__ ctrl(), adr); - - // Divide pointer by card size - Node* card_offset = __ URShiftX( cast, __ ConI(CardTable::card_shift()) ); - - // Combine card table base and card offset - Node* card_adr = __ AddP(no_base, byte_map_base_node(kit), card_offset ); - - // If we know the value being stored does it cross regions? - - if (val != nullptr) { - // Does the store cause us to cross regions? - - // Should be able to do an unsigned compare of region_size instead of - // and extra shift. Do we have an unsigned compare?? - // Node* region_size = __ ConI(1 << G1HeapRegion::LogOfHRGrainBytes); - Node* xor_res = __ URShiftX ( __ XorX( cast, __ CastPX(__ ctrl(), val)), __ ConI(checked_cast(G1HeapRegion::LogOfHRGrainBytes))); - - // if (xor_res == 0) same region so skip - __ if_then(xor_res, BoolTest::ne, zeroX, likely); { - - // No barrier if we are storing a null. - __ if_then(val, BoolTest::ne, kit->null(), likely); { - - // Ok must mark the card if not already dirty - - // load the original value of the card - Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); - - __ if_then(card_val, BoolTest::ne, young_card, unlikely); { - kit->sync_kit(ideal); - kit->insert_mem_bar(Op_MemBarVolatile, oop_store); - __ sync_kit(kit); - - Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); - __ if_then(card_val_reload, BoolTest::ne, dirty_card); { - g1_mark_card(kit, ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); - } __ end_if(); - } __ end_if(); - } __ end_if(); - } __ end_if(); - } else { - // The Object.clone() intrinsic uses this path if !ReduceInitialCardMarks. - // We don't need a barrier here if the destination is a newly allocated object - // in Eden. Otherwise, GC verification breaks because we assume that cards in Eden - // are set to 'g1_young_gen' (see G1CardTable::verify_g1_young_region()). - assert(!use_ReduceInitialCardMarks(), "can only happen with card marking"); - Node* card_val = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); - __ if_then(card_val, BoolTest::ne, young_card); { - g1_mark_card(kit, ideal, card_adr, oop_store, alias_idx, index, index_adr, buffer, tf); - } __ end_if(); + if (newval_type == TypePtr::Null) { + // Simply elide post-barrier if writing null. + barrier_data &= ~G1C2BarrierPost; + barrier_data &= ~G1C2BarrierPostNotNull; + } else if (((barrier_data & G1C2BarrierPost) != 0) && + newval_type == TypePtr::NotNull) { + // If the post-barrier has not been elided yet (e.g. due to newval being + // freshly allocated), mark it as not-null (simplifies barrier tests and + // compressed OOPs logic). + barrier_data |= G1C2BarrierPostNotNull; } - - // Final sync IdealKit and GraphKit. - kit->final_sync(ideal); + store->set_barrier_data(barrier_data); + return; } -// Helper that guards and inserts a pre-barrier. -void G1BarrierSetC2::insert_pre_barrier(GraphKit* kit, Node* base_oop, Node* offset, - Node* pre_val, bool need_mem_bar) const { - // We could be accessing the referent field of a reference object. If so, when G1 - // is enabled, we need to log the value in the referent field in an SATB buffer. - // This routine performs some compile time filters and generates suitable - // runtime filters that guard the pre-barrier code. - // Also add memory barrier for non volatile load from the referent field - // to prevent commoning of loads across safepoint. - - // Some compile time checks. - - // If offset is a constant, is it java_lang_ref_Reference::_reference_offset? - const TypeX* otype = offset->find_intptr_t_type(); - if (otype != nullptr && otype->is_con() && - otype->get_con() != java_lang_ref_Reference::referent_offset()) { - // Constant offset but not the reference_offset so just return - return; - } - - // We only need to generate the runtime guards for instances. - const TypeOopPtr* btype = base_oop->bottom_type()->isa_oopptr(); - if (btype != nullptr) { - if (btype->isa_aryptr()) { - // Array type so nothing to do - return; +// Refine (not really expand) G1 barriers by looking at the new value type +// (whether it is necessarily null or necessarily non-null). +bool G1BarrierSetC2::expand_barriers(Compile* C, PhaseIterGVN& igvn) const { + ResourceMark rm; + VectorSet visited; + Node_List worklist; + worklist.push(C->root()); + while (worklist.size() > 0) { + Node* n = worklist.pop(); + if (visited.test_set(n->_idx)) { + continue; } - - const TypeInstPtr* itype = btype->isa_instptr(); - if (itype != nullptr) { - // Can the klass of base_oop be statically determined to be - // _not_ a sub-class of Reference and _not_ Object? - ciKlass* klass = itype->instance_klass(); - if (klass->is_loaded() && - !klass->is_subtype_of(kit->env()->Reference_klass()) && - !kit->env()->Object_klass()->is_subtype_of(klass)) { - return; + refine_barrier_by_new_val_type(n); + for (uint j = 0; j < n->req(); j++) { + Node* in = n->in(j); + if (in != nullptr) { + worklist.push(in); } } } + return false; +} - // The compile time filters did not reject base_oop/offset so - // we need to generate the following runtime filters - // - // if (offset == java_lang_ref_Reference::_reference_offset) { - // if (instance_of(base, java.lang.ref.Reference)) { - // pre_barrier(_, pre_val, ...); +uint G1BarrierSetC2::estimated_barrier_size(const Node* node) const { + // These Ideal node counts are extracted from the pre-matching Ideal graph + // generated when compiling the following method with early barrier expansion: + // static void write(MyObject obj1, Object o) { + // obj1.o1 = o; // } - // } - - float likely = PROB_LIKELY( 0.999); - float unlikely = PROB_UNLIKELY(0.999); - - IdealKit ideal(kit); - - Node* referent_off = __ ConX(java_lang_ref_Reference::referent_offset()); - - __ if_then(offset, BoolTest::eq, referent_off, unlikely); { - // Update graphKit memory and control from IdealKit. - kit->sync_kit(ideal); - - Node* ref_klass_con = kit->makecon(TypeKlassPtr::make(kit->env()->Reference_klass())); - Node* is_instof = kit->gen_instanceof(base_oop, ref_klass_con); - - // Update IdealKit memory and control from graphKit. - __ sync_kit(kit); - - Node* one = __ ConI(1); - // is_instof == 0 if base_oop == nullptr - __ if_then(is_instof, BoolTest::eq, one, unlikely); { - - // Update graphKit from IdeakKit. - kit->sync_kit(ideal); - - // Use the pre-barrier to record the value in the referent field - pre_barrier(kit, false /* do_load */, - __ ctrl(), - nullptr /* obj */, nullptr /* adr */, max_juint /* alias_idx */, nullptr /* val */, nullptr /* val_type */, - pre_val /* pre_val */, - T_OBJECT); - if (need_mem_bar) { - // Add memory barrier to prevent commoning reads from this field - // across safepoint since GC can change its value. - kit->insert_mem_bar(Op_MemBarCPUOrder); - } - // Update IdealKit from graphKit. - __ sync_kit(kit); - - } __ end_if(); // _ref_type != ref_none - } __ end_if(); // offset == referent_offset + uint8_t barrier_data = MemNode::barrier_data(node); + uint nodes = 0; + if ((barrier_data & G1C2BarrierPre) != 0) { + nodes += 50; + } + if ((barrier_data & G1C2BarrierPost) != 0) { + nodes += 60; + } + return nodes; +} - // Final sync IdealKit and GraphKit. - kit->final_sync(ideal); +bool G1BarrierSetC2::can_initialize_object(const StoreNode* store) const { + assert(store->Opcode() == Op_StoreP || store->Opcode() == Op_StoreN, "OOP store expected"); + // It is OK to move the store across the object initialization boundary only + // if it does not have any barrier, or if it has barriers that can be safely + // elided (because of the compensation steps taken on the allocation slow path + // when ReduceInitialCardMarks is enabled). + return (MemNode::barrier_data(store) == 0) || use_ReduceInitialCardMarks(); } -#undef __ +void G1BarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const { + if (ac->is_clone_inst() && !use_ReduceInitialCardMarks()) { + clone_in_runtime(phase, ac, G1BarrierSetRuntime::clone_addr(), "G1BarrierSetRuntime::clone"); + return; + } + BarrierSetC2::clone_at_expansion(phase, ac); +} -Node* G1BarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const { +Node* G1BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) const { DecoratorSet decorators = access.decorators(); - Node* adr = access.addr().node(); - Node* obj = access.base(); - - bool anonymous = (decorators & C2_UNSAFE_ACCESS) != 0; - bool mismatched = (decorators & C2_MISMATCHED) != 0; - bool unknown = (decorators & ON_UNKNOWN_OOP_REF) != 0; + bool anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; bool in_heap = (decorators & IN_HEAP) != 0; - bool in_native = (decorators & IN_NATIVE) != 0; - bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; - bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; - bool is_unordered = (decorators & MO_UNORDERED) != 0; - bool no_keepalive = (decorators & AS_NO_KEEPALIVE) != 0; - bool is_mixed = !in_heap && !in_native; - bool need_cpu_mem_bar = !is_unordered || mismatched || is_mixed; - - Node* top = Compile::current()->top(); - Node* offset = adr->is_AddP() ? adr->in(AddPNode::Offset) : top; - - // If we are reading the value of the referent field of a Reference - // object (either by using Unsafe directly or through reflection) - // then, if G1 is enabled, we need to record the referent in an - // SATB log buffer using the pre-barrier mechanism. - // Also we need to add memory barrier to prevent commoning reads - // from this field across safepoint since GC can change its value. - bool need_read_barrier = (((on_weak || on_phantom) && !no_keepalive) || - (in_heap && unknown && offset != top && obj != top)); + bool tightly_coupled_alloc = (decorators & C2_TIGHTLY_COUPLED_ALLOC) != 0; + bool need_store_barrier = !(tightly_coupled_alloc && use_ReduceInitialCardMarks()) && (in_heap || anonymous); + if (access.is_oop() && need_store_barrier) { + access.set_barrier_data(get_store_barrier(access)); + if (tightly_coupled_alloc) { + assert(!use_ReduceInitialCardMarks(), + "post-barriers are only needed for tightly-coupled initialization stores when ReduceInitialCardMarks is disabled"); + access.set_barrier_data(access.barrier_data() ^ G1C2BarrierPre); + } + } + return BarrierSetC2::store_at_resolved(access, val); +} - if (!access.is_oop() || !need_read_barrier) { - return CardTableBarrierSetC2::load_at_resolved(access, val_type); +Node* G1BarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val, + Node* new_val, const Type* value_type) const { + GraphKit* kit = access.kit(); + if (!access.is_oop()) { + return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type); } + access.set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); + return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type); +} - assert(access.is_parse_access(), "entry not supported at optimization time"); +Node* G1BarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val, + Node* new_val, const Type* value_type) const { + GraphKit* kit = access.kit(); + if (!access.is_oop()) { + return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type); + } + access.set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); + return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type); +} - C2ParseAccess& parse_access = static_cast(access); - GraphKit* kit = parse_access.kit(); - Node* load; +Node* G1BarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const { + GraphKit* kit = access.kit(); + if (!access.is_oop()) { + return BarrierSetC2::atomic_xchg_at_resolved(access, new_val, value_type); + } + access.set_barrier_data(G1C2BarrierPre | G1C2BarrierPost); + return BarrierSetC2::atomic_xchg_at_resolved(access, new_val, value_type); +} - Node* control = kit->control(); - const TypePtr* adr_type = access.addr().type(); - MemNode::MemOrd mo = access.mem_node_mo(); - bool requires_atomic_access = (decorators & MO_UNORDERED) == 0; - bool unaligned = (decorators & C2_UNALIGNED) != 0; - bool unsafe = (decorators & C2_UNSAFE_ACCESS) != 0; - // Pinned control dependency is the strictest. So it's ok to substitute it for any other. - load = kit->make_load(control, adr, val_type, access.type(), adr_type, mo, - LoadNode::Pinned, requires_atomic_access, unaligned, mismatched, unsafe, - access.barrier_data()); +class G1BarrierSetC2State : public BarrierSetC2State { +private: + GrowableArray* _stubs; +public: + G1BarrierSetC2State(Arena* arena) + : BarrierSetC2State(arena), + _stubs(new (arena) GrowableArray(arena, 8, 0, nullptr)) {} - if (on_weak || on_phantom) { - // Use the pre-barrier to record the value in the referent field - pre_barrier(kit, false /* do_load */, - kit->control(), - nullptr /* obj */, nullptr /* adr */, max_juint /* alias_idx */, nullptr /* val */, nullptr /* val_type */, - load /* pre_val */, T_OBJECT); - // Add memory barrier to prevent commoning reads from this field - // across safepoint since GC can change its value. - kit->insert_mem_bar(Op_MemBarCPUOrder); - } else if (unknown) { - // We do not require a mem bar inside pre_barrier if need_mem_bar - // is set: the barriers would be emitted by us. - insert_pre_barrier(kit, obj, offset, load, !need_cpu_mem_bar); + GrowableArray* stubs() { + return _stubs; } - return load; -} - -bool G1BarrierSetC2::is_gc_barrier_node(Node* node) const { - if (CardTableBarrierSetC2::is_gc_barrier_node(node)) { - return true; + bool needs_liveness_data(const MachNode* mach) const { + return G1PreBarrierStubC2::needs_barrier(mach) || + G1PostBarrierStubC2::needs_barrier(mach); } - if (node->Opcode() != Op_CallLeaf) { - return false; - } - CallLeafNode *call = node->as_CallLeaf(); - if (call->_name == nullptr) { + + bool needs_livein_data() const { return false; } +}; - return strcmp(call->_name, "write_ref_field_pre_entry") == 0 || strcmp(call->_name, "write_ref_field_post_entry") == 0; +static G1BarrierSetC2State* barrier_set_state() { + return reinterpret_cast(Compile::current()->barrier_set_state()); } -bool G1BarrierSetC2::is_g1_pre_val_load(Node* n) { - if (n->is_Load() && n->as_Load()->has_pinned_control_dependency()) { - // Make sure the only users of it are: CmpP, StoreP, and a call to write_ref_field_pre_entry +G1BarrierStubC2::G1BarrierStubC2(const MachNode* node) : BarrierStubC2(node) {} - // Skip possible decode - if (n->outcnt() == 1 && n->unique_out()->is_DecodeN()) { - n = n->unique_out(); - } +G1PreBarrierStubC2::G1PreBarrierStubC2(const MachNode* node) : G1BarrierStubC2(node) {} - if (n->outcnt() == 3) { - int found = 0; - for (SimpleDUIterator iter(n); iter.has_next(); iter.next()) { - Node* use = iter.get(); - if (use->is_Cmp() || use->is_Store()) { - ++found; - } else if (use->is_CallLeaf()) { - CallLeafNode* call = use->as_CallLeaf(); - if (strcmp(call->_name, "write_ref_field_pre_entry") == 0) { - ++found; - } - } - } - if (found == 3) { - return true; - } - } +bool G1PreBarrierStubC2::needs_barrier(const MachNode* node) { + return (node->barrier_data() & G1C2BarrierPre) != 0; +} + +G1PreBarrierStubC2* G1PreBarrierStubC2::create(const MachNode* node) { + G1PreBarrierStubC2* const stub = new (Compile::current()->comp_arena()) G1PreBarrierStubC2(node); + if (!Compile::current()->output()->in_scratch_emit_size()) { + barrier_set_state()->stubs()->append(stub); } - return false; + return stub; } -bool G1BarrierSetC2::is_gc_pre_barrier_node(Node *node) const { - return is_g1_pre_val_load(node); +void G1PreBarrierStubC2::initialize_registers(Register obj, Register pre_val, Register thread, Register tmp1, Register tmp2) { + _obj = obj; + _pre_val = pre_val; + _thread = thread; + _tmp1 = tmp1; + _tmp2 = tmp2; } -void G1BarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const { - if (is_g1_pre_val_load(node)) { - macro->replace_node(node, macro->zerocon(node->as_Load()->bottom_type()->basic_type())); - } else { - assert(node->Opcode() == Op_CastP2X, "ConvP2XNode required"); - assert(node->outcnt() <= 2, "expects 1 or 2 users: Xor and URShift nodes"); - // It could be only one user, URShift node, in Object.clone() intrinsic - // but the new allocation is passed to arraycopy stub and it could not - // be scalar replaced. So we don't check the case. +Register G1PreBarrierStubC2::obj() const { + return _obj; +} - // An other case of only one user (Xor) is when the value check for null - // in G1 post barrier is folded after CCP so the code which used URShift - // is removed. +Register G1PreBarrierStubC2::pre_val() const { + return _pre_val; +} - // Take Region node before eliminating post barrier since it also - // eliminates CastP2X node when it has only one user. - Node* this_region = node->in(0); - assert(this_region != nullptr, ""); +Register G1PreBarrierStubC2::thread() const { + return _thread; +} - // Remove G1 post barrier. +Register G1PreBarrierStubC2::tmp1() const { + return _tmp1; +} + +Register G1PreBarrierStubC2::tmp2() const { + return _tmp2; +} - // Search for CastP2X->Xor->URShift->Cmp path which - // checks if the store done to a different from the value's region. - // And replace Cmp with #0 (false) to collapse G1 post barrier. - Node* xorx = node->find_out_with(Op_XorX); - if (xorx != nullptr) { - Node* shift = xorx->unique_out(); - Node* cmpx = shift->unique_out(); - assert(cmpx->is_Cmp() && cmpx->unique_out()->is_Bool() && - cmpx->unique_out()->as_Bool()->_test._test == BoolTest::ne, - "missing region check in G1 post barrier"); - macro->replace_node(cmpx, macro->makecon(TypeInt::CC_EQ)); +void G1PreBarrierStubC2::emit_code(MacroAssembler& masm) { + G1BarrierSetAssembler* bs = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + bs->generate_c2_pre_barrier_stub(&masm, this); +} - // Remove G1 pre barrier. +G1PostBarrierStubC2::G1PostBarrierStubC2(const MachNode* node) : G1BarrierStubC2(node) {} - // Search "if (marking != 0)" check and set it to "false". - // There is no G1 pre barrier if previous stored value is null - // (for example, after initialization). - if (this_region->is_Region() && this_region->req() == 3) { - int ind = 1; - if (!this_region->in(ind)->is_IfFalse()) { - ind = 2; - } - if (this_region->in(ind)->is_IfFalse() && - this_region->in(ind)->in(0)->Opcode() == Op_If) { - Node* bol = this_region->in(ind)->in(0)->in(1); - assert(bol->is_Bool(), ""); - cmpx = bol->in(1); - if (bol->as_Bool()->_test._test == BoolTest::ne && - cmpx->is_Cmp() && cmpx->in(2) == macro->intcon(0) && - cmpx->in(1)->is_Load()) { - Node* adr = cmpx->in(1)->as_Load()->in(MemNode::Address); - const int marking_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - if (adr->is_AddP() && adr->in(AddPNode::Base) == macro->top() && - adr->in(AddPNode::Address)->Opcode() == Op_ThreadLocal && - adr->in(AddPNode::Offset) == macro->MakeConX(marking_offset)) { - macro->replace_node(cmpx, macro->makecon(TypeInt::CC_EQ)); - } - } - } - } - } else { - assert(!use_ReduceInitialCardMarks(), "can only happen with card marking"); - // This is a G1 post barrier emitted by the Object.clone() intrinsic. - // Search for the CastP2X->URShiftX->AddP->LoadB->Cmp path which checks if the card - // is marked as young_gen and replace the Cmp with 0 (false) to collapse the barrier. - Node* shift = node->find_out_with(Op_URShiftX); - assert(shift != nullptr, "missing G1 post barrier"); - Node* addp = shift->unique_out(); - Node* load = addp->find_out_with(Op_LoadB); - assert(load != nullptr, "missing G1 post barrier"); - Node* cmpx = load->unique_out(); - assert(cmpx->is_Cmp() && cmpx->unique_out()->is_Bool() && - cmpx->unique_out()->as_Bool()->_test._test == BoolTest::ne, - "missing card value check in G1 post barrier"); - macro->replace_node(cmpx, macro->makecon(TypeInt::CC_EQ)); - // There is no G1 pre barrier in this case - } - // Now CastP2X can be removed since it is used only on dead path - // which currently still alive until igvn optimize it. - assert(node->outcnt() == 0 || node->unique_out()->Opcode() == Op_URShiftX, ""); - macro->replace_node(node, macro->top()); - } +bool G1PostBarrierStubC2::needs_barrier(const MachNode* node) { + return (node->barrier_data() & G1C2BarrierPost) != 0; } -Node* G1BarrierSetC2::step_over_gc_barrier(Node* c) const { - if (!use_ReduceInitialCardMarks() && - c != nullptr && c->is_Region() && c->req() == 3) { - for (uint i = 1; i < c->req(); i++) { - if (c->in(i) != nullptr && c->in(i)->is_Region() && - c->in(i)->req() == 3) { - Node* r = c->in(i); - for (uint j = 1; j < r->req(); j++) { - if (r->in(j) != nullptr && r->in(j)->is_Proj() && - r->in(j)->in(0) != nullptr && - r->in(j)->in(0)->Opcode() == Op_CallLeaf && - r->in(j)->in(0)->as_Call()->entry_point() == CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry)) { - Node* call = r->in(j)->in(0); - c = c->in(i == 1 ? 2 : 1); - if (c != nullptr && c->Opcode() != Op_Parm) { - c = c->in(0); - if (c != nullptr) { - c = c->in(0); - assert(call->in(0) == nullptr || - call->in(0)->in(0) == nullptr || - call->in(0)->in(0)->in(0) == nullptr || - call->in(0)->in(0)->in(0)->in(0) == nullptr || - call->in(0)->in(0)->in(0)->in(0)->in(0) == nullptr || - c == call->in(0)->in(0)->in(0)->in(0)->in(0), "bad barrier shape"); - return c; - } - } - } - } - } - } +G1PostBarrierStubC2* G1PostBarrierStubC2::create(const MachNode* node) { + G1PostBarrierStubC2* const stub = new (Compile::current()->comp_arena()) G1PostBarrierStubC2(node); + if (!Compile::current()->output()->in_scratch_emit_size()) { + barrier_set_state()->stubs()->append(stub); } - return c; + return stub; } -#ifdef ASSERT -bool G1BarrierSetC2::has_cas_in_use_chain(Node *n) const { - Unique_Node_List visited; - Node_List worklist; - worklist.push(n); - while (worklist.size() > 0) { - Node* x = worklist.pop(); - if (visited.member(x)) { - continue; - } else { - visited.push(x); - } +void G1PostBarrierStubC2::initialize_registers(Register thread, Register tmp1, Register tmp2, Register tmp3) { + _thread = thread; + _tmp1 = tmp1; + _tmp2 = tmp2; + _tmp3 = tmp3; +} - if (x->is_LoadStore()) { - int op = x->Opcode(); - if (op == Op_CompareAndExchangeP || op == Op_CompareAndExchangeN || - op == Op_CompareAndSwapP || op == Op_CompareAndSwapN || - op == Op_WeakCompareAndSwapP || op == Op_WeakCompareAndSwapN) { - return true; - } - } - if (!x->is_CFG()) { - for (SimpleDUIterator iter(x); iter.has_next(); iter.next()) { - Node* use = iter.get(); - worklist.push(use); - } - } - } - return false; +Register G1PostBarrierStubC2::thread() const { + return _thread; } -void G1BarrierSetC2::verify_pre_load(Node* marking_if, Unique_Node_List& loads /*output*/) const { - assert(loads.size() == 0, "Loads list should be empty"); - Node* pre_val_if = marking_if->find_out_with(Op_IfTrue)->find_out_with(Op_If); - if (pre_val_if != nullptr) { - Unique_Node_List visited; - Node_List worklist; - Node* pre_val = pre_val_if->in(1)->in(1)->in(1); +Register G1PostBarrierStubC2::tmp1() const { + return _tmp1; +} - worklist.push(pre_val); - while (worklist.size() > 0) { - Node* x = worklist.pop(); - if (visited.member(x)) { - continue; - } else { - visited.push(x); - } +Register G1PostBarrierStubC2::tmp2() const { + return _tmp2; +} - if (has_cas_in_use_chain(x)) { - loads.clear(); - return; - } +Register G1PostBarrierStubC2::tmp3() const { + return _tmp3; +} - if (x->is_Con()) { - continue; - } - if (x->is_EncodeP() || x->is_DecodeN()) { - worklist.push(x->in(1)); - continue; - } - if (x->is_Load() || x->is_LoadStore()) { - assert(x->in(0) != nullptr, "Pre-val load has to have a control"); - loads.push(x); - continue; - } - if (x->is_Phi()) { - for (uint i = 1; i < x->req(); i++) { - worklist.push(x->in(i)); - } - continue; - } - assert(false, "Pre-val anomaly"); - } - } +void G1PostBarrierStubC2::emit_code(MacroAssembler& masm) { + G1BarrierSetAssembler* bs = static_cast(BarrierSet::barrier_set()->barrier_set_assembler()); + bs->generate_c2_post_barrier_stub(&masm, this); } -void G1BarrierSetC2::verify_no_safepoints(Compile* compile, Node* marking_check_if, const Unique_Node_List& loads) const { - if (loads.size() == 0) { - return; - } +void* G1BarrierSetC2::create_barrier_state(Arena* comp_arena) const { + return new (comp_arena) G1BarrierSetC2State(comp_arena); +} - if (loads.size() == 1) { // Handle the typical situation when there a single pre-value load - // that is dominated by the marking_check_if, that's true when the - // barrier itself does the pre-val load. - Node *pre_val = loads.at(0); - if (pre_val->in(0)->in(0) == marking_check_if) { // IfTrue->If - return; - } +int G1BarrierSetC2::get_store_barrier(C2Access& access) const { + if (!access.is_parse_access()) { + // Only support for eliding barriers at parse time for now. + return G1C2BarrierPre | G1C2BarrierPost; } - - // All other cases are when pre-value loads dominate the marking check. - Unique_Node_List controls; - for (uint i = 0; i < loads.size(); i++) { - Node *c = loads.at(i)->in(0); - controls.push(c); + GraphKit* kit = (static_cast(access)).kit(); + Node* ctl = kit->control(); + Node* adr = access.addr().node(); + uint adr_idx = kit->C->get_alias_index(access.addr().type()); + assert(adr_idx != Compile::AliasIdxTop, "use other store_to_memory factory"); + + bool can_remove_pre_barrier = g1_can_remove_pre_barrier(kit, &kit->gvn(), adr, access.type(), adr_idx); + + // We can skip marks on a freshly-allocated object in Eden. Keep this code in + // sync with CardTableBarrierSet::on_slowpath_allocation_exit. That routine + // informs GC to take appropriate compensating steps, upon a slow-path + // allocation, so as to make this card-mark elision safe. + // The post-barrier can also be removed if null is written. This case is + // handled by G1BarrierSetC2::expand_barriers, which runs at the end of C2's + // platform-independent optimizations to exploit stronger type information. + bool can_remove_post_barrier = use_ReduceInitialCardMarks() && + ((access.base() == kit->just_allocated_object(ctl)) || + g1_can_remove_post_barrier(kit, &kit->gvn(), ctl, adr)); + + int barriers = 0; + if (!can_remove_pre_barrier) { + barriers |= G1C2BarrierPre; + } + if (!can_remove_post_barrier) { + barriers |= G1C2BarrierPost; } - Unique_Node_List visited; - Unique_Node_List safepoints; - Node_List worklist; - uint found = 0; + return barriers; +} - worklist.push(marking_check_if); - while (worklist.size() > 0 && found < controls.size()) { - Node* x = worklist.pop(); - if (x == nullptr || x == compile->top()) continue; - if (visited.member(x)) { - continue; - } else { - visited.push(x); - } +void G1BarrierSetC2::late_barrier_analysis() const { + compute_liveness_at_stubs(); +} - if (controls.member(x)) { - found++; - } - if (x->is_Region()) { - for (uint i = 1; i < x->req(); i++) { - worklist.push(x->in(i)); - } - } else { - if (!x->is_SafePoint()) { - worklist.push(x->in(0)); - } else { - safepoints.push(x); - } +void G1BarrierSetC2::emit_stubs(CodeBuffer& cb) const { + MacroAssembler masm(&cb); + GrowableArray* const stubs = barrier_set_state()->stubs(); + for (int i = 0; i < stubs->length(); i++) { + // Make sure there is enough space in the code buffer + if (cb.insts()->maybe_expand_to_ensure_remaining(PhaseOutput::MAX_inst_size) && cb.blob() == nullptr) { + ciEnv::current()->record_failure("CodeCache is full"); + return; } + stubs->at(i)->emit_code(masm); } - assert(found == controls.size(), "Pre-barrier structure anomaly or possible safepoint"); + masm.flush(); } -void G1BarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase phase) const { - if (phase != BarrierSetC2::BeforeCodeGen) { - return; +#ifndef PRODUCT +void G1BarrierSetC2::dump_barrier_data(const MachNode* mach, outputStream* st) const { + if ((mach->barrier_data() & G1C2BarrierPre) != 0) { + st->print("pre "); } - // Verify G1 pre-barriers - const int marking_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()); - - Unique_Node_List visited; - Node_List worklist; - // We're going to walk control flow backwards starting from the Root - worklist.push(compile->root()); - while (worklist.size() > 0) { - Node* x = worklist.pop(); - if (x == nullptr || x == compile->top()) continue; - if (visited.member(x)) { - continue; - } else { - visited.push(x); - } - - if (x->is_Region()) { - for (uint i = 1; i < x->req(); i++) { - worklist.push(x->in(i)); - } - } else { - worklist.push(x->in(0)); - // We are looking for the pattern: - // /->ThreadLocal - // If->Bool->CmpI->LoadB->AddP->ConL(marking_offset) - // \->ConI(0) - // We want to verify that the If and the LoadB have the same control - // See GraphKit::g1_write_barrier_pre() - if (x->is_If()) { - IfNode *iff = x->as_If(); - if (iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp()) { - CmpNode *cmp = iff->in(1)->in(1)->as_Cmp(); - if (cmp->Opcode() == Op_CmpI && cmp->in(2)->is_Con() && cmp->in(2)->bottom_type()->is_int()->get_con() == 0 - && cmp->in(1)->is_Load()) { - LoadNode* load = cmp->in(1)->as_Load(); - if (load->Opcode() == Op_LoadB && load->in(2)->is_AddP() && load->in(2)->in(2)->Opcode() == Op_ThreadLocal - && load->in(2)->in(3)->is_Con() - && load->in(2)->in(3)->bottom_type()->is_intptr_t()->get_con() == marking_offset) { - - Node* if_ctrl = iff->in(0); - Node* load_ctrl = load->in(0); - - if (if_ctrl != load_ctrl) { - // Skip possible CProj->NeverBranch in infinite loops - if ((if_ctrl->is_Proj() && if_ctrl->Opcode() == Op_CProj) - && if_ctrl->in(0)->is_NeverBranch()) { - if_ctrl = if_ctrl->in(0)->in(0); - } - } - assert(load_ctrl != nullptr && if_ctrl == load_ctrl, "controls must match"); - - Unique_Node_List loads; - verify_pre_load(iff, loads); - verify_no_safepoints(compile, iff, loads); - } - } - } - } - } + if ((mach->barrier_data() & G1C2BarrierPost) != 0) { + st->print("post "); } -} -#endif - -bool G1BarrierSetC2::escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const { - if (opcode == Op_StoreP) { - Node* adr = n->in(MemNode::Address); - const Type* adr_type = gvn->type(adr); - // Pointer stores in G1 barriers looks like unsafe access. - // Ignore such stores to be able scalar replace non-escaping - // allocations. - if (adr_type->isa_rawptr() && adr->is_AddP()) { - Node* base = conn_graph->get_addp_base(adr); - if (base->Opcode() == Op_LoadP && - base->in(MemNode::Address)->is_AddP()) { - adr = base->in(MemNode::Address); - Node* tls = conn_graph->get_addp_base(adr); - if (tls->Opcode() == Op_ThreadLocal) { - int offs = (int) gvn->find_intptr_t_con(adr->in(AddPNode::Offset), Type::OffsetBot); - const int buf_offset = in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()); - if (offs == buf_offset) { - return true; // G1 pre barrier previous oop value store. - } - if (offs == in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())) { - return true; // G1 post barrier card address store. - } - } - } - } + if ((mach->barrier_data() & G1C2BarrierPostNotNull) != 0) { + st->print("notnull "); } - return false; } +#endif // !PRODUCT diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp index c445a87d2e46d..dc333d8c33174 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp @@ -31,29 +31,62 @@ class PhaseTransform; class Type; class TypeFunc; -class G1BarrierSetC2: public CardTableBarrierSetC2 { +const int G1C2BarrierPre = 1; +const int G1C2BarrierPost = 2; +const int G1C2BarrierPostNotNull = 4; + +class G1BarrierStubC2 : public BarrierStubC2 { +public: + G1BarrierStubC2(const MachNode* node); + virtual void emit_code(MacroAssembler& masm) = 0; +}; + +class G1PreBarrierStubC2 : public G1BarrierStubC2 { +private: + Register _obj; + Register _pre_val; + Register _thread; + Register _tmp1; + Register _tmp2; + +protected: + G1PreBarrierStubC2(const MachNode* node); + +public: + static bool needs_barrier(const MachNode* node); + static G1PreBarrierStubC2* create(const MachNode* node); + void initialize_registers(Register obj, Register pre_val, Register thread, Register tmp1 = noreg, Register tmp2 = noreg); + Register obj() const; + Register pre_val() const; + Register thread() const; + Register tmp1() const; + Register tmp2() const; + virtual void emit_code(MacroAssembler& masm); +}; + +class G1PostBarrierStubC2 : public G1BarrierStubC2 { +private: + Register _thread; + Register _tmp1; + Register _tmp2; + Register _tmp3; + protected: - virtual void pre_barrier(GraphKit* kit, - bool do_load, - Node* ctl, - Node* obj, - Node* adr, - uint adr_idx, - Node* val, - const TypeOopPtr* val_type, - Node* pre_val, - BasicType bt) const; - - virtual void post_barrier(GraphKit* kit, - Node* ctl, - Node* store, - Node* obj, - Node* adr, - uint adr_idx, - Node* val, - BasicType bt, - bool use_precise) const; + G1PostBarrierStubC2(const MachNode* node); +public: + static bool needs_barrier(const MachNode* node); + static G1PostBarrierStubC2* create(const MachNode* node); + void initialize_registers(Register thread, Register tmp1 = noreg, Register tmp2 = noreg, Register tmp3 = noreg); + Register thread() const; + Register tmp1() const; + Register tmp2() const; + Register tmp3() const; + virtual void emit_code(MacroAssembler& masm); +}; + +class G1BarrierSetC2: public CardTableBarrierSetC2 { +protected: bool g1_can_remove_pre_barrier(GraphKit* kit, PhaseValues* phase, Node* adr, @@ -64,44 +97,31 @@ class G1BarrierSetC2: public CardTableBarrierSetC2 { PhaseValues* phase, Node* store, Node* adr) const; - void g1_mark_card(GraphKit* kit, - IdealKit& ideal, - Node* card_adr, - Node* oop_store, - uint oop_alias_idx, - Node* index, - Node* index_adr, - Node* buffer, - const TypeFunc* tf) const; - - // Helper for unsafe accesses, that may or may not be on the referent field. - // Generates the guards that check whether the result of - // Unsafe.getReference should be recorded in an SATB log buffer. - void insert_pre_barrier(GraphKit* kit, Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar) const; - - static const TypeFunc* write_ref_field_pre_entry_Type(); - static const TypeFunc* write_ref_field_post_entry_Type(); + int get_store_barrier(C2Access& access) const; virtual Node* load_at_resolved(C2Access& access, const Type* val_type) const; + virtual Node* store_at_resolved(C2Access& access, C2AccessValue& val) const; + virtual Node* atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val, + Node* new_val, const Type* value_type) const; + virtual Node* atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val, + Node* new_val, const Type* value_type) const; + virtual Node* atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const; -#ifdef ASSERT - bool has_cas_in_use_chain(Node* x) const; - void verify_pre_load(Node* marking_check_if, Unique_Node_List& loads /*output*/) const; - void verify_no_safepoints(Compile* compile, Node* marking_load, const Unique_Node_List& loads) const; -#endif - - static bool is_g1_pre_val_load(Node* n); public: - virtual bool is_gc_pre_barrier_node(Node* node) const; - virtual bool is_gc_barrier_node(Node* node) const; virtual void eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const; - virtual Node* step_over_gc_barrier(Node* c) const; - -#ifdef ASSERT - virtual void verify_gc_barriers(Compile* compile, CompilePhase phase) const; + virtual void eliminate_gc_barrier_data(Node* node) const; + virtual bool expand_barriers(Compile* C, PhaseIterGVN& igvn) const; + virtual uint estimated_barrier_size(const Node* node) const; + virtual bool can_initialize_object(const StoreNode* store) const; + virtual void clone_at_expansion(PhaseMacroExpand* phase, + ArrayCopyNode* ac) const; + virtual void* create_barrier_state(Arena* comp_arena) const; + virtual void emit_stubs(CodeBuffer& cb) const; + virtual void late_barrier_analysis() const; + +#ifndef PRODUCT + virtual void dump_barrier_data(const MachNode* mach, outputStream* st) const; #endif - - virtual bool escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const; }; #endif // SHARE_GC_G1_C2_G1BARRIERSETC2_HPP diff --git a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp index a0fce437807f4..2e247f46c93d8 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp +++ b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.cpp @@ -61,3 +61,11 @@ JRT_LEAF(void, G1BarrierSetRuntime::write_ref_field_post_entry(volatile G1CardTa G1DirtyCardQueue& queue = G1ThreadLocalData::dirty_card_queue(thread); G1BarrierSet::dirty_card_queue_set().enqueue(queue, card_addr); JRT_END + +JRT_LEAF(void, G1BarrierSetRuntime::clone(oopDesc* src, oopDesc* dst, size_t size)) + HeapAccess<>::clone(src, dst, size); +JRT_END + +address G1BarrierSetRuntime::clone_addr() { + return reinterpret_cast

        (clone); +} diff --git a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.hpp b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.hpp index 366679f032ba9..f98e94096e72d 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSetRuntime.hpp +++ b/src/hotspot/share/gc/g1/g1BarrierSetRuntime.hpp @@ -35,6 +35,8 @@ class oopDesc; class JavaThread; class G1BarrierSetRuntime: public AllStatic { +private: + static void clone(oopDesc* src, oopDesc* dst, size_t size); public: using CardValue = G1CardTable::CardValue; @@ -46,6 +48,8 @@ class G1BarrierSetRuntime: public AllStatic { // C2 slow-path runtime calls. static void write_ref_field_pre_entry(oopDesc* orig, JavaThread *thread); static void write_ref_field_post_entry(volatile CardValue* card_addr, JavaThread* thread); + + static address clone_addr(); }; #endif // SHARE_GC_G1_G1BARRIERSETRUNTIME_HPP diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp index 59e0245204441..643a7936b9b17 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp @@ -109,6 +109,10 @@ Label* BarrierStubC2::continuation() { return &_continuation; } +uint8_t BarrierStubC2::barrier_data() const { + return _node->barrier_data(); +} + void BarrierStubC2::preserve(Register r) { const VMReg vm_reg = r->as_VMReg(); assert(vm_reg->is_Register(), "r must be a general-purpose register"); diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp index c1485c069c83c..00fbf1f2c9f8b 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp @@ -254,6 +254,8 @@ class BarrierStubC2 : public ArenaObj { Label* entry(); // Return point from the stub (typically end of barrier). Label* continuation(); + // High-level, GC-specific barrier flags. + uint8_t barrier_data() const; // Preserve the value in reg across runtime calls in this barrier. void preserve(Register reg); @@ -340,6 +342,8 @@ class BarrierSetC2: public CHeapObj { // Estimated size of the node barrier in number of C2 Ideal nodes. // This is used to guide heuristics in C2, e.g. whether to unroll a loop. virtual uint estimated_barrier_size(const Node* node) const { return 0; } + // Whether the given store can be used to initialize a newly allocated object. + virtual bool can_initialize_object(const StoreNode* store) const { return true; } enum CompilePhase { BeforeOptimize, diff --git a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp index 87bb9f3cd5170..11b742156a831 100644 --- a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.cpp @@ -125,39 +125,10 @@ void CardTableBarrierSetC2::post_barrier(GraphKit* kit, kit->final_sync(ideal); } -void CardTableBarrierSetC2::clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const { - BarrierSetC2::clone(kit, src, dst, size, is_array); - const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM; - - // If necessary, emit some card marks afterwards. (Non-arrays only.) - bool card_mark = !is_array && !use_ReduceInitialCardMarks(); - if (card_mark) { - assert(!is_array, ""); - // Put in store barrier for any and all oops we are sticking - // into this object. (We could avoid this if we could prove - // that the object type contains no oop fields at all.) - Node* no_particular_value = nullptr; - Node* no_particular_field = nullptr; - int raw_adr_idx = Compile::AliasIdxRaw; - post_barrier(kit, kit->control(), - kit->memory(raw_adr_type), - dst, - no_particular_field, - raw_adr_idx, - no_particular_value, - T_OBJECT, - false); - } -} - bool CardTableBarrierSetC2::use_ReduceInitialCardMarks() const { return ReduceInitialCardMarks; } -bool CardTableBarrierSetC2::is_gc_barrier_node(Node* node) const { - return ModRefBarrierSetC2::is_gc_barrier_node(node) || node->Opcode() == Op_StoreCM; -} - void CardTableBarrierSetC2::eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const { assert(node->Opcode() == Op_CastP2X, "ConvP2XNode required"); Node *shift = node->unique_out(); diff --git a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp index 9512f09ff8a6d..3bbf14892d3ef 100644 --- a/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/cardTableBarrierSetC2.hpp @@ -42,8 +42,6 @@ class CardTableBarrierSetC2: public ModRefBarrierSetC2 { Node* byte_map_base_node(GraphKit* kit) const; public: - virtual void clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const; - virtual bool is_gc_barrier_node(Node* node) const; virtual void eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const; virtual bool array_copy_requires_gc_barriers(bool tightly_coupled_alloc, BasicType type, bool is_clone, bool is_clone_instance, ArrayCopyPhase phase) const; diff --git a/src/hotspot/share/opto/buildOopMap.cpp b/src/hotspot/share/opto/buildOopMap.cpp index 4591e87da2d14..b553cc6ea6949 100644 --- a/src/hotspot/share/opto/buildOopMap.cpp +++ b/src/hotspot/share/opto/buildOopMap.cpp @@ -235,6 +235,13 @@ OopMap *OopFlow::build_oop_map( Node *n, int max_reg, PhaseRegAlloc *regalloc, i Node *def = _defs[reg]; // Get reaching def assert( def, "since live better have reaching def" ); + if (def->is_MachTemp()) { + assert(!def->bottom_type()->isa_oop_ptr(), + "ADLC only assigns OOP types to MachTemp defs corresponding to xRegN operands"); + // Exclude MachTemp definitions even if they are typed as oops. + continue; + } + // Classify the reaching def as oop, derived, callee-save, dead, or other const Type *t = def->bottom_type(); if( t->isa_oop_ptr() ) { // Oop or derived? diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index 9db94748ca27c..3c6de96074a15 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -161,6 +161,14 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo Node *m = val->out(i); if( !m->is_Mach() ) continue; MachNode *mach = m->as_Mach(); + if (mach->barrier_data() != 0) { + // Using memory accesses with barriers to perform implicit null checks is + // not supported. These operations might expand into multiple assembly + // instructions during code emission, including new memory accesses (e.g. + // in G1's pre-barrier), which would invalidate the implicit null + // exception table. + continue; + } was_store = false; int iop = mach->ideal_Opcode(); switch( iop ) { diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index bf773d43d3d39..6d96bff1c1c44 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -1594,6 +1594,14 @@ static bool match_into_reg( const Node *n, Node *m, Node *control, int i, bool s // the same register. See find_shared_node. return false; } else { // Not a constant + if (!shared && Matcher::is_encode_and_store_pattern(n, m)) { + // Make it possible to match "encode and store" patterns with non-shared + // encode operations that are pinned to a control node (e.g. by CastPP + // node removal in final graph reshaping). The matched instruction cannot + // float above the encode's control node because it is pinned to the + // store's control node. + return false; + } // Stop recursion if they have different Controls. Node* m_control = m->in(0); // Control of load's memory can post-dominates load's control. @@ -2833,6 +2841,18 @@ bool Matcher::is_non_long_integral_vector(const Node* n) { return is_subword_type(bt) || bt == T_INT; } +bool Matcher::is_encode_and_store_pattern(const Node* n, const Node* m) { + if (n == nullptr || + m == nullptr || + n->Opcode() != Op_StoreN || + !m->is_EncodeP() || + n->as_Store()->barrier_data() == 0) { + return false; + } + assert(m == n->in(MemNode::ValueIn), "m should be input to n"); + return true; +} + #ifdef ASSERT bool Matcher::verify_after_postselect_cleanup() { assert(!C->failing(), "sanity"); diff --git a/src/hotspot/share/opto/matcher.hpp b/src/hotspot/share/opto/matcher.hpp index 84e48086f92d3..257628350881a 100644 --- a/src/hotspot/share/opto/matcher.hpp +++ b/src/hotspot/share/opto/matcher.hpp @@ -385,6 +385,8 @@ class Matcher : public PhaseTransform { return ((bt & BoolTest::unsigned_compare) == BoolTest::unsigned_compare); } + static bool is_encode_and_store_pattern(const Node* n, const Node* m); + // These calls are all generated by the ADLC // Java-Java calling convention diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index eee14e5ba03f1..6613918826057 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -4644,6 +4644,11 @@ intptr_t InitializeNode::can_capture_store(StoreNode* st, PhaseGVN* phase, bool Node* mem = st->in(MemNode::Memory); if (!(mem->is_Proj() && mem->in(0) == this)) return FAIL; // must not be preceded by other stores + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + if ((st->Opcode() == Op_StoreP || st->Opcode() == Op_StoreN) && + !bs->can_initialize_object(st)) { + return FAIL; + } Node* adr = st->in(MemNode::Address); intptr_t offset; AllocateNode* alloc = AllocateNode::Ideal_allocation(adr, phase, offset); diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index b3f251bb361ba..260f887347f18 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -2022,6 +2022,8 @@ void PhaseOutput::FillExceptionTables(uint cnt, uint *call_returns, uint *inct_s // Handle implicit null exception table updates if (n->is_MachNullCheck()) { + assert(n->in(1)->as_Mach()->barrier_data() == 0, + "Implicit null checks on memory accesses with barriers are not yet supported"); uint block_num = block->non_connector_successor(0)->_pre_order; _inc_table.append(inct_starts[inct_cnt++], blk_labels[block_num].loc_pos()); continue; diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java index 23b9321fc35c1..3f82c3e00b3ac 100644 --- a/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestVolatiles.java @@ -261,20 +261,11 @@ private void checkstore(OutputAnalyzer output, String testType, boolean useCompr }; break; case "G1": - // a card mark volatile barrier should be generated - // before the card mark strb - // - // following the fix for 8225776 the G1 barrier is now - // scheduled out of line after the membar volatile and - // and subsequent return matches = new String[] { "membar_release \\(elided\\)", useCompressedOops ? "stlrw?" : "stlr", "membar_volatile \\(elided\\)", - "ret", - "membar_volatile", - "dmb ish", - "strb" + "ret" }; break; case "Shenandoah": @@ -332,20 +323,11 @@ private void checkcas(OutputAnalyzer output, String testType, boolean useCompres }; break; case "G1": - // a card mark volatile barrier should be generated - // before the card mark strb - // - // following the fix for 8225776 the G1 barrier is now - // scheduled out of line after the membar acquire and - // and subsequent return matches = new String[] { "membar_release \\(elided\\)", useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", "membar_acquire \\(elided\\)", - "ret", - "membar_volatile", - "dmb ish", - "strb" + "ret" }; break; case "Shenandoah": @@ -418,20 +400,11 @@ private void checkcae(OutputAnalyzer output, String testType, boolean useCompres return; case "G1": - // a card mark volatile barrier should be generated - // before the card mark strb - // - // following the fix for 8225776 the G1 barrier is now - // scheduled out of line after the membar acquire and - // and subsequent return matches = new String[] { "membar_release \\(elided\\)", useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", "membar_acquire \\(elided\\)", - "ret", - "membar_volatile", - "dmb ish", - "strb" + "ret" }; break; case "Shenandoah": @@ -484,20 +457,11 @@ private void checkgas(OutputAnalyzer output, String testType, boolean useCompres }; break; case "G1": - // a card mark volatile barrier should be generated - // before the card mark strb - // - // following the fix for 8225776 the G1 barrier is now - // scheduled out of line after the membar acquire and - // and subsequent return matches = new String[] { "membar_release \\(elided\\)", useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq", "membar_acquire \\(elided\\)", - "ret", - "membar_volatile", - "dmb ish", - "strb" + "ret" }; break; case "Shenandoah": diff --git a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java index cd3d5329771ef..69b3cb5274b57 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java @@ -1355,9 +1355,12 @@ int testReReduce(boolean cond, int x, int y) { } @Test - @IR(counts = { IRNode.ALLOC, "1" }) - // The last allocation won't be reduced because it would cause the creation - // of a nested SafePointScalarMergeNode. + // Using G1, all allocations are reduced. + @IR(applyIf = {"UseG1GC", "true"}, failOn = { IRNode.ALLOC }) + // Otherwise, the last allocation won't be reduced because it would cause + // the creation of a nested SafePointScalarMergeNode. This is caused by the + // store barrier corresponding to 'C.other = B'. + @IR(applyIf = {"UseG1GC", "false"}, counts = { IRNode.ALLOC, "1" }) int testReReduce_C2(boolean cond1, int x, int y) { return testReReduce(cond1, x, y); } @DontCompile diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.java b/test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.java new file mode 100644 index 0000000000000..36ad0bf84a40b --- /dev/null +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestG1BarrierGeneration.java @@ -0,0 +1,639 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.gcbarriers; + +import compiler.lib.ir_framework.*; +import java.lang.invoke.VarHandle; +import java.lang.invoke.MethodHandles; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.util.concurrent.ThreadLocalRandom; +import jdk.test.lib.Asserts; + +/** + * @test + * @summary Test that G1 barriers are generated and optimized as expected. + * @library /test/lib / + * @requires vm.gc.G1 + * @run driver compiler.gcbarriers.TestG1BarrierGeneration + */ + +public class TestG1BarrierGeneration { + static final String PRE_ONLY = "pre"; + static final String POST_ONLY = "post"; + static final String POST_ONLY_NOT_NULL = "post notnull"; + static final String PRE_AND_POST = "pre post"; + static final String PRE_AND_POST_NOT_NULL = "pre post notnull"; + + static class Outer { + Object f; + } + + static class OuterWithVolatileField { + volatile Object f; + } + + static class OuterWithFewFields implements Cloneable { + Object f1; + Object f2; + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + } + + static class OuterWithManyFields implements Cloneable { + Object f1; + Object f2; + Object f3; + Object f4; + Object f5; + Object f6; + Object f7; + Object f8; + Object f9; + Object f10; + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + } + + static final VarHandle fVarHandle; + static { + MethodHandles.Lookup l = MethodHandles.lookup(); + try { + fVarHandle = l.findVarHandle(Outer.class, "f", Object.class); + } catch (Exception e) { + throw new Error(e); + } + } + + public static void main(String[] args) { + TestFramework framework = new TestFramework(); + Scenario[] scenarios = new Scenario[2*2]; + int scenarioIndex = 0; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + scenarios[scenarioIndex] = + new Scenario(scenarioIndex, + "-XX:CompileCommand=inline,java.lang.ref.*::*", + "-XX:" + (i == 0 ? "-" : "+") + "UseCompressedOops", + "-XX:" + (j == 0 ? "-" : "+") + "ReduceInitialCardMarks"); + scenarioIndex++; + } + } + framework.addScenarios(scenarios); + framework.start(); + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testStore(Outer o, Object o1) { + o.f = o1; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testStoreNull(Outer o) { + o.f = null; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testStoreObfuscatedNull(Outer o, Object o1) { + Object o2 = o1; + for (int i = 0; i < 4; i++) { + if ((i % 2) == 0) { + o2 = null; + } + } + // o2 is null here, but this is only known to C2 after applying some + // optimizations (loop unrolling, IGVN). + o.f = o2; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testStoreNotNull(Outer o, Object o1) { + if (o1.hashCode() == 42) { + return; + } + o.f = o1; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "2"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "2"}, + phase = CompilePhase.FINAL_CODE) + public static void testStoreTwice(Outer o, Outer p, Object o1) { + o.f = o1; + p.f = o1; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testStoreVolatile(OuterWithVolatileField o, Object o1) { + o.f = o1; + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + phase = CompilePhase.FINAL_CODE) + public static Outer testStoreOnNewObject(Object o1) { + Outer o = new Outer(); + o.f = o1; + return o; + } + + @Test + @IR(failOn = {IRNode.STORE_P, IRNode.STORE_N}, + phase = CompilePhase.BEFORE_MACRO_EXPANSION) + public static Outer testStoreNullOnNewObject() { + Outer o = new Outer(); + o.f = null; + return o; + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + phase = CompilePhase.FINAL_CODE) + public static Outer testStoreNotNullOnNewObject(Object o1) { + if (o1.hashCode() == 42) { + return null; + } + Outer o = new Outer(); + o.f = o1; + return o; + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "2"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "false"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "2"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + phase = CompilePhase.FINAL_CODE) + public static Outer testStoreOnNewObjectInTwoPaths(Object o1, boolean c) { + Outer o; + if (c) { + o = new Outer(); + o.f = o1; + } else { + o = new Outer(); + o.f = o1; + } + return o; + } + + @Run(test = {"testStore", + "testStoreNull", + "testStoreObfuscatedNull", + "testStoreNotNull", + "testStoreTwice", + "testStoreVolatile", + "testStoreOnNewObject", + "testStoreNullOnNewObject", + "testStoreNotNullOnNewObject", + "testStoreOnNewObjectInTwoPaths"}) + public void runStoreTests() { + { + Outer o = new Outer(); + Object o1 = new Object(); + testStore(o, o1); + Asserts.assertEquals(o1, o.f); + } + { + Outer o = new Outer(); + testStoreNull(o); + Asserts.assertNull(o.f); + } + { + Outer o = new Outer(); + Object o1 = new Object(); + testStoreObfuscatedNull(o, o1); + Asserts.assertNull(o.f); + } + { + Outer o = new Outer(); + Object o1 = new Object(); + testStoreNotNull(o, o1); + Asserts.assertEquals(o1, o.f); + } + { + Outer o = new Outer(); + Outer p = new Outer(); + Object o1 = new Object(); + testStoreTwice(o, p, o1); + Asserts.assertEquals(o1, o.f); + Asserts.assertEquals(o1, p.f); + } + { + OuterWithVolatileField o = new OuterWithVolatileField(); + Object o1 = new Object(); + testStoreVolatile(o, o1); + Asserts.assertEquals(o1, o.f); + } + { + Object o1 = new Object(); + Outer o = testStoreOnNewObject(o1); + Asserts.assertEquals(o1, o.f); + } + { + Outer o = testStoreNullOnNewObject(); + Asserts.assertNull(o.f); + } + { + Object o1 = new Object(); + Outer o = testStoreNotNullOnNewObject(o1); + Asserts.assertEquals(o1, o.f); + } + { + Object o1 = new Object(); + Outer o = testStoreOnNewObjectInTwoPaths(o1, ThreadLocalRandom.current().nextBoolean()); + Asserts.assertEquals(o1, o.f); + } + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testArrayStore(Object[] a, int index, Object o1) { + a[index] = o1; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testArrayStoreNull(Object[] a, int index) { + a[index] = null; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST_NOT_NULL, "1"}, + phase = CompilePhase.FINAL_CODE) + public static void testArrayStoreNotNull(Object[] a, int index, Object o1) { + if (o1.hashCode() == 42) { + return; + } + a[index] = o1; + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "2"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "2"}, + phase = CompilePhase.FINAL_CODE) + public static void testArrayStoreTwice(Object[] a, Object[] b, int index, Object o1) { + a[index] = o1; + b[index] = o1; + } + + @Test + @IR(applyIfAnd = {"UseCompressedOops", "false", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"UseCompressedOops", "true", "ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + phase = CompilePhase.FINAL_CODE) + public static Object[] testStoreOnNewArray(Object o1) { + Object[] a = new Object[10]; + // The index needs to be concrete for C2 to detect that it is safe to + // remove the pre-barrier. + a[4] = o1; + return a; + } + + @Run(test = {"testArrayStore", + "testArrayStoreNull", + "testArrayStoreNotNull", + "testArrayStoreTwice", + "testStoreOnNewArray"}) + public void runArrayStoreTests() { + { + Object[] a = new Object[10]; + Object o1 = new Object(); + testArrayStore(a, 4, o1); + Asserts.assertEquals(o1, a[4]); + } + { + Object[] a = new Object[10]; + testArrayStoreNull(a, 4); + Asserts.assertNull(a[4]); + } + { + Object[] a = new Object[10]; + Object o1 = new Object(); + testArrayStoreNotNull(a, 4, o1); + Asserts.assertEquals(o1, a[4]); + } + { + Object[] a = new Object[10]; + Object[] b = new Object[10]; + Object o1 = new Object(); + testArrayStoreTwice(a, b, 4, o1); + Asserts.assertEquals(o1, a[4]); + Asserts.assertEquals(o1, b[4]); + } + { + Object o1 = new Object(); + Object[] a = testStoreOnNewArray(o1); + Asserts.assertEquals(o1, a[4]); + } + } + + @Test + public static Object[] testCloneArrayOfObjects(Object[] a) { + Object[] a1 = null; + try { + a1 = a.clone(); + } catch (Exception e) {} + return a1; + } + + @Test + @IR(applyIf = {"ReduceInitialCardMarks", "true"}, + failOn = {IRNode.G1_STORE_P, IRNode.G1_STORE_N, IRNode.G1_ENCODE_P_AND_STORE_N}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"ReduceInitialCardMarks", "false", "UseCompressedOops", "false"}, + counts = {IRNode.G1_STORE_P_WITH_BARRIER_FLAG, POST_ONLY, "2"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIfAnd = {"ReduceInitialCardMarks", "false", "UseCompressedOops", "true"}, + counts = {IRNode.G1_STORE_N_WITH_BARRIER_FLAG, POST_ONLY, "2"}, + phase = CompilePhase.FINAL_CODE) + public static OuterWithFewFields testCloneObjectWithFewFields(OuterWithFewFields o) { + Object o1 = null; + try { + o1 = o.clone(); + } catch (Exception e) {} + return (OuterWithFewFields)o1; + } + + @Test + @IR(applyIf = {"ReduceInitialCardMarks", "true"}, + counts = {IRNode.CALL_OF, "jlong_disjoint_arraycopy", "1"}) + @IR(applyIf = {"ReduceInitialCardMarks", "false"}, + counts = {IRNode.CALL_OF, "G1BarrierSetRuntime::clone", "1"}) + public static OuterWithManyFields testCloneObjectWithManyFields(OuterWithManyFields o) { + Object o1 = null; + try { + o1 = o.clone(); + } catch (Exception e) {} + return (OuterWithManyFields)o1; + } + + @Run(test = {"testCloneArrayOfObjects", + "testCloneObjectWithFewFields", + "testCloneObjectWithManyFields"}) + public void runCloneTests() { + { + Object o1 = new Object(); + Object[] a = new Object[4]; + for (int i = 0; i < 4; i++) { + a[i] = o1; + } + Object[] a1 = testCloneArrayOfObjects(a); + for (int i = 0; i < 4; i++) { + Asserts.assertEquals(o1, a1[i]); + } + } + { + Object a = new Object(); + Object b = new Object(); + OuterWithFewFields o = new OuterWithFewFields(); + o.f1 = a; + o.f2 = b; + OuterWithFewFields o1 = testCloneObjectWithFewFields(o); + Asserts.assertEquals(a, o1.f1); + Asserts.assertEquals(b, o1.f2); + } + { + Object a = new Object(); + Object b = new Object(); + Object c = new Object(); + Object d = new Object(); + Object e = new Object(); + Object f = new Object(); + Object g = new Object(); + Object h = new Object(); + Object i = new Object(); + Object j = new Object(); + OuterWithManyFields o = new OuterWithManyFields(); + o.f1 = a; + o.f2 = b; + o.f3 = c; + o.f4 = d; + o.f5 = e; + o.f6 = f; + o.f7 = g; + o.f8 = h; + o.f9 = i; + o.f10 = j; + OuterWithManyFields o1 = testCloneObjectWithManyFields(o); + Asserts.assertEquals(a, o1.f1); + Asserts.assertEquals(b, o1.f2); + Asserts.assertEquals(c, o1.f3); + Asserts.assertEquals(d, o1.f4); + Asserts.assertEquals(e, o1.f5); + Asserts.assertEquals(f, o1.f6); + Asserts.assertEquals(g, o1.f7); + Asserts.assertEquals(h, o1.f8); + Asserts.assertEquals(i, o1.f9); + Asserts.assertEquals(j, o1.f10); + } + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + static Object testCompareAndExchange(Outer o, Object oldVal, Object newVal) { + return fVarHandle.compareAndExchange(o, oldVal, newVal); + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + static boolean testCompareAndSwap(Outer o, Object oldVal, Object newVal) { + return fVarHandle.compareAndSet(o, oldVal, newVal); + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_GET_AND_SET_P_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_GET_AND_SET_N_WITH_BARRIER_FLAG, PRE_AND_POST, "1"}, + phase = CompilePhase.FINAL_CODE) + static Object testGetAndSet(Outer o, Object newVal) { + return fVarHandle.getAndSet(o, newVal); + } + + @Run(test = {"testCompareAndExchange", + "testCompareAndSwap", + "testGetAndSet"}) + public void runAtomicTests() { + { + Outer o = new Outer(); + Object oldVal = new Object(); + o.f = oldVal; + Object newVal = new Object(); + Object oldVal2 = testCompareAndExchange(o, oldVal, newVal); + Asserts.assertEquals(oldVal, oldVal2); + Asserts.assertEquals(o.f, newVal); + } + { + Outer o = new Outer(); + Object oldVal = new Object(); + o.f = oldVal; + Object newVal = new Object(); + boolean b = testCompareAndSwap(o, oldVal, newVal); + Asserts.assertTrue(b); + Asserts.assertEquals(o.f, newVal); + } + { + Outer o = new Outer(); + Object oldVal = new Object(); + o.f = oldVal; + Object newVal = new Object(); + Object oldVal2 = testGetAndSet(o, newVal); + Asserts.assertEquals(oldVal, oldVal2); + Asserts.assertEquals(o.f, newVal); + } + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_LOAD_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_LOAD_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + static Object testLoadSoftReference(SoftReference ref) { + return ref.get(); + } + + @Test + @IR(applyIf = {"UseCompressedOops", "false"}, + counts = {IRNode.G1_LOAD_P_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + @IR(applyIf = {"UseCompressedOops", "true"}, + counts = {IRNode.G1_LOAD_N_WITH_BARRIER_FLAG, PRE_ONLY, "1"}, + phase = CompilePhase.FINAL_CODE) + static Object testLoadWeakReference(WeakReference ref) { + return ref.get(); + } + + @Run(test = {"testLoadSoftReference", + "testLoadWeakReference"}) + public void runReferenceTests() { + { + Object o1 = new Object(); + SoftReference sref = new SoftReference(o1); + Object o2 = testLoadSoftReference(sref); + Asserts.assertTrue(o2 == o1 || o2 == null); + } + { + Object o1 = new Object(); + WeakReference wref = new WeakReference(o1); + Object o2 = testLoadWeakReference(wref); + Asserts.assertTrue(o2 == o1 || o2 == null); + } + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 16f56012d3dd9..a7c61f710505a 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -358,6 +358,11 @@ public class IRNode { beforeMatchingNameRegex(CALL, "Call.*Java"); } + public static final String CALL_OF = COMPOSITE_PREFIX + "CALL_OF" + POSTFIX; + static { + callOfNodes(CALL_OF, "Call.*"); + } + public static final String CALL_OF_METHOD = COMPOSITE_PREFIX + "CALL_OF_METHOD" + POSTFIX; static { callOfNodes(CALL_OF_METHOD, "Call.*Java"); @@ -581,6 +586,92 @@ public class IRNode { vectorNode(FMA_VD, "FmaVD", TYPE_DOUBLE); } + public static final String G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1CompareAndExchangeN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_COMPARE_AND_EXCHANGE_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1CompareAndExchangeP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_COMPARE_AND_EXCHANGE_P_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1CompareAndSwapN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_COMPARE_AND_SWAP_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1CompareAndSwapP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_COMPARE_AND_SWAP_P_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_ENCODE_P_AND_STORE_N = PREFIX + "G1_ENCODE_P_AND_STORE_N" + POSTFIX; + static { + machOnlyNameRegex(G1_ENCODE_P_AND_STORE_N, "g1EncodePAndStoreN"); + } + + public static final String G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1EncodePAndStoreN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_ENCODE_P_AND_STORE_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_GET_AND_SET_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_GET_AND_SET_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1GetAndSetN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_GET_AND_SET_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_GET_AND_SET_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_GET_AND_SET_P_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1GetAndSetP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_GET_AND_SET_P_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_LOAD_N = PREFIX + "G1_LOAD_N" + POSTFIX; + static { + machOnlyNameRegex(G1_LOAD_N, "g1LoadN"); + } + + public static final String G1_LOAD_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_LOAD_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1LoadN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_LOAD_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_LOAD_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_LOAD_P_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1LoadP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_LOAD_P_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_STORE_N = PREFIX + "G1_STORE_N" + POSTFIX; + static { + machOnlyNameRegex(G1_STORE_N, "g1StoreN"); + } + + public static final String G1_STORE_N_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_STORE_N_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1StoreN\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_STORE_N_WITH_BARRIER_FLAG, regex); + } + + public static final String G1_STORE_P = PREFIX + "G1_STORE_P" + POSTFIX; + static { + machOnlyNameRegex(G1_STORE_P, "g1StoreP"); + } + + public static final String G1_STORE_P_WITH_BARRIER_FLAG = COMPOSITE_PREFIX + "G1_STORE_P_WITH_BARRIER_FLAG" + POSTFIX; + static { + String regex = START + "g1StoreP\\S*" + MID + "barrier\\(\\s*" + IS_REPLACED + "\\s*\\)" + END; + machOnly(G1_STORE_P_WITH_BARRIER_FLAG, regex); + } + public static final String IF = PREFIX + "IF" + POSTFIX; static { beforeMatchingNameRegex(IF, "If\\b"); @@ -852,6 +943,11 @@ public class IRNode { vectorNode(LSHIFT_VL, "LShiftVL", TYPE_LONG); } + public static final String MACH_TEMP = PREFIX + "MACH_TEMP" + POSTFIX; + static { + machOnlyNameRegex(MACH_TEMP, "MachTemp"); + } + public static final String MACRO_LOGIC_V = PREFIX + "MACRO_LOGIC_V" + POSTFIX; static { afterBarrierExpansionToBeforeMatching(MACRO_LOGIC_V, "MacroLogicV"); @@ -1148,6 +1244,12 @@ public class IRNode { trapNodes(NULL_CHECK_TRAP, "null_check"); } + public static final String OOPMAP_WITH = COMPOSITE_PREFIX + "OOPMAP_WITH" + POSTFIX; + static { + String regex = "(#\\s*OopMap\\s*\\{.*" + IS_REPLACED + ".*\\})"; + optoOnly(OOPMAP_WITH, regex); + } + public static final String OR_VB = VECTOR_PREFIX + "OR_VB" + POSTFIX; static { vectorNode(OR_VB, "OrV", TYPE_BYTE); diff --git a/test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java b/test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java new file mode 100644 index 0000000000000..ecd8f58c5ed82 --- /dev/null +++ b/test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.runtime.safepoints; + +import compiler.lib.ir_framework.*; +import java.lang.ref.SoftReference; + +/** + * @test + * @summary Test that undefined values generated by MachTemp nodes (in this + * case, derived from G1 barriers) are not included in OopMaps. + * Extracted from java.lang.invoke.LambdaFormEditor::getInCache. + * @key randomness + * @library /test/lib / + * @requires vm.gc.G1 & vm.bits == 64 & vm.opt.final.UseCompressedOops == true + * @run driver compiler.runtime.safepoints.TestMachTempsAcrossSafepoints + */ + +public class TestMachTempsAcrossSafepoints { + + static class RefWithKey extends SoftReference { + final int key; + + public RefWithKey(int key) { + super(new Object()); + this.key = key; + } + + @DontInline + @Override + public boolean equals(Object obj) { + return obj instanceof RefWithKey that && this.key == that.key; + } + } + + public static void main(String[] args) throws Exception { + String inlineCmd = "-XX:CompileCommand=inline,java.lang.ref.SoftReference::get"; + TestFramework.runWithFlags(inlineCmd, "-XX:+StressGCM", "-XX:+StressLCM", "-XX:StressSeed=1"); + TestFramework.runWithFlags(inlineCmd, "-XX:+StressGCM", "-XX:+StressLCM"); + } + + @Test + @IR(counts = {IRNode.G1_LOAD_N, "1"}, phase = CompilePhase.FINAL_CODE) + @IR(counts = {IRNode.MACH_TEMP, ">= 1"}, phase = CompilePhase.FINAL_CODE) + @IR(counts = {IRNode.STATIC_CALL_OF_METHOD, "equals", "2"}) + @IR(failOn = {IRNode.OOPMAP_WITH, "NarrowOop"}) + static private Object test(RefWithKey key, RefWithKey[] refs) { + RefWithKey k = null; + // This loop causes the register allocator to not "rematerialize" all + // MachTemp nodes generated for the reference g1LoadN instruction below. + for (int i = 0; i < refs.length; i++) { + RefWithKey k0 = refs[0]; + if (k0.equals(key)) { + k = k0; + } + } + if (k != null && !key.equals(k)) { + return null; + } + // The MachTemp node implementing the dst TEMP operand in the g1LoadN + // instruction corresponding to k.get() can be scheduled across the + // above call to RefWithKey::equals(), due to an unfortunate interaction + // of inaccurate basic block frequency estimation (emulated in this test + // by randomizing the GCM and LCM heuristics) and call-catch cleanup. + // Since narrow pointer MachTemp nodes are typed as narrow OOPs, this + // causes the oopmap builder to include the MachTemp node definition in + // the RefWithKey::equals() return oopmap. + return (k != null) ? k.get() : null; + } + + @Run(test = "test") + @Warmup(0) + public void run() { + RefWithKey ref = new RefWithKey(42); + test(ref, new RefWithKey[]{ref}); + } +} diff --git a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java index df4f9063586f4..d62e286c68d58 100644 --- a/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java +++ b/test/hotspot/jtreg/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java @@ -304,7 +304,10 @@ private String[] cmd(long classStart, long classStop) { "-XX:+StressMacroExpansion", "-XX:+StressIncrementalInlining", // StressSeed is uint - "-XX:StressSeed=" + rng.nextInt(Integer.MAX_VALUE))); + "-XX:StressSeed=" + rng.nextInt(Integer.MAX_VALUE), + // Do not fail on huge methods where StressGCM makes register + // allocation allocate lots of memory + "-XX:CompileCommand=memlimit,*.*,0")); for (String arg : CTW_EXTRA_ARGS.split(",")) { Args.add(arg); diff --git a/test/jdk/java/lang/invoke/BigArityTest.java b/test/jdk/java/lang/invoke/BigArityTest.java index 338903f31630d..2dba056a183ab 100644 --- a/test/jdk/java/lang/invoke/BigArityTest.java +++ b/test/jdk/java/lang/invoke/BigArityTest.java @@ -24,7 +24,7 @@ /* @test * @summary High arity invocations * @compile BigArityTest.java - * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -esa -DBigArityTest.ITERATION_COUNT=1 test.java.lang.invoke.BigArityTest + * @run junit/othervm/timeout=2500 -XX:+IgnoreUnrecognizedVMOptions -XX:-VerifyDependencies -XX:CompileCommand=memlimit,*.*,0 -esa -DBigArityTest.ITERATION_COUNT=1 test.java.lang.invoke.BigArityTest */ package test.java.lang.invoke; From 19642bd3833fa96eb4bc7a8a11e902782e0b7844 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Thu, 3 Oct 2024 09:23:46 +0000 Subject: [PATCH 114/188] 8341148: Open source several Choice related tests Reviewed-by: abhiscxk --- .../Choice/ChoiceInLWTest/ChoiceInLWTest.java | 96 +++++++++++++++++++ .../MultiItemSelected_DragOut.java | 74 ++++++++++++++ .../MultiItemSelected_KeySelect.java | 75 +++++++++++++++ .../MultiItemSelected_UpDown.java | 76 +++++++++++++++ .../RepaintAfterRemoveLastItemTest.java | 77 +++++++++++++++ 5 files changed, 398 insertions(+) create mode 100644 test/jdk/java/awt/Choice/ChoiceInLWTest/ChoiceInLWTest.java create mode 100644 test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_DragOut.java create mode 100644 test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_KeySelect.java create mode 100644 test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_UpDown.java create mode 100644 test/jdk/java/awt/Choice/RepaintAfterRemoveLastItemTest/RepaintAfterRemoveLastItemTest.java diff --git a/test/jdk/java/awt/Choice/ChoiceInLWTest/ChoiceInLWTest.java b/test/jdk/java/awt/Choice/ChoiceInLWTest/ChoiceInLWTest.java new file mode 100644 index 0000000000000..9d1ad19549189 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceInLWTest/ChoiceInLWTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4130788 + * @summary Choice components move unexpectedly when in lightweight containers + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ChoiceInLWTest + */ + +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.lang.reflect.InvocationTargetException; + +public class ChoiceInLWTest extends Frame implements Runnable { + private final Choice choices; + static final String INSTRUCTIONS = """ + After test starts wait for two seconds and open a choice. + If choice's popup obscures the label above it press Fail. + Otherwise press Pass. + """; + + public ChoiceInLWTest() { + setLayout(new BorderLayout()); + Container lwCont = new Container(); + lwCont.setLayout(new FlowLayout()); + choices = new Choice(); + choices.add("This is just a token item to get a nice width."); + lwCont.add(choices); + add("Center", lwCont); + Label label = new Label("You should see an unobscured Choice below."); + label.setAlignment(Label.CENTER); + add("North", label); + addChoiceItem(); + addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + super.windowOpened(e); + new Thread(ChoiceInLWTest.this).start(); + } + }); + pack(); + } + + private void addChoiceItem() { + choices.add("Adding an item used to move the Choice!"); + } + + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException ignore) { + } + addChoiceItem(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Choice in LW Container Test") + .testUI(ChoiceInLWTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + + } +} diff --git a/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_DragOut.java b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_DragOut.java new file mode 100644 index 0000000000000..aed1543774575 --- /dev/null +++ b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_DragOut.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6367251 + * @summary 2 items are highlighted when pressing, dragging the mouse inside the choice, XToolkit + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiItemSelected_DragOut + */ + +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; + +public class MultiItemSelected_DragOut extends Frame { + static final String INSTRUCTIONS = """ + 1) Open Choice. + 2) Start drag from first item to second or third one. + 3) Without releasing left mouse button + press and release right mouse button. + 4) Release left mouse button. + 5) Open choice again. + 6) If there is only one selection cursor + in the dropdown list press Pass otherwise press Fail. + """; + + public MultiItemSelected_DragOut() { + Choice choice = new Choice(); + + for (int i = 1; i < 10; i++) { + choice.add("item " + i); + } + add(choice); + choice.addItemListener(ie -> System.out.println(ie)); + + setLayout(new FlowLayout()); + setSize(200, 200); + validate(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("MultiItemSelected Drag Out Test") + .testUI(MultiItemSelected_DragOut::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_KeySelect.java b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_KeySelect.java new file mode 100644 index 0000000000000..9e930f9923b81 --- /dev/null +++ b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_KeySelect.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6367251 + * @summary 2 items are highlighted when dragging inside and press ESC or ENTER + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiItemSelected_KeySelect + */ + +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; + +public class MultiItemSelected_KeySelect extends Frame { + static final String INSTRUCTIONS = """ + 1) Open Choice. + 2) Start drag from first item to another one. + 3) Without releasing the mouse button press ESC key. + 4) Open choice again. + 5) Verify that there is only one + selection cursor in the dropdown list. + 6) Repeat steps 2-5 once again but this time + press ENTER key instead of ESC. + 7) If in both scenarios there is only one selection cursor + press Pass otherwise press Fail. + """; + + public MultiItemSelected_KeySelect() { + Choice choice = new Choice(); + + for (int i = 1; i < 10; i++) { + choice.add("item " + i); + } + add(choice); + choice.addItemListener(ie -> System.out.println(ie)); + setLayout(new FlowLayout()); + setSize(200, 200); + validate(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("MultiItemSelected Key Select Test") + .testUI(MultiItemSelected_KeySelect::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_UpDown.java b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_UpDown.java new file mode 100644 index 0000000000000..5904d98a9081f --- /dev/null +++ b/test/jdk/java/awt/Choice/MultiItemSelected/MultiItemSelected_UpDown.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6367251 + * @summary 2 items are highlighted when dragging outside and press UP or DOWN + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MultiItemSelected_UpDown + */ + +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.lang.reflect.InvocationTargetException; + +public class MultiItemSelected_UpDown extends Frame { + static final String INSTRUCTIONS = """ + 1) Open Choice. + 2) Start drag from first item to another one. + 3) Without interrupting drag + move mouse cursor outside the choice popup. + 4) Press UP, DOWN key several times to position + selection cursor to a different item. + 5) Release mouse button. + 6) If popup is closed upon mouse button release open Choice again. + 7) Verify that there is only one + selection cursor in the dropdown list. + 8) If true then press Pass, otherwise press Fail. + """; + + public MultiItemSelected_UpDown() { + Choice choice = new Choice(); + + for (int i = 1; i < 20; i++) { + choice.add(" item " + i); + } + add(choice); + choice.addItemListener(ie -> System.out.println(ie)); + setLayout(new FlowLayout()); + setSize(200, 200); + validate(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("MultiItemSelected Up/Down Test") + .testUI(MultiItemSelected_UpDown::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Choice/RepaintAfterRemoveLastItemTest/RepaintAfterRemoveLastItemTest.java b/test/jdk/java/awt/Choice/RepaintAfterRemoveLastItemTest/RepaintAfterRemoveLastItemTest.java new file mode 100644 index 0000000000000..20acc66b6bda1 --- /dev/null +++ b/test/jdk/java/awt/Choice/RepaintAfterRemoveLastItemTest/RepaintAfterRemoveLastItemTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6292186 + * @summary Choice is not refreshed properly when the last item gets removed + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RepaintAfterRemoveLastItemTest + */ + +import java.awt.Button; +import java.awt.Choice; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.lang.reflect.InvocationTargetException; + +public class RepaintAfterRemoveLastItemTest extends Frame implements ActionListener { + Choice ch = new Choice(); + + static final String INSTRUCTIONS = """ + Press on the 'remove' button after that if the choice does not display + 'only item' press Pass. If 'only item' is still displayed press Fail. + """; + + public RepaintAfterRemoveLastItemTest() { + ch.add("only item"); + add(ch); + + Button b = new Button("remove"); + add(b); + b.addActionListener(this); + setLayout(new FlowLayout()); + setSize(200, 200); + validate(); + } + + public void actionPerformed(ActionEvent ae) { + if (ch.getItemCount() != 0) { + ch.remove(0); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Repaint After Remove Test") + .testUI(RepaintAfterRemoveLastItemTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} From 6af13580c2086afefde489275bc2353c2320ff3f Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Thu, 3 Oct 2024 12:02:24 +0000 Subject: [PATCH 115/188] 8337753: Target class of upcall stub may be unloaded Reviewed-by: amitkumar, vlivanov, mdoerr --- .../cpu/aarch64/stubGenerator_aarch64.cpp | 23 +++++ .../cpu/aarch64/upcallLinker_aarch64.cpp | 16 ++- src/hotspot/cpu/arm/upcallLinker_arm.cpp | 2 +- src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 25 +++++ src/hotspot/cpu/ppc/upcallLinker_ppc.cpp | 18 ++-- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 24 +++++ src/hotspot/cpu/riscv/upcallLinker_riscv.cpp | 16 ++- src/hotspot/cpu/s390/stubGenerator_s390.cpp | 24 +++++ src/hotspot/cpu/s390/upcallLinker_s390.cpp | 17 ++-- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 24 +++++ src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 1 + src/hotspot/cpu/x86/upcallLinker_x86_32.cpp | 2 +- src/hotspot/cpu/x86/upcallLinker_x86_64.cpp | 19 ++-- src/hotspot/cpu/zero/upcallLinker_zero.cpp | 2 +- src/hotspot/share/code/codeBlob.cpp | 8 +- src/hotspot/share/prims/upcallLinker.cpp | 35 +++---- src/hotspot/share/prims/upcallLinker.hpp | 4 +- src/hotspot/share/runtime/frame.cpp | 17 +++- src/hotspot/share/runtime/frame.hpp | 1 + src/hotspot/share/runtime/stubRoutines.cpp | 1 + src/hotspot/share/runtime/stubRoutines.hpp | 6 ++ test/jdk/TEST.groups | 3 +- test/jdk/java/foreign/TestUpcallStress.java | 97 +++++++++++++++++++ 23 files changed, 307 insertions(+), 78 deletions(-) create mode 100644 test/jdk/java/foreign/TestUpcallStress.java diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index eb235f8472c1d..31116e006f025 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -7320,6 +7320,28 @@ class StubGenerator: public StubCodeGenerator { return start; } + // load Method* target of MethodHandle + // j_rarg0 = jobject receiver + // rmethod = result + address generate_upcall_stub_load_target() { + StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target"); + address start = __ pc(); + + __ resolve_global_jobject(j_rarg0, rscratch1, rscratch2); + // Load target method from receiver + __ load_heap_oop(rmethod, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), rscratch1, rscratch2); + __ load_heap_oop(rmethod, Address(rmethod, java_lang_invoke_LambdaForm::vmentry_offset()), rscratch1, rscratch2); + __ load_heap_oop(rmethod, Address(rmethod, java_lang_invoke_MemberName::method_offset()), rscratch1, rscratch2); + __ access_load_at(T_ADDRESS, IN_HEAP, rmethod, + Address(rmethod, java_lang_invoke_ResolvedMethodName::vmtarget_offset()), + noreg, noreg); + __ str(rmethod, Address(rthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized + + __ ret(lr); + + return start; + } + #undef __ #define __ masm-> @@ -8241,6 +8263,7 @@ class StubGenerator: public StubCodeGenerator { #endif StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); StubRoutines::aarch64::set_completed(); // Inidicate that arraycopy and zero_blocks stubs are generated } diff --git a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp index 28ec07815be5c..517fccb2d1aa5 100644 --- a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "classfile/javaClasses.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "prims/upcallLinker.hpp" @@ -117,7 +118,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, @@ -222,7 +223,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ lea(c_rarg0, Address(sp, frame_data_offset)); - __ movptr(c_rarg1, (intptr_t)receiver); __ movptr(rscratch1, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry)); __ blr(rscratch1); __ mov(rthread, r0); @@ -238,12 +238,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0); __ block_comment("} argument shuffle"); - __ block_comment("{ receiver "); - __ get_vm_result(j_rarg0, rthread); - __ block_comment("} receiver "); - - __ mov_metadata(rmethod, entry); - __ str(rmethod, Address(rthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized + __ block_comment("{ load target "); + __ movptr(j_rarg0, (intptr_t)receiver); + __ far_call(RuntimeAddress(StubRoutines::upcall_stub_load_target()), rscratch1); // puts target Method* in rmethod + __ block_comment("} load target "); __ push_cont_fastpath(rthread); @@ -318,7 +316,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, #ifndef PRODUCT stringStream ss; - ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + ss.print("upcall_stub_%s", signature->as_C_string()); const char* name = _masm->code_string(ss.as_string()); #else // PRODUCT const char* name = "upcall_stub"; diff --git a/src/hotspot/cpu/arm/upcallLinker_arm.cpp b/src/hotspot/cpu/arm/upcallLinker_arm.cpp index c7645f4a03351..696b2001e6b7b 100644 --- a/src/hotspot/cpu/arm/upcallLinker_arm.cpp +++ b/src/hotspot/cpu/arm/upcallLinker_arm.cpp @@ -25,7 +25,7 @@ #include "prims/upcallLinker.hpp" #include "utilities/debug.hpp" -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index ee3f1911e2082..206c161287fa2 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -4587,6 +4587,30 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { return start; } + // load Method* target of MethodHandle + // R3_ARG1 = jobject receiver + // R19_method = result Method* + address generate_upcall_stub_load_target() { + + StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target"); + address start = __ pc(); + + __ resolve_global_jobject(R3_ARG1, R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS); + // Load target method from receiver + __ load_heap_oop(R19_method, java_lang_invoke_MethodHandle::form_offset(), R3_ARG1, + R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL); + __ load_heap_oop(R19_method, java_lang_invoke_LambdaForm::vmentry_offset(), R19_method, + R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL); + __ load_heap_oop(R19_method, java_lang_invoke_MemberName::method_offset(), R19_method, + R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL); + __ ld(R19_method, java_lang_invoke_ResolvedMethodName::vmtarget_offset(), R19_method); + __ std(R19_method, in_bytes(JavaThread::callee_target_offset()), R16_thread); // just in case callee is deoptimized + + __ blr(); + + return start; + } + // Initialization void generate_initial_stubs() { // Generates all stubs and initializes the entry points @@ -4651,6 +4675,7 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { } StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); } void generate_compiler_stubs() { diff --git a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp index b60fd4f16d163..635bab900d157 100644 --- a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp +++ b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "classfile/javaClasses.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "prims/upcallLinker.hpp" @@ -118,7 +119,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; // arg save & restore + move -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, @@ -221,7 +222,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry), R0); __ addi(R3_ARG1, R1_SP, frame_data_offset); - __ load_const_optimized(R4_ARG2, (intptr_t)receiver, R0); __ call_c(call_target_address); __ mr(R16_thread, R3_RET); __ block_comment("} on_entry"); @@ -236,12 +236,12 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, arg_shuffle.generate(_masm, as_VMStorage(callerSP), frame::native_abi_minframe_size, frame::jit_out_preserve_size); __ block_comment("} argument shuffle"); - __ block_comment("{ receiver "); - __ get_vm_result(R3_ARG1); - __ block_comment("} receiver "); - - __ load_const_optimized(R19_method, (intptr_t)entry); - __ std(R19_method, in_bytes(JavaThread::callee_target_offset()), R16_thread); + __ block_comment("{ load target "); + __ load_const_optimized(call_target_address, StubRoutines::upcall_stub_load_target(), R0); + __ load_const_optimized(R3_ARG1, (intptr_t)receiver, R0); + __ mtctr(call_target_address); + __ bctrl(); // loads target Method* into R19_method + __ block_comment("} load target "); __ push_cont_fastpath(); @@ -326,7 +326,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, #ifndef PRODUCT stringStream ss; - ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + ss.print("upcall_stub_%s", signature->as_C_string()); const char* name = _masm->code_string(ss.as_string()); #else // PRODUCT const char* name = "upcall_stub"; diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 5970111088fd1..8bf3ac5c90163 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -6124,6 +6124,29 @@ static const int64_t right_3_bits = right_n_bits(3); return start; } + // load Method* target of MethodHandle + // j_rarg0 = jobject receiver + // xmethod = Method* result + address generate_upcall_stub_load_target() { + + StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target"); + address start = __ pc(); + + __ resolve_global_jobject(j_rarg0, t0, t1); + // Load target method from receiver + __ load_heap_oop(xmethod, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), t0, t1); + __ load_heap_oop(xmethod, Address(xmethod, java_lang_invoke_LambdaForm::vmentry_offset()), t0, t1); + __ load_heap_oop(xmethod, Address(xmethod, java_lang_invoke_MemberName::method_offset()), t0, t1); + __ access_load_at(T_ADDRESS, IN_HEAP, xmethod, + Address(xmethod, java_lang_invoke_ResolvedMethodName::vmtarget_offset()), + noreg, noreg); + __ sd(xmethod, Address(xthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized + + __ ret(); + + return start; + } + #undef __ // Initialization @@ -6189,6 +6212,7 @@ static const int64_t right_3_bits = right_n_bits(3); #endif // COMPILER2 StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); StubRoutines::riscv::set_completed(); } diff --git a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp index 383f332f8fd94..55160be99d0d8 100644 --- a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp +++ b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "classfile/javaClasses.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "prims/upcallLinker.hpp" @@ -117,7 +118,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, @@ -223,7 +224,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ la(c_rarg0, Address(sp, frame_data_offset)); - __ movptr(c_rarg1, (address) receiver); __ rt_call(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry)); __ mv(xthread, x10); __ reinit_heapbase(); @@ -260,12 +260,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0); __ block_comment("} argument shuffle"); - __ block_comment("{ receiver "); - __ get_vm_result(j_rarg0, xthread); - __ block_comment("} receiver "); - - __ mov_metadata(xmethod, entry); - __ sd(xmethod, Address(xthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized + __ block_comment("{ load target "); + __ movptr(j_rarg0, (address) receiver); + __ far_call(RuntimeAddress(StubRoutines::upcall_stub_load_target())); // loads Method* into xmethod + __ block_comment("} load target "); __ push_cont_fastpath(xthread); @@ -338,7 +336,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, #ifndef PRODUCT stringStream ss; - ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + ss.print("upcall_stub_%s", signature->as_C_string()); const char *name = _masm->code_string(ss.as_string()); #else // PRODUCT const char* name = "upcall_stub"; diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index d878731cca51f..dd9ed4c95462b 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -3053,6 +3053,29 @@ class StubGenerator: public StubCodeGenerator { return start; } + // load Method* target of MethodHandle + // Z_ARG1 = jobject receiver + // Z_method = Method* result + address generate_upcall_stub_load_target() { + StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target"); + address start = __ pc(); + + __ resolve_global_jobject(Z_ARG1, Z_tmp_1, Z_tmp_2); + // Load target method from receiver + __ load_heap_oop(Z_method, Address(Z_ARG1, java_lang_invoke_MethodHandle::form_offset()), + noreg, noreg, IS_NOT_NULL); + __ load_heap_oop(Z_method, Address(Z_method, java_lang_invoke_LambdaForm::vmentry_offset()), + noreg, noreg, IS_NOT_NULL); + __ load_heap_oop(Z_method, Address(Z_method, java_lang_invoke_MemberName::method_offset()), + noreg, noreg, IS_NOT_NULL); + __ z_lg(Z_method, Address(Z_method, java_lang_invoke_ResolvedMethodName::vmtarget_offset())); + __ z_stg(Z_method, Address(Z_thread, JavaThread::callee_target_offset())); // just in case callee is deoptimized + + __ z_br(Z_R14); + + return start; + } + void generate_initial_stubs() { // Generates all stubs and initializes the entry points. @@ -3110,6 +3133,7 @@ class StubGenerator: public StubCodeGenerator { } StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); } void generate_compiler_stubs() { diff --git a/src/hotspot/cpu/s390/upcallLinker_s390.cpp b/src/hotspot/cpu/s390/upcallLinker_s390.cpp index 734b4e89c7cb2..8baad40a519a4 100644 --- a/src/hotspot/cpu/s390/upcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/upcallLinker_s390.cpp @@ -23,6 +23,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "classfile/javaClasses.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" #include "prims/upcallLinker.hpp" @@ -116,7 +117,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; // arg save & restore + move -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, @@ -206,7 +207,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("on_entry {"); __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry)); __ z_aghik(Z_ARG1, Z_SP, frame_data_offset); - __ load_const_optimized(Z_ARG2, (intptr_t)receiver); __ call(call_target_address); __ z_lgr(Z_thread, Z_RET); __ block_comment("} on_entry"); @@ -216,12 +216,11 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, arg_shuffle.generate(_masm, shuffle_reg, abi._shadow_space_bytes, frame::z_jit_out_preserve_size); __ block_comment("} argument_shuffle"); - __ block_comment("receiver {"); - __ get_vm_result(Z_ARG1); - __ block_comment("} receiver"); - - __ load_const_optimized(Z_method, (intptr_t)entry); - __ z_stg(Z_method, Address(Z_thread, in_bytes(JavaThread::callee_target_offset()))); + __ block_comment("load_target {"); + __ load_const_optimized(Z_ARG1, (intptr_t)receiver); + __ load_const_optimized(call_target_address, StubRoutines::upcall_stub_load_target()); + __ call(call_target_address); // load taget Method* into Z_method + __ block_comment("} load_target"); __ z_lg(call_target_address, Address(Z_method, in_bytes(Method::from_compiled_offset()))); __ call(call_target_address); @@ -274,7 +273,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, #ifndef PRODUCT stringStream ss; - ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + ss.print("upcall_stub_%s", signature->as_C_string()); const char* name = _masm->code_string(ss.as_string()); #else // PRODUCT const char* name = "upcall_stub"; diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 4f37dc31d0305..835bfc770fe90 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" +#include "classfile/javaClasses.hpp" #include "classfile/vmIntrinsics.hpp" #include "compiler/oopMap.hpp" #include "gc/shared/barrierSet.hpp" @@ -3796,6 +3797,28 @@ address StubGenerator::generate_upcall_stub_exception_handler() { return start; } +// load Method* target of MethodHandle +// j_rarg0 = jobject receiver +// rbx = result +address StubGenerator::generate_upcall_stub_load_target() { + StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target"); + address start = __ pc(); + + __ resolve_global_jobject(j_rarg0, r15_thread, rscratch1); + // Load target method from receiver + __ load_heap_oop(rbx, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), rscratch1); + __ load_heap_oop(rbx, Address(rbx, java_lang_invoke_LambdaForm::vmentry_offset()), rscratch1); + __ load_heap_oop(rbx, Address(rbx, java_lang_invoke_MemberName::method_offset()), rscratch1); + __ access_load_at(T_ADDRESS, IN_HEAP, rbx, + Address(rbx, java_lang_invoke_ResolvedMethodName::vmtarget_offset()), + noreg, noreg); + __ movptr(Address(r15_thread, JavaThread::callee_target_offset()), rbx); // just in case callee is deoptimized + + __ ret(0); + + return start; +} + address StubGenerator::generate_lookup_secondary_supers_table_stub(u1 super_klass_index) { StubCodeMark mark(this, "StubRoutines", "lookup_secondary_supers_table"); @@ -3955,6 +3978,7 @@ void StubGenerator::generate_final_stubs() { } StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target(); } void StubGenerator::generate_compiler_stubs() { diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 71777fbfffea2..7280e9fbe957e 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -620,6 +620,7 @@ class StubGenerator: public StubCodeGenerator { // shared exception handler for FFM upcall stubs address generate_upcall_stub_exception_handler(); + address generate_upcall_stub_load_target(); // Specialized stub implementations for UseSecondarySupersTable. address generate_lookup_secondary_supers_table_stub(u1 super_klass_index); diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp index e5075e180d9d6..d795c751d02b5 100644 --- a/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp +++ b/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "prims/upcallLinker.hpp" -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp index 82179f9022e92..bc261bfd93f44 100644 --- a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp @@ -23,7 +23,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" -#include "code/codeBlob.hpp" +#include "classfile/javaClasses.hpp" #include "code/codeBlob.hpp" #include "code/vmreg.inline.hpp" #include "compiler/disassembler.hpp" @@ -169,10 +169,10 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr __ block_comment("} restore_callee_saved_regs "); } -static const int upcall_stub_code_base_size = 1024; +static const int upcall_stub_code_base_size = 1200; static const int upcall_stub_size_per_arg = 16; -address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, +address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, @@ -281,7 +281,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ vzeroupper(); __ lea(c_rarg0, Address(rsp, frame_data_offset)); - __ movptr(c_rarg1, (intptr_t)receiver); // stack already aligned __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry))); __ movptr(r15_thread, rax); @@ -297,12 +296,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, arg_shuffle.generate(_masm, shuffle_reg, abi._shadow_space_bytes, 0); __ block_comment("} argument shuffle"); - __ block_comment("{ receiver "); - __ get_vm_result(j_rarg0, r15_thread); - __ block_comment("} receiver "); - - __ mov_metadata(rbx, entry); - __ movptr(Address(r15_thread, JavaThread::callee_target_offset()), rbx); // just in case callee is deoptimized + __ block_comment("{ load target "); + __ movptr(j_rarg0, (intptr_t)receiver); + __ call(RuntimeAddress(StubRoutines::upcall_stub_load_target())); // puts target Method* in rbx + __ block_comment("} load target "); __ push_cont_fastpath(); @@ -377,7 +374,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, #ifndef PRODUCT stringStream ss; - ss.print("upcall_stub_%s", entry->signature()->as_C_string()); + ss.print("upcall_stub_%s", signature->as_C_string()); const char* name = _masm->code_string(ss.freeze()); #else // PRODUCT const char* name = "upcall_stub"; diff --git a/src/hotspot/cpu/zero/upcallLinker_zero.cpp b/src/hotspot/cpu/zero/upcallLinker_zero.cpp index 6447dac86c915..408ebc328205d 100644 --- a/src/hotspot/cpu/zero/upcallLinker_zero.cpp +++ b/src/hotspot/cpu/zero/upcallLinker_zero.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "prims/upcallLinker.hpp" -address UpcallLinker::make_upcall_stub(jobject mh, Method* entry, +address UpcallLinker::make_upcall_stub(jobject mh, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 81c4d001078cb..23f621ffec832 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -41,7 +41,7 @@ #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/javaFrameAnchor.hpp" -#include "runtime/jniHandles.hpp" +#include "runtime/jniHandles.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/sharedRuntime.hpp" @@ -623,7 +623,7 @@ UpcallStub* UpcallStub::create(const char* name, CodeBuffer* cb, jobject receive // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); - trace_new_stub(blob, "UpcallStub"); + trace_new_stub(blob, "UpcallStub - ", name); return blob; } @@ -772,6 +772,10 @@ void UpcallStub::verify() { void UpcallStub::print_on(outputStream* st) const { RuntimeBlob::print_on(st); print_value_on(st); + st->print_cr("Frame data offset: %d", (int) _frame_data_offset); + oop recv = JNIHandles::resolve(_receiver); + st->print("Receiver MH="); + recv->print_on(st); Disassembler::decode((RuntimeBlob*)this, st); } diff --git a/src/hotspot/share/prims/upcallLinker.cpp b/src/hotspot/share/prims/upcallLinker.cpp index b02746911a808..1abce57652a9f 100644 --- a/src/hotspot/share/prims/upcallLinker.cpp +++ b/src/hotspot/share/prims/upcallLinker.cpp @@ -22,7 +22,7 @@ */ #include "precompiled.hpp" -#include "classfile/javaClasses.hpp" +#include "classfile/javaClasses.inline.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "compiler/compilationPolicy.hpp" @@ -73,7 +73,7 @@ JavaThread* UpcallLinker::maybe_attach_and_get_thread() { } // modelled after JavaCallWrapper::JavaCallWrapper -JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context, jobject receiver) { +JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context) { JavaThread* thread = maybe_attach_and_get_thread(); guarantee(thread->thread_state() == _thread_in_native, "wrong thread state for upcall"); context->thread = thread; @@ -108,8 +108,6 @@ JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context, jobject recei debug_only(thread->inc_java_call_counter()); thread->set_active_handles(context->new_handles); // install new handle block and reset Java frame linkage - thread->set_vm_result(JNIHandles::resolve(receiver)); - return thread; } @@ -138,11 +136,10 @@ void UpcallLinker::on_exit(UpcallStub::FrameData* context) { } void UpcallLinker::handle_uncaught_exception(oop exception) { - ResourceMark rm; - // Based on CATCH macro tty->print_cr("Uncaught exception:"); - exception->print(); - ShouldNotReachHere(); + Handle exception_h(Thread::current(), exception); + java_lang_Throwable::print_stack_trace(exception_h, tty); + fatal("Unrecoverable uncaught exception encountered"); } JVM_ENTRY(jlong, UL_MakeUpcallStub(JNIEnv *env, jclass unused, jobject mh, jobject abi, jobject conv, @@ -150,36 +147,30 @@ JVM_ENTRY(jlong, UL_MakeUpcallStub(JNIEnv *env, jclass unused, jobject mh, jobje ResourceMark rm(THREAD); Handle mh_h(THREAD, JNIHandles::resolve(mh)); jobject mh_j = JNIHandles::make_global(mh_h); + oop type = java_lang_invoke_MethodHandle::type(mh_h()); - oop lform = java_lang_invoke_MethodHandle::form(mh_h()); - oop vmentry = java_lang_invoke_LambdaForm::vmentry(lform); - Method* entry = java_lang_invoke_MemberName::vmtarget(vmentry); - const methodHandle mh_entry(THREAD, entry); - - assert(entry->method_holder()->is_initialized(), "no clinit barrier"); - CompilationPolicy::compile_if_required(mh_entry, CHECK_0); - - assert(entry->is_static(), "static only"); // Fill in the signature array, for the calling-convention call. - const int total_out_args = entry->size_of_parameters(); - assert(total_out_args > 0, "receiver arg"); + const int total_out_args = java_lang_invoke_MethodType::ptype_slot_count(type) + 1; // +1 for receiver + bool create_new = true; + TempNewSymbol signature = java_lang_invoke_MethodType::as_signature(type, create_new); BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_out_args); BasicType ret_type; { int i = 0; - SignatureStream ss(entry->signature()); + out_sig_bt[i++] = T_OBJECT; // receiver MH + SignatureStream ss(signature); for (; !ss.at_return_type(); ss.next()) { out_sig_bt[i++] = ss.type(); // Collect remaining bits of signature if (ss.type() == T_LONG || ss.type() == T_DOUBLE) out_sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots } - assert(i == total_out_args, ""); + assert(i == total_out_args, "%d != %d", i, total_out_args); ret_type = ss.type(); } return (jlong) UpcallLinker::make_upcall_stub( - mh_j, entry, out_sig_bt, total_out_args, ret_type, + mh_j, signature, out_sig_bt, total_out_args, ret_type, abi, conv, needs_return_buffer, checked_cast(ret_buf_size)); JVM_END diff --git a/src/hotspot/share/prims/upcallLinker.hpp b/src/hotspot/share/prims/upcallLinker.hpp index d80516b256678..765ed63fc5a56 100644 --- a/src/hotspot/share/prims/upcallLinker.hpp +++ b/src/hotspot/share/prims/upcallLinker.hpp @@ -34,10 +34,10 @@ class UpcallLinker { private: static JavaThread* maybe_attach_and_get_thread(); - static JavaThread* on_entry(UpcallStub::FrameData* context, jobject receiver); + static JavaThread* on_entry(UpcallStub::FrameData* context); static void on_exit(UpcallStub::FrameData* context); public: - static address make_upcall_stub(jobject mh, Method* entry, + static address make_upcall_stub(jobject mh, Symbol* signature, BasicType* out_sig_bt, int total_out_args, BasicType ret_type, jobject jabi, jobject jconv, diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index e193271eff658..17078a69ab991 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -719,6 +719,8 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose st->print("v ~MethodHandlesAdapterBlob " PTR_FORMAT, p2i(pc())); } else if (_cb->is_uncommon_trap_stub()) { st->print("v ~UncommonTrapBlob " PTR_FORMAT, p2i(pc())); + } else if (_cb->is_upcall_stub()) { + st->print("v ~UpcallStub::%s " PTR_FORMAT, _cb->name(), p2i(pc())); } else { st->print("v blob " PTR_FORMAT, p2i(pc())); } @@ -1116,6 +1118,19 @@ void frame::oops_entry_do(OopClosure* f, const RegisterMap* map) const { entry_frame_call_wrapper()->oops_do(f); } +void frame::oops_upcall_do(OopClosure* f, const RegisterMap* map) const { + assert(map != nullptr, "map must be set"); + if (map->include_argument_oops()) { + // Upcall stubs call a MethodHandle impl method of which only the receiver + // is ever an oop. + // Currently we should not be able to get here, since there are no + // safepoints in the one resolve stub we can get into (handle_wrong_method) + // Leave this here as a trap in case we ever do: + ShouldNotReachHere(); // not implemented + } + _cb->as_upcall_stub()->oops_do(f, *this); +} + bool frame::is_deoptimized_frame() const { assert(_deopt_state != unknown, "not answerable"); if (_deopt_state == is_deoptimized) { @@ -1147,7 +1162,7 @@ void frame::oops_do_internal(OopClosure* f, NMethodClosure* cf, } else if (is_entry_frame()) { oops_entry_do(f, map); } else if (is_upcall_stub_frame()) { - _cb->as_upcall_stub()->oops_do(f, *this); + oops_upcall_do(f, map); } else if (CodeCache::contains(pc())) { oops_nmethod_do(f, cf, df, derived_mode, map); } else { diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index 1c57e3de4daa6..50aafce3837ac 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.hpp @@ -464,6 +464,7 @@ class frame { const RegisterMap* map, bool use_interpreter_oop_map_cache) const; void oops_entry_do(OopClosure* f, const RegisterMap* map) const; + void oops_upcall_do(OopClosure* f, const RegisterMap* map) const; void oops_nmethod_do(OopClosure* f, NMethodClosure* cf, DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, const RegisterMap* map) const; diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index a2b8c1da64490..331aa3c73641f 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -188,6 +188,7 @@ address StubRoutines::_cont_returnBarrier = nullptr; address StubRoutines::_cont_returnBarrierExc = nullptr; address StubRoutines::_upcall_stub_exception_handler = nullptr; +address StubRoutines::_upcall_stub_load_target = nullptr; address StubRoutines::_lookup_secondary_supers_table_slow_path_stub = nullptr; address StubRoutines::_lookup_secondary_supers_table_stubs[Klass::SECONDARY_SUPERS_TABLE_SIZE] = { nullptr }; diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index b58c591bbf75c..be9577d542f67 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -298,6 +298,7 @@ class StubRoutines: AllStatic { static address _vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP]; static address _upcall_stub_exception_handler; + static address _upcall_stub_load_target; static address _lookup_secondary_supers_table_stubs[]; static address _lookup_secondary_supers_table_slow_path_stub; @@ -506,6 +507,11 @@ class StubRoutines: AllStatic { return _upcall_stub_exception_handler; } + static address upcall_stub_load_target() { + assert(_upcall_stub_load_target != nullptr, "not implemented"); + return _upcall_stub_load_target; + } + static address lookup_secondary_supers_table_stub(u1 slot) { assert(slot < Klass::SECONDARY_SUPERS_TABLE_SIZE, "out of bounds"); assert(_lookup_secondary_supers_table_stubs[slot] != nullptr, "not implemented"); diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 0c6b13fdca057..d51fcec733b3c 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -381,7 +381,8 @@ jdk_svc = \ jdk_foreign = \ java/foreign \ jdk/internal/reflect/CallerSensitive/CheckCSMs.java \ - -java/foreign/TestMatrix.java + -java/foreign/TestMatrix.java \ + -java/foreign/TestUpcallStress.java jdk_vector = \ jdk/incubator/vector diff --git a/test/jdk/java/foreign/TestUpcallStress.java b/test/jdk/java/foreign/TestUpcallStress.java new file mode 100644 index 0000000000000..4060774685641 --- /dev/null +++ b/test/jdk/java/foreign/TestUpcallStress.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @requires jdk.foreign.linker != "FALLBACK" + * @requires (os.arch == "aarch64" | os.arch=="riscv64") & os.name == "Linux" + * @requires os.maxMemory > 4G + * @modules java.base/jdk.internal.foreign + * @build NativeTestHelper CallGeneratorHelper TestUpcallBase + * @bug 8337753 + * + * @run testng/othervm/timeout=3200 + * -Xcheck:jni + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:-VerifyDependencies + * --enable-native-access=ALL-UNNAMED + * -Dgenerator.sample.factor=17 + * TestUpcallStress + */ + +import java.lang.foreign.Arena; +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.MemorySegment; + +import org.testng.annotations.Test; + +import java.lang.invoke.MethodHandle; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.*; +import java.util.function.Consumer; + +public class TestUpcallStress extends TestUpcallBase { + + static { + System.loadLibrary("TestUpcall"); + } + + @Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class) + public void testUpcallsStress(int count, String fName, Ret ret, List paramTypes, + List fields) throws Throwable { + ExecutorService executor = Executors.newFixedThreadPool(16); + for (int threadIdx = 0; threadIdx < 16; threadIdx++) { + executor.submit(() -> { + for (int iter = 0; iter < 10000; iter++) { + List> returnChecks = new ArrayList<>(); + List> argChecks = new ArrayList<>(); + MemorySegment addr = findNativeOrThrow(fName); + try (Arena arena = Arena.ofConfined()) { + FunctionDescriptor descriptor = function(ret, paramTypes, fields); + MethodHandle mh = downcallHandle(LINKER, addr, arena, descriptor); + AtomicReference capturedArgs = new AtomicReference<>(); + Object[] args = makeArgs(capturedArgs, arena, descriptor, returnChecks, argChecks, 0); + + Object res = mh.invokeWithArguments(args); + + if (ret == Ret.NON_VOID) { + returnChecks.forEach(c -> c.accept(res)); + } + + Object[] capturedArgsArr = capturedArgs.get(); + for (int i = 0; i < capturedArgsArr.length; i++) { + argChecks.get(i).accept(capturedArgsArr[i]); + } + } catch (Throwable ex) { + throw new AssertionError(ex); + } + } + }); + } + // This shutdownNow is 'wrong', since it doesn't wait for tasks to terminate, + // but it seems to be the only way to reproduce the race of JDK-8337753 + executor.shutdownNow(); + } +} From d7f32d891cde2278fe7158fb28d29235db5c818c Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 3 Oct 2024 12:08:23 +0000 Subject: [PATCH 116/188] 8341415: Optimize RawBytecodeHelper::next Reviewed-by: liach --- .../classfile/impl/RawBytecodeHelper.java | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java index 2403ae150e9dd..659f41f9699ae 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java @@ -299,7 +299,6 @@ public static int align(int n) { private int nextBci; private int bci; private int opcode; - private boolean isWide; public static CodeRange of(byte[] array) { return new CodeRange(array, array.length); @@ -341,14 +340,14 @@ public void reset(int nextBci) { * be valid and can be accessed unchecked. */ public int opcode() { - return opcode; + return opcode & 0xFF; } /** * Returns whether the current functional opcode is in wide. */ public boolean isWide() { - return isWide; + return (opcode & (WIDE << 8)) != 0; } /** @@ -411,7 +410,7 @@ public int destW() { // *load, *store, iinc public int getIndex() { - return isWide ? getU2Unchecked(bci + 2) : getIndexU1(); + return isWide() ? getU2Unchecked(bci + 2) : getIndexU1(); } // ldc @@ -443,12 +442,11 @@ public boolean next() { int len = LENGTHS[code & 0xFF]; // & 0xFF eliminates bound check this.bci = bci; opcode = code; - isWide = false; if (len <= 0) { len = checkSpecialInstruction(bci, end, code); // sets opcode } - if (len <= 0 || (nextBci += len) > end) { + if ((nextBci += len) > end) { opcode = ILLEGAL; } @@ -457,37 +455,34 @@ public boolean next() { // Put rarely used code in another method to reduce code size private int checkSpecialInstruction(int bci, int end, int code) { + int len = -1; if (code == WIDE) { - if (bci + 1 >= end) { - return -1; + if (bci + 1 < end) { + opcode = (WIDE << 8) | (code = getIndexU1()); + // Validated in UtilTest.testOpcodeLengthTable + len = LENGTHS[code] * 2; } - opcode = code = getIndexU1(); - isWide = true; - // Validated in UtilTest.testOpcodeLengthTable - return LENGTHS[code] * 2; - } - if (code == TABLESWITCH) { + } else if (code == TABLESWITCH) { int alignedBci = align(bci + 1); - if (alignedBci + 3 * 4 >= end) { - return -1; + if (alignedBci + 3 * 4 < end) { + int lo = getIntUnchecked(alignedBci + 1 * 4); + int hi = getIntUnchecked(alignedBci + 2 * 4); + long l = alignedBci - bci + (3L + (long) hi - lo + 1L) * 4L; + len = l > 0 && ((int) l == l) ? (int) l : -1; } - int lo = getIntUnchecked(alignedBci + 1 * 4); - int hi = getIntUnchecked(alignedBci + 2 * 4); - long l = alignedBci - bci + (3L + (long) hi - lo + 1L) * 4L; - return l > 0 && ((int) l == l) ? (int) l : -1; - } - if (code == LOOKUPSWITCH) { + } else if (code == LOOKUPSWITCH) { int alignedBci = align(bci + 1); - if (alignedBci + 2 * 4 >= end) { - return -1; - } - int npairs = getIntUnchecked(alignedBci + 4); - if (npairs < 0) { - return -1; + if (alignedBci + 2 * 4 < end) { + int npairs = getIntUnchecked(alignedBci + 4); + if (npairs >= 0) { + long l = alignedBci - bci + (2L + 2L * npairs) * 4L; + len = l > 0 && ((int) l == l) ? (int) l : -1; + } } - long l = alignedBci - bci + (2L + 2L * npairs) * 4L; - return l > 0 && ((int) l == l) ? (int) l : -1; } - return -1; + if (len <= 0) { + opcode = ILLEGAL; + } + return len; } } From 7d524d7e378430afb3a262e8fe544bd1be22748c Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 3 Oct 2024 12:20:01 +0000 Subject: [PATCH 117/188] 8341004: Open source AWT FileDialog related tests Reviewed-by: kizune --- .../awt/FileDialog/DoubleActionCloseX.java | 75 +++++++++++ .../java/awt/FileDialog/DoubleActionESC.java | 122 ++++++++++++++++++ .../FileDialog/TestFileDialogDupJNIRef.java | 82 ++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 test/jdk/java/awt/FileDialog/DoubleActionCloseX.java create mode 100644 test/jdk/java/awt/FileDialog/DoubleActionESC.java create mode 100644 test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java diff --git a/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java b/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java new file mode 100644 index 0000000000000..5d3feaa42ed4b --- /dev/null +++ b/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6227750 + * @summary Tests that FileDialog can be closed by clicking the 'close' (X) button + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DoubleActionCloseX + */ + +public class DoubleActionCloseX { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + NOTE: On Linux and Mac, there is no 'close'(X) button + when file dialog is visible, press Pass. + + Click the 'Open File Dialog' button to open FileDialog. + A file dialog will appear on the screen. + Click on the 'close'(X) button. + The dialog should be closed. + If not, the test failed, press Fail otherwise press Pass. + """; + + PassFailJFrame.builder() + .title("DoubleActionCloseX Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(DoubleActionCloseX::createUI) + .build() + .awaitAndCheck(); + } + public static Frame createUI() { + Frame f = new Frame("DoubleActionCloseX Test"); + Button b = new Button("Open File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setVisible(true); + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/FileDialog/DoubleActionESC.java b/test/jdk/java/awt/FileDialog/DoubleActionESC.java new file mode 100644 index 0000000000000..748c3aeb5e446 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/DoubleActionESC.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; + +/* + * @test + * @bug 5097243 + * @summary Tests that FileDialog can be closed by ESC any time + * @key headful + * @run main DoubleActionESC + */ + +public class DoubleActionESC { + private static Frame f; + private static Button showBtn; + private static FileDialog fd; + private static Robot robot; + private static volatile Point p; + private static volatile Dimension d; + private static volatile CountDownLatch latch; + private static final int REPEAT_COUNT = 2; + + public static void main(String[] args) throws Exception { + latch = new CountDownLatch(1); + + robot = new Robot(); + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> { + createAndShowUI(); + }); + + robot.delay(1000); + EventQueue.invokeAndWait(() -> { + p = showBtn.getLocationOnScreen(); + d = showBtn.getSize(); + }); + + for (int i = 0; i < REPEAT_COUNT; ++i) { + Thread thread = new Thread(() -> { + robot.mouseMove(p.x + d.width / 2, p.y + d.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + }); + thread.start(); + robot.delay(3000); + + Thread thread1 = new Thread(() -> { + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.waitForIdle(); + }); + thread1.start(); + robot.delay(3000); + } + + latch.await(); + if (fd.isVisible()) { + throw new RuntimeException("File Dialog is not closed"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + public static void createAndShowUI() { + f = new Frame("DoubleActionESC Test"); + showBtn = new Button("Show File Dialog"); + fd = new FileDialog(f); + showBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == showBtn) { + fd.setSize(200, 200); + fd.setLocation(200, 200); + fd.setVisible(true); + latch.countDown(); + } + } + }); + f.add(showBtn); + f.setSize(300, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + } +} diff --git a/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java b/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java new file mode 100644 index 0000000000000..56b6c49214488 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4906972 + * @summary Tests using of JNI reference to peer object. + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestFileDialogDupJNIRef + */ + +public class TestFileDialogDupJNIRef { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This is a crash test. + After test started you will see 'Test Frame' with one button. + 1. Click the button to open FileDialog. + 2. Go to the dialog and choose any directory with some files in it.. + 3. Click on any file to highlight it. + 4. Click on the file again to rename. + 5. Leave the file in edit mode and click Open button + + If there was no crash the test passed, Press Pass. + """; + + PassFailJFrame.builder() + .title("TestFileDialogDupJNIRef Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TestFileDialogDupJNIRef::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame frame = new Frame("TestFileDialogDupJNIRef Test Frame"); + Button open = new Button("Open File Dialog"); + + open.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + FileDialog fd = new FileDialog(frame); + fd.setVisible(true); + } + }); + + frame.setLayout(new FlowLayout()); + frame.add(open); + frame.setSize(250, 70); + return frame; + } +} From 21f8ccf4a97313593f210f9a07e56d5ff92b7aa5 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Thu, 3 Oct 2024 12:55:54 +0000 Subject: [PATCH 118/188] 8341310: Test TestJcmdWithSideCar.java should skip ACCESS_TMP_VIA_PROC_ROOT (after JDK-8327114) Reviewed-by: kevinw --- .../jtreg/containers/docker/TestJcmdWithSideCar.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java index 2088398834702..5dea864f42750 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java @@ -42,8 +42,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Paths; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; @@ -52,7 +52,9 @@ import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.Collectors; + import jdk.test.lib.Container; +import jdk.test.lib.Platform; import jdk.test.lib.Utils; import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; @@ -108,6 +110,11 @@ public static void main(String[] args) throws Exception { mainContainer.waitForMainMethodStart(TIME_TO_WAIT_FOR_MAIN_METHOD_START); for (AttachStrategy attachStrategy : EnumSet.allOf(AttachStrategy.class)) { + if (attachStrategy == AttachStrategy.ACCESS_TMP_VIA_PROC_ROOT && + elevated && !Platform.isRoot()) { + // Elevated attach via proc/root not yet supported. + continue; + } long mainProcPid = testCase01(attachStrategy, elevated); // Excluding the test case below until JDK-8228850 is fixed From eb93e6952b5d2dbe78cd9680855ac99c69b3dcb2 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Thu, 3 Oct 2024 14:02:40 +0000 Subject: [PATCH 119/188] 8339979: VirtualThreadSchedulerMXBeanTest.testReduceParallelism fails intermittently Reviewed-by: kevinw --- .../VirtualThreadSchedulerMXBeanTest.java | 95 ++++++++++++++----- 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java b/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java index 891f6e62e6fc7..b256d2b89ab0b 100644 --- a/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java +++ b/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java @@ -34,6 +34,8 @@ import java.lang.management.ManagementFactory; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.IntPredicate; +import java.util.function.LongPredicate; import java.util.stream.Stream; import java.util.stream.IntStream; import javax.management.MBeanServer; @@ -140,23 +142,37 @@ void testReduceParallelism(VirtualThreadSchedulerMXBean bean) throws Exception { try { // increase parallelism + saturate - int newParallelism = parallelism + 4; - bean.setParallelism(newParallelism); - IntStream.range(0, newParallelism).forEach(_ -> executor.submit(busyTask)); - awaitMountedVirtualThreadCountGte(bean, newParallelism); + int highParallelism = parallelism + 4; + bean.setParallelism(highParallelism); + IntStream.range(0, highParallelism).forEach(_ -> executor.submit(busyTask)); + + // mounted virtual thread count should increase to highParallelism. + // Sample the count at highParallelism a few times. + for (int i = 0; i < 5; i++) { + Thread.sleep(100); + awaitMountedVirtualThreadCountEq(bean, highParallelism); + } // reduce parallelism and workload - newParallelism = Math.clamp(parallelism / 2, 1, parallelism); - bean.setParallelism(newParallelism); + int lowParallelism = Math.clamp(parallelism / 2, 1, parallelism); + bean.setParallelism(lowParallelism); sleep.set(true); - // mounted virtual thread count should reduce - awaitMountedVirtualThreadCountLte(bean, newParallelism); - // increase workload, the mounted virtual thread count should not increase + // mounted virtual thread count should reduce to lowParallelism or less. + // Sample the count at lowParallelism or less a few times. + for (int i = 0; i < 5; i++) { + Thread.sleep(100); + awaitMountedVirtualThreadCountLte(bean, lowParallelism); + } + + // increase workload sleep.set(false); + + // mounted virtual thread count should not exceed lowParallelism. + // Sample the count at lowParallelism a few times. for (int i = 0; i < 5; i++) { Thread.sleep(100); - assertTrue(bean.getMountedVirtualThreadCount() <= newParallelism); + awaitMountedVirtualThreadCountEq(bean, lowParallelism); } } finally { @@ -230,31 +246,64 @@ void testQueuedVirtualThreadCount(VirtualThreadSchedulerMXBean bean) throws Exce * Waits for pool size >= target to be true. */ void awaitPoolSizeGte(VirtualThreadSchedulerMXBean bean, int target) throws InterruptedException { - System.err.format("await pool size >= %d ...%n", target); - while (bean.getPoolSize() < target) { - Thread.sleep(10); - } + awaitPoolSize(bean, ps -> ps >= target, ">= " + target); } /** * Waits for the mounted virtual thread count >= target to be true. */ void awaitMountedVirtualThreadCountGte(VirtualThreadSchedulerMXBean bean, - int target) throws InterruptedException { - System.err.format("await mounted virtual thread count >= %d ...%n", target); - while (bean.getMountedVirtualThreadCount() < target) { - Thread.sleep(10); - } + long target) throws InterruptedException { + awaitMountedVirtualThreadCount(bean, c -> c >= target, ">= " + target); } /** * Waits for the mounted virtual thread count <= target to be true. */ void awaitMountedVirtualThreadCountLte(VirtualThreadSchedulerMXBean bean, - int target) throws InterruptedException { - System.err.format("await mounted virtual thread count <= %d ...%n", target); - while (bean.getMountedVirtualThreadCount() > target) { - Thread.sleep(10); + long target) throws InterruptedException { + awaitMountedVirtualThreadCount(bean, c -> c <= target, "<= " + target); + } + + /** + * Waits for the mounted virtual thread count == target to be true. + */ + void awaitMountedVirtualThreadCountEq(VirtualThreadSchedulerMXBean bean, + long target) throws InterruptedException { + awaitMountedVirtualThreadCount(bean, c -> c == target, "== " + target); + } + + /** + * Waits until evaluating the given predicte on the pool size is true. + */ + void awaitPoolSize(VirtualThreadSchedulerMXBean bean, + IntPredicate predicate, + String reason) throws InterruptedException { + int poolSize = bean.getPoolSize(); + if (!predicate.test(poolSize)) { + System.err.format("poolSize = %d, await %s ...%n", poolSize, reason); + while (!predicate.test(poolSize)) { + Thread.sleep(10); + poolSize = bean.getPoolSize(); + } + System.err.format("poolSize = %d%n", poolSize); + } + } + + /** + * Waits until evaluating the given predicte on the mounted thread count is true. + */ + void awaitMountedVirtualThreadCount(VirtualThreadSchedulerMXBean bean, + LongPredicate predicate, + String reason) throws InterruptedException { + long count = bean.getMountedVirtualThreadCount(); + if (!predicate.test(count)) { + System.err.format("mountedVirtualThreadCount = %d, await %s ...%n", count, reason); + while (!predicate.test(count)) { + Thread.sleep(10); + count = bean.getMountedVirtualThreadCount(); + } + System.err.format("mountedVirtualThreadCount = %d%n", count); } } } \ No newline at end of file From 12028000db2ef3b1c784af119c495aa3ef9590cf Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 3 Oct 2024 14:34:05 +0000 Subject: [PATCH 120/188] 8341006: Optimize StackMapGenerator detect frames Reviewed-by: liach --- .../classfile/impl/StackMapGenerator.java | 159 ++++++++++-------- 1 file changed, 91 insertions(+), 68 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index ae9835206831e..0eae3c357196a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -39,7 +40,6 @@ import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; import java.util.Arrays; -import java.util.BitSet; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -58,8 +58,8 @@ *

        * The {@linkplain #generate() frames computation} consists of following steps: *

          - *
        1. {@linkplain #detectFrameOffsets() Detection} of mandatory stack map frames offsets:
            - *
          • Mandatory stack map frame offsets include all jump and switch instructions targets, + *
          • {@linkplain #detectFrames() Detection} of mandatory stack map frames:
              + *
            • Mandatory stack map frame include all jump and switch instructions targets, * offsets immediately following {@linkplain #noControlFlow(int) "no control flow"} * and all exception table handlers. *
            • Detection is performed in a single fast pass through the bytecode, @@ -163,6 +163,7 @@ static StackMapGenerator of(DirectCodeBuilder dcb, BufWriterImpl buf) { private static final int FLAG_THIS_UNINIT = 0x01; private static final int FRAME_DEFAULT_CAPACITY = 10; private static final int T_BOOLEAN = 4, T_LONG = 11; + private static final Frame[] EMPTY_FRAME_ARRAY = new Frame[0]; private static final int ITEM_TOP = 0, ITEM_INTEGER = 1, @@ -198,7 +199,8 @@ static record RawExceptionCatch(int start, int end, int handler, Type catchType) private final ClassHierarchyImpl classHierarchy; private final boolean patchDeadCode; private final boolean filterDeadLabels; - private List frames; + private Frame[] frames = EMPTY_FRAME_ARRAY; + private int framesCount = 0; private final Frame currentFrame; private int maxStack, maxLocals; @@ -262,10 +264,10 @@ public int maxStack() { private Frame getFrame(int offset) { //binary search over frames ordered by offset int low = 0; - int high = frames.size() - 1; + int high = framesCount - 1; while (low <= high) { int mid = (low + high) >>> 1; - var f = frames.get(mid); + var f = frames[mid]; if (f.offset < offset) low = mid + 1; else if (f.offset > offset) @@ -283,8 +285,8 @@ private void checkJumpTarget(Frame frame, int target) { private int exMin, exMax; private boolean isAnyFrameDirty() { - for (var f : frames) { - if (f.dirty) return true; + for (int i = 0; i < framesCount; i++) { + if (frames[i].dirty) return true; } return false; } @@ -292,27 +294,10 @@ private boolean isAnyFrameDirty() { private void generate() { exMin = bytecode.length(); exMax = -1; - for (var exhandler : handlers) { - int start_pc = labelContext.labelToBci(exhandler.tryStart()); - int end_pc = labelContext.labelToBci(exhandler.tryEnd()); - int handler_pc = labelContext.labelToBci(exhandler.handler()); - if (start_pc >= 0 && end_pc >= 0 && end_pc > start_pc && handler_pc >= 0) { - if (start_pc < exMin) exMin = start_pc; - if (end_pc > exMax) exMax = end_pc; - var catchType = exhandler.catchType(); - rawHandlers.add(new RawExceptionCatch(start_pc, end_pc, handler_pc, - catchType.isPresent() ? cpIndexToType(catchType.get().index(), cp) - : Type.THROWABLE_TYPE)); - } - } - BitSet frameOffsets = detectFrameOffsets(); - int framesCount = frameOffsets.cardinality(); - frames = new ArrayList<>(framesCount); - int offset = -1; - for (int i = 0; i < framesCount; i++) { - offset = frameOffsets.nextSetBit(offset + 1); - frames.add(new Frame(offset, classHierarchy)); + if (!handlers.isEmpty()) { + generateHandlers(); } + detectFrames(); do { processMethod(); } while (isAnyFrameDirty()); @@ -321,23 +306,45 @@ private void generate() { //dead code patching for (int i = 0; i < framesCount; i++) { - var frame = frames.get(i); + var frame = frames[i]; if (frame.flags == -1) { - if (!patchDeadCode) throw generatorError("Unable to generate stack map frame for dead code", frame.offset); - //patch frame - frame.pushStack(Type.THROWABLE_TYPE); - if (maxStack < 1) maxStack = 1; - int end = (i < framesCount - 1 ? frames.get(i + 1).offset : bytecode.length()) - 1; - //patch bytecode - var arr = bytecode.array(); - Arrays.fill(arr, frame.offset, end, (byte) NOP); - arr[end] = (byte) ATHROW; - //patch handlers - removeRangeFromExcTable(frame.offset, end + 1); + deadCodePatching(frame, i); + } + } + } + + private void generateHandlers() { + var labelContext = this.labelContext; + for (int i = 0; i < handlers.size(); i++) { + var exhandler = handlers.get(i); + int start_pc = labelContext.labelToBci(exhandler.tryStart()); + int end_pc = labelContext.labelToBci(exhandler.tryEnd()); + int handler_pc = labelContext.labelToBci(exhandler.handler()); + if (start_pc >= 0 && end_pc >= 0 && end_pc > start_pc && handler_pc >= 0) { + if (start_pc < exMin) exMin = start_pc; + if (end_pc > exMax) exMax = end_pc; + var catchType = exhandler.catchType(); + rawHandlers.add(new RawExceptionCatch(start_pc, end_pc, handler_pc, + catchType.isPresent() ? cpIndexToType(catchType.get().index(), cp) + : Type.THROWABLE_TYPE)); } } } + private void deadCodePatching(Frame frame, int i) { + if (!patchDeadCode) throw generatorError("Unable to generate stack map frame for dead code", frame.offset); + //patch frame + frame.pushStack(Type.THROWABLE_TYPE); + if (maxStack < 1) maxStack = 1; + int end = (i < framesCount - 1 ? frames[i + 1].offset : bytecode.length()) - 1; + //patch bytecode + var arr = bytecode.array(); + Arrays.fill(arr, frame.offset, end, (byte) NOP); + arr[end] = (byte) ATHROW; + //patch handlers + removeRangeFromExcTable(frame.offset, end + 1); + } + private void removeRangeFromExcTable(int rangeStart, int rangeEnd) { var it = handlers.listIterator(); while (it.hasNext()) { @@ -380,14 +387,15 @@ private void removeRangeFromExcTable(int rangeStart, int rangeEnd) { * @return StackMapTableAttribute or null if stack map is empty */ public Attribute stackMapTableAttribute() { - return frames.isEmpty() ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) { + return framesCount == 0 ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) { @Override public void writeBody(BufWriterImpl b) { - b.writeU2(frames.size()); + b.writeU2(framesCount); Frame prevFrame = new Frame(classHierarchy); prevFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType); prevFrame.trimAndCompress(); - for (var fr : frames) { + for (int i = 0; i < framesCount; i++) { + var fr = frames[i]; fr.trimAndCompress(); fr.writeTo(b, prevFrame, cp); prevFrame = fr; @@ -412,19 +420,19 @@ private void processMethod() { boolean ncf = false; while (bcs.next()) { currentFrame.offset = bcs.bci(); - if (stackmapIndex < frames.size()) { - int thisOffset = frames.get(stackmapIndex).offset; + if (stackmapIndex < framesCount) { + int thisOffset = frames[stackmapIndex].offset; if (ncf && thisOffset > bcs.bci()) { throw generatorError("Expecting a stack map frame"); } if (thisOffset == bcs.bci()) { - Frame nextFrame = frames.get(stackmapIndex++); + Frame nextFrame = frames[stackmapIndex++]; if (!ncf) { currentFrame.checkAssignableTo(nextFrame); } while (!nextFrame.dirty) { //skip unmatched frames - if (stackmapIndex == frames.size()) return; //skip the rest of this round - nextFrame = frames.get(stackmapIndex++); + if (stackmapIndex == framesCount) return; //skip the rest of this round + nextFrame = frames[stackmapIndex++]; } bcs.reset(nextFrame.offset); //skip code up-to the next frame bcs.next(); @@ -841,18 +849,10 @@ private IllegalArgumentException generatorError(String msg, int offset) { } /** - * Performs detection of mandatory stack map frames offsets - * in a single bytecode traversing pass - * @return java.lang.BitSet of detected frames offsets + * Performs detection of mandatory stack map frames in a single bytecode traversing pass + * @return detected frames */ - private BitSet detectFrameOffsets() { - var offsets = new BitSet() { - @Override - public void set(int i) { - Preconditions.checkIndex(i, bytecode.length(), RawBytecodeHelper.IAE_FORMATTER); - super.set(i); - } - }; + private void detectFrames() { var bcs = bytecode.start(); boolean no_control_flow = false; int opcode, bci = 0; @@ -860,22 +860,22 @@ public void set(int i) { opcode = bcs.opcode(); bci = bcs.bci(); if (no_control_flow) { - offsets.set(bci); + addFrame(bci); } no_control_flow = switch (opcode) { case GOTO -> { - offsets.set(bcs.dest()); + addFrame(bcs.dest()); yield true; } case GOTO_W -> { - offsets.set(bcs.destW()); + addFrame(bcs.destW()); yield true; } case IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ACMPEQ, IF_ACMPNE , IFNULL , IFNONNULL -> { - offsets.set(bcs.dest()); + addFrame(bcs.dest()); yield false; } case TABLESWITCH, LOOKUPSWITCH -> { @@ -891,9 +891,9 @@ public void set(int i) { keys = bcs.getIntUnchecked(aligned_bci + 4); delta = 2; } - offsets.set(bci + default_ofset); + addFrame(bci + default_ofset); for (int i = 0; i < keys; i++) { - offsets.set(bci + bcs.getIntUnchecked(aligned_bci + (3 + i * delta) * 4)); + addFrame(bci + bcs.getIntUnchecked(aligned_bci + (3 + i * delta) * 4)); } yield true; } @@ -904,13 +904,36 @@ public void set(int i) { } catch (IllegalArgumentException iae) { throw generatorError("Detected branch target out of bytecode range", bci); } - for (var exhandler : rawHandlers) try { - offsets.set(exhandler.handler()); + for (int i = 0; i < rawHandlers.size(); i++) try { + addFrame(rawHandlers.get(i).handler()); } catch (IllegalArgumentException iae) { if (!filterDeadLabels) throw generatorError("Detected exception handler out of bytecode range"); } - return offsets; + } + + private void addFrame(int offset) { + Preconditions.checkIndex(offset, bytecode.length(), RawBytecodeHelper.IAE_FORMATTER); + var frames = this.frames; + int i = 0, framesCount = this.framesCount; + for (; i < framesCount; i++) { + var frameOffset = frames[i].offset; + if (frameOffset == offset) { + return; + } + if (frameOffset > offset) { + break; + } + } + if (framesCount >= frames.length) { + int newCapacity = framesCount + 8; + this.frames = frames = framesCount == 0 ? new Frame[newCapacity] : Arrays.copyOf(frames, newCapacity); + } + if (i != framesCount) { + System.arraycopy(frames, i, frames, i + 1, framesCount - i); + } + frames[i] = new Frame(offset, classHierarchy); + this.framesCount = framesCount + 1; } private final class Frame { From f1ea57f06a044ebd39d31a7c4765d0220327b0a0 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 3 Oct 2024 15:13:42 +0000 Subject: [PATCH 121/188] 8340229: Improve opening sentence of FileInputStream constructor specification Reviewed-by: alanb, jpai --- .../share/classes/java/io/FileInputStream.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/java/io/FileInputStream.java b/src/java.base/share/classes/java/io/FileInputStream.java index 60b289637fdfc..180b2e416a914 100644 --- a/src/java.base/share/classes/java/io/FileInputStream.java +++ b/src/java.base/share/classes/java/io/FileInputStream.java @@ -82,10 +82,9 @@ public class FileInputStream extends InputStream private volatile boolean closed; /** - * Creates a {@code FileInputStream} by - * opening a connection to an actual file, - * the file named by the path name {@code name} - * in the file system. {@linkplain java.nio.file##links Symbolic links} + * Creates a {@code FileInputStream} to read from an existing file + * named by the path name {@code name}. + * {@linkplain java.nio.file##links Symbolic links} * are automatically redirected to the target of the link. * A new {@code FileDescriptor} * object is created to represent this file @@ -115,10 +114,8 @@ public FileInputStream(String name) throws FileNotFoundException { } /** - * Creates a {@code FileInputStream} by - * opening a connection to an actual file, - * the file named by the {@code File} - * object {@code file} in the file system. + * Creates a {@code FileInputStream} to read from an existing file + * represented by the {@code File} object {@code file}. * {@linkplain java.nio.file##links Symbolic links} * are automatically redirected to the target of the link. * A new {@code FileDescriptor} object From 3ee94e040a7395d11a294a6b660d707c97f188f8 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 3 Oct 2024 15:13:58 +0000 Subject: [PATCH 122/188] 8341282: (fs) Move creation time fallback logic to Java layer (Linux) Reviewed-by: sgehwolf, alanb --- .../sun/nio/fs/UnixFileAttributes.java | 7 +++--- .../native/libnio/fs/UnixNativeDispatcher.c | 25 +++++++++++-------- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java index 3b09bd259ceec..2a036d22aed9d 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,6 +58,7 @@ class UnixFileAttributes private long st_ctime_nsec; private long st_birthtime_sec; private long st_birthtime_nsec; + private boolean birthtime_available; // created lazily private volatile UserPrincipal owner; @@ -163,10 +164,10 @@ public FileTime lastAccessTime() { @Override public FileTime creationTime() { - if (UnixNativeDispatcher.birthtimeSupported()) { + if (UnixNativeDispatcher.birthtimeSupported() && birthtime_available) { return toFileTime(st_birthtime_sec, st_birthtime_nsec); } else { - // return last modified when birth time not supported + // return last modified when birth time unsupported or unavailable return lastModifiedTime(); } } diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index b91ab6f0cab92..61e9215471a32 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -184,6 +184,7 @@ static jfieldID attrs_st_birthtime_sec; #if defined(__linux__) // Linux has nsec granularity if supported static jfieldID attrs_st_birthtime_nsec; #endif +static jfieldID attrs_birthtime_available; static jfieldID attrs_f_frsize; static jfieldID attrs_f_blocks; @@ -332,6 +333,8 @@ Java_sun_nio_fs_UnixNativeDispatcher_init(JNIEnv* env, jclass this) attrs_st_birthtime_nsec = (*env)->GetFieldID(env, clazz, "st_birthtime_nsec", "J"); CHECK_NULL_RETURN(attrs_st_birthtime_nsec, 0); #endif + attrs_birthtime_available = (*env)->GetFieldID(env, clazz, "birthtime_available", "Z"); + CHECK_NULL_RETURN(attrs_birthtime_available, 0); clazz = (*env)->FindClass(env, "sun/nio/fs/UnixFileStoreAttributes"); CHECK_NULL_RETURN(clazz, 0); @@ -620,19 +623,19 @@ static void copy_statx_attributes(JNIEnv* env, struct my_statx* buf, jobject att (*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->stx_atime.tv_sec); (*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->stx_mtime.tv_sec); (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->stx_ctime.tv_sec); + + // Check mask for birth time and set flag accordingly. The birth time is + // filled in if and only if the STATX_BTIME bit is set in the mask. + // Although the statx system call might be supported by the operating + // system, the birth time is not necessarily supported by the file system. if ((buf->stx_mask & STATX_BTIME) != 0) { - // Birth time was filled in so use it - (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, - (jlong)buf->stx_btime.tv_sec); - (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, - (jlong)buf->stx_btime.tv_nsec); + (*env)->SetBooleanField(env, attrs, attrs_birthtime_available, (jboolean)JNI_TRUE); + (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->stx_btime.tv_sec); + (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, (jlong)buf->stx_btime.tv_nsec); } else { - // Birth time was not filled in: fall back to last modification time - (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, - (jlong)buf->stx_mtime.tv_sec); - (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, - (jlong)buf->stx_mtime.tv_nsec); + (*env)->SetBooleanField(env, attrs, attrs_birthtime_available, (jboolean)JNI_FALSE); } + (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->stx_atime.tv_nsec); (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->stx_mtime.tv_nsec); (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->stx_ctime.tv_nsec); @@ -661,7 +664,9 @@ static void copy_stat_attributes(JNIEnv* env, struct stat* buf, jobject attrs) { (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->st_ctime); #ifdef _DARWIN_FEATURE_64_BIT_INODE + // birthtime_available defaults to 'false'; on Darwin, it is always true (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->st_birthtime); + (*env)->SetBooleanField(env, attrs, attrs_birthtime_available, (jboolean)JNI_TRUE); // rely on default value of 0 for st_birthtime_nsec field on Darwin #endif From ebb4759c3d2776f5e6e83f743a7891a145f8aee4 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Thu, 3 Oct 2024 16:19:09 +0000 Subject: [PATCH 123/188] 8340625: Open source additional Component tests (part 3) Reviewed-by: psadhukhan --- .../PaintGlitchTest/PaintGlitchTest.java | 225 +++++++++ .../Component/ProcessEvent/ProcessEvent.java | 455 ++++++++++++++++++ .../SetFontOrBackground/SetBgrFnt.java | 123 +++++ 3 files changed, 803 insertions(+) create mode 100644 test/jdk/java/awt/Component/PaintGlitchTest/PaintGlitchTest.java create mode 100644 test/jdk/java/awt/Component/ProcessEvent/ProcessEvent.java create mode 100644 test/jdk/java/awt/Component/SetFontOrBackground/SetBgrFnt.java diff --git a/test/jdk/java/awt/Component/PaintGlitchTest/PaintGlitchTest.java b/test/jdk/java/awt/Component/PaintGlitchTest/PaintGlitchTest.java new file mode 100644 index 0000000000000..867d82d326297 --- /dev/null +++ b/test/jdk/java/awt/Component/PaintGlitchTest/PaintGlitchTest.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4045781 + * @summary Exposed/damaged canvases don't always update correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual PaintGlitchTest + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollBar; +import javax.swing.JTextArea; +import javax.swing.JTextField; + +public class PaintGlitchTest extends Frame { + static final String INSTRUCTIONS = """ + 1. Click on the 'Painting Glitch Test' window and select from + its menu a content type (text, gradient, fill, + AWT components, Swing components etc.). + 2. Select 'Modal Dialog...' to create a dialog. + 3. Drag the dialog over the content very fast + for 10 seconds or so - make sure you + keep dragging while the content is painting. + 4. Verify that the area exposed by the drag (the damaged regions) + always update properly no white areas or bits of the dialog + should be left after the drag operation is + completed (i.e. after you let go of the mouse). + 5. Repeat for all other content types. + 6. If for any content type the damaged dialog is not properly + repainted press Fail. Otherwise press Pass. + """; + + public PaintGlitchTest() { + super("Painting Glitch Test"); + + TextPanel textPanel = new TextPanel(); + GradientPanel gradientPanel = new GradientPanel(); + ComponentPanel componentPanel = new ComponentPanel(); + SwingPanel swingPanel = new SwingPanel(); + + add(textPanel); + + MenuBar menubar = new MenuBar(); + Menu testMenu = new Menu("Test"); + testMenu.add(makeContentItem("Text Lines", textPanel) ); + testMenu.add(makeContentItem("Gradient Fill", gradientPanel) ); + testMenu.add(makeContentItem("AWT Components", componentPanel) ); + testMenu.add(makeContentItem("Swing Components", swingPanel) ); + testMenu.addSeparator(); + MenuItem dialogItem = new MenuItem("Modal Dialog..."); + dialogItem.addActionListener(ev -> new ObscuringDialog(PaintGlitchTest.this).show()); + testMenu.add(dialogItem); + testMenu.addSeparator(); + menubar.add(testMenu); + + setMenuBar(menubar); + setSize(400,300); + } + + public static void main(String args[]) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Repaint Glitch") + .testUI(PaintGlitchTest::new) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } + + public MenuItem makeContentItem(String title, final Component content) { + MenuItem menuItem = new MenuItem(title); + menuItem.addActionListener( + ev -> { + remove(0); + add(content); + validate(); + } + ); + + return menuItem; + } +} + +class GradientPanel extends Canvas { + public void paint(Graphics g) { + long ms = System.currentTimeMillis(); + // just paint something that'll take a while + int x, y; + int width = getSize().width; + int height = getSize().height; + int step = 8; + + for (x = 0; x < width; x += step) { + for (y = 0; y < height; y += step) { + int red = (255 * y) / height; + int green = (255 * x * y) / (width * height); + int blue = (255 * x) / width; + + Color color = new Color(red, green, blue); + g.setColor(color); + g.fillRect(x, y, step, step); + } + } + long time = System.currentTimeMillis() - ms; + PassFailJFrame.log("GradientPanel paint took " + time + " ms"); + } + + public Dimension getPreferredSize() { + return new Dimension(200,1000); + } +} + +class TextPanel extends Canvas { + public void paint(Graphics g) { + long ms = System.currentTimeMillis(); + Font font = new Font("SanSerif", Font.ITALIC, 12); + + g.setFont(font); + // just paint something that'll take a while + int x, y; + int height = getHeight(); + int step = 16; + + for (x = y = 0; y < height; y += step) { + g.drawString(y + " : The quick brown fox jumps over the lazy dog. " + + "The rain in Spain falls mainly on the plain.", x, y); + } + long time = System.currentTimeMillis() - ms; + PassFailJFrame.log("TextPanel paint took " + time + " ms"); + } + + public Dimension getPreferredSize() { + return new Dimension(640,1000); + } +} + +class ComponentPanel extends Panel { + ComponentPanel() { + add(new Label("Label")); + add(new Button("Button")); + add(new Checkbox("Checkbox")); + Choice c = new Choice(); + c.add("choice"); + java.awt.List l = new java.awt.List(); + l.add("list"); + add(new Scrollbar()); + add(new TextField("TextField")); + add(new TextArea("TextArea")); + add(new Panel()); + add(new Canvas()); + } +} + +class SwingPanel extends JPanel { + SwingPanel() { + add(new JLabel("JLabel")); + add(new JButton("JButton")); + add(new JCheckBox("JCheckBox")); + JComboBox c = new JComboBox(); + JList l = new JList(); + add(new JScrollBar()); + add(new JTextField("This is a JTextField with some text in it to make it longer.")); + add(new JTextArea("This is a JTextArea with some text in it to make it longer.")); + } +} + +class ObscuringDialog extends Dialog { + ObscuringDialog(Frame f) { + super(f, "Obscuring Dialog"); + Button ok = new Button("OK, go away"); + ok.addActionListener(ev -> dispose()); + add(ok); + pack(); + } +} diff --git a/test/jdk/java/awt/Component/ProcessEvent/ProcessEvent.java b/test/jdk/java/awt/Component/ProcessEvent/ProcessEvent.java new file mode 100644 index 0000000000000..3dfd5a0403804 --- /dev/null +++ b/test/jdk/java/awt/Component/ProcessEvent/ProcessEvent.java @@ -0,0 +1,455 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4292099 + * @summary AWT Event delivery to processEvent + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ProcessEvent + */ + +import java.awt.AWTEvent; +import java.awt.AWTEventMulticaster; +import java.awt.Adjustable; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.ItemSelectable; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.TextEvent; +import java.awt.event.TextListener; +import java.lang.reflect.InvocationTargetException; + +public class ProcessEvent extends Frame { + + static final String INSTRUCTIONS = """ + Press each of the four buttons for ActionEvent, AdjustmentEvent, + ItemEvent and TextEvent. If a message for each corresponding event + appears in the log area and says the event listener was + called, then press Pass otherwise press Fail. + """; + ActionBtn af; + AdjustmentBtn adjf; + ItemBtn itf; + TextBtn txtf; + + public ProcessEvent() { + setLayout(new FlowLayout()); + add(af = new ActionBtn()); + af.setBackground(Color.green); + + add(adjf = new AdjustmentBtn()); + adjf.setBackground(Color.green); + + add(itf = new ItemBtn()); + itf.setBackground(Color.green); + + add(txtf = new TextBtn()); + txtf.setBackground(Color.green); + + // These action listeners simply provide feedback of when + // the event is delivered properly. + af.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ae) { + PassFailJFrame.log(af.getText() + + ": action listener called: " + + ae.toString()); + } + }); + + adjf.addAdjustmentListener(new AdjustmentListener() { + public void adjustmentValueChanged(AdjustmentEvent ae) { + PassFailJFrame.log(adjf.getText() + + ": adjustment listener called: " + + ae.toString()); + } + }); + + itf.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + PassFailJFrame.log(itf.getText() + + ": item listener called: " + + e.toString()); + } + }); + + txtf.addTextListener(new TextListener() { + public void textValueChanged(TextEvent e) { + PassFailJFrame.log(txtf.getText() + + ": text listener called: " + + e.toString()); + } + }); + + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Process Events Test") + .testUI(ProcessEvent::new) + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} + +class ButtonComponent extends Component implements ItemSelectable, Adjustable { + + transient protected TextListener textListener; + transient ActionListener actionListener; + transient AdjustmentListener adjustmentListener; + transient ItemListener itemListener; + String actionCommand = null; + + String text = null; + + public ButtonComponent(String label) { + super(); + text = label; + } + + public String getText() { + return text; + } + + public Dimension getPreferredSize() { + return new Dimension(200, 30); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public String getActionCommand() { + if (actionCommand == null) + return getText(); + else + return actionCommand; + } + + public void setActionCommand(String ac) { + actionCommand = ac; + } + + // ActionEvent listener support + + public synchronized void addActionListener(ActionListener l) { + if (l == null) { + return; + } + enableEvents(AWTEvent.ACTION_EVENT_MASK); + actionListener = AWTEventMulticaster.add(actionListener, l); + } + + public synchronized void removeActionListener(ActionListener l) { + if (l == null) { + return; + } + actionListener = AWTEventMulticaster.remove(actionListener, l); + } + + // AdjustmentEvent listener support + + public synchronized void addAdjustmentListener(AdjustmentListener l) { + if (l == null) { + return; + } + enableEvents(AWTEvent.ADJUSTMENT_EVENT_MASK); + adjustmentListener = AWTEventMulticaster.add(adjustmentListener, l); + } + + public synchronized void removeAdjustmentListener(AdjustmentListener l) { + if (l == null) { + return; + } + adjustmentListener = AWTEventMulticaster.remove(adjustmentListener, l); + } + + // ItemEvent listener support + + public synchronized void addItemListener(ItemListener l) { + if (l == null) { + return; + } + enableEvents(AWTEvent.ITEM_EVENT_MASK); + itemListener = AWTEventMulticaster.add(itemListener, l); + } + + public synchronized void removeItemListener(ItemListener l) { + if (l == null) { + return; + } + itemListener = AWTEventMulticaster.remove(itemListener, l); + } + + // TextEvent listener support + + public synchronized void addTextListener(TextListener l) { + if (l == null) { + return; + } + enableEvents(AWTEvent.TEXT_EVENT_MASK); + textListener = AWTEventMulticaster.add(textListener, l); + } + + public synchronized void removeTextListener(TextListener l) { + if (l == null) { + return; + } + textListener = AWTEventMulticaster.remove(textListener, l); + } + + // Implement the processEvent and processXXXEvent methods to + // handle reception and processing of the event types. + + protected void processEvent(AWTEvent e) { + if (e instanceof ActionEvent) { + processActionEvent((ActionEvent) e); + return; + } + if (e instanceof AdjustmentEvent) { + processAdjustmentEvent((AdjustmentEvent) e); + return; + } + if (e instanceof ItemEvent) { + processItemEvent((ItemEvent) e); + return; + } + if (e instanceof TextEvent) { + processTextEvent((TextEvent) e); + return; + } + super.processEvent(e); + } + + protected void processActionEvent(ActionEvent e) { + if (actionListener != null) { + actionListener.actionPerformed(e); + } + } + + protected void processAdjustmentEvent(AdjustmentEvent e) { + if (adjustmentListener != null) { + adjustmentListener.adjustmentValueChanged(e); + } + } + + protected void processItemEvent(ItemEvent e) { + if (itemListener != null) { + itemListener.itemStateChanged(e); + } + } + + protected void processTextEvent(TextEvent e) { + if (textListener != null) { + textListener.textValueChanged(e); + } + } + + public void paint(Graphics g) { + Dimension dim = getSize(); + g.clearRect(0, 0, dim.width, dim.height); + g.setColor(getForeground()); + g.drawString(text, 2, dim.height - 2); + } + + /** + * Returns the selected items or null if no items are selected. + */ + public Object[] getSelectedObjects() { + return null; + } + + /** + * Gets the orientation of the adjustable object. + */ + public int getOrientation() { + return 0; + } + + /** + * Gets the minimum value of the adjustable object. + */ + public int getMinimum() { + return 0; + } + + /** + * Sets the minimum value of the adjustable object. + * + * @param min the minimum value + */ + public void setMinimum(int min) { + } + + /** + * Gets the maximum value of the adjustable object. + */ + public int getMaximum() { + return 0; + } + + /** + * Sets the maximum value of the adjustable object. + * + * @param max the maximum value + */ + public void setMaximum(int max) { + } + + /** + * Gets the unit value increment for the adjustable object. + */ + public int getUnitIncrement() { + return 0; + } + + /** + * Sets the unit value increment for the adjustable object. + * + * @param u the unit increment + */ + public void setUnitIncrement(int u) { + } + + /** + * Gets the block value increment for the adjustable object. + */ + public int getBlockIncrement() { + return 0; + } + + /** + * Sets the block value increment for the adjustable object. + * + * @param b the block increment + */ + public void setBlockIncrement(int b) { + } + + /** + * Gets the length of the propertional indicator. + */ + public int getVisibleAmount() { + return 0; + } + + /** + * Sets the length of the proportionl indicator of the + * adjustable object. + * + * @param v the length of the indicator + */ + public void setVisibleAmount(int v) { + } + + /** + * Gets the current value of the adjustable object. + */ + public int getValue() { + return 0; + } + + /** + * Sets the current value of the adjustable object. This + * value must be within the range defined by the minimum and + * maximum values for this object. + * + * @param v the current value + */ + public void setValue(int v) { + } + +} + +class ActionBtn extends ButtonComponent { + public ActionBtn() { + super("ActionEvent"); + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + ActionEvent ae = new ActionEvent(e.getSource(), + ActionEvent.ACTION_PERFORMED, + getActionCommand()); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae); + } + }); + } +} + +class AdjustmentBtn extends ButtonComponent { + public AdjustmentBtn() { + super("AdjustmentEvent"); + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + AdjustmentEvent ae = new AdjustmentEvent((Adjustable) e.getSource(), + AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + 1, 1); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae); + } + }); + } +} + +class ItemBtn extends ButtonComponent { + public ItemBtn() { + super("ItemEvent"); + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + ItemEvent ae = new ItemEvent((ItemSelectable) e.getSource(), + ItemEvent.ITEM_STATE_CHANGED, + e.getSource(), 1); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae); + } + }); + } +} + +class TextBtn extends ButtonComponent { + public TextBtn() { + super("TextEvent"); + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + TextEvent ae = new TextEvent(e.getSource(), + TextEvent.TEXT_VALUE_CHANGED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae); + } + }); + } +} diff --git a/test/jdk/java/awt/Component/SetFontOrBackground/SetBgrFnt.java b/test/jdk/java/awt/Component/SetFontOrBackground/SetBgrFnt.java new file mode 100644 index 0000000000000..02707ad578475 --- /dev/null +++ b/test/jdk/java/awt/Component/SetFontOrBackground/SetBgrFnt.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4906548 4921849 + * @summary Checks that setFont and setBackground have immediate effect + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetBgrFnt + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.lang.reflect.InvocationTargetException; + +public class SetBgrFnt extends Frame { + static final String INSTRUCTIONS = """ + 1. Press a button marked 'Switch fonts' + fonts in three components below (a Button, a Checkbox + and a Label) must change immediately. + + 2. Press a button marked 'Switch background' + background of three components and canvas must change. + MacOS is an exception - AWT buttons on macOS so not + change color so on macOS only canvas, checkbox + and a label should change background. + + If this is the behavior that you observe press Pass, + otherwise press Fail. + """; + Label la; + Button bu, bu1, bu2; + Checkbox cb; + Font font1, font2; + Canvas ca; + boolean bToggleFont = true; + boolean bToggleBg = true; + + public SetBgrFnt() { + bu = new Button("Switch fonts"); + bu1 = new Button("Switch background"); + bu2 = new Button("I'm a button"); + cb = new Checkbox("Checkbox I am"); + la = new Label("I am a label"); + ca = new Canvas(); + font1 = new Font("Serif", Font.ITALIC, 22); + font2 = new Font("SansSerif", Font.PLAIN, 10); + la.setFont(font1); + cb.setFont(font1); + bu2.setFont(font1); + bu.addActionListener(ae -> { + if (bToggleFont) { + la.setFont(font2); + cb.setFont(font2); + bu2.setFont(font2); + } else { + la.setFont(font1); + cb.setFont(font1); + bu2.setFont(font1); + } + bToggleFont = !bToggleFont; + }); + + bu1.addActionListener(ae -> { + if (bToggleBg) { + ca.setBackground(Color.YELLOW); + setBackground(Color.YELLOW); + } else { + ca.setBackground(Color.GREEN); + setBackground(Color.GREEN); + } + bToggleBg = !bToggleBg; + }); + + setLayout(new GridLayout(8, 1)); + add(bu); + add(bu1); + add(new Label()); + add("South", la); + add("South", bu2); + add("South", cb); + add("South", ca); + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Set Font and Background Test") + .testUI(SetBgrFnt::new) + .instructions(INSTRUCTIONS) + .columns(40) + .build() + .awaitAndCheck(); + } +} From de12fc7a3601ad7d5e10ccd38967b26eadf96aff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Thu, 3 Oct 2024 16:44:22 +0000 Subject: [PATCH 124/188] 8339684: ResizeObserver callback interrupts smooth scrolling on Chrome Reviewed-by: prappo --- .../doclets/formats/html/resources/script.js.template | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index 633f453bc43b1..2185b1c951f8e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -300,6 +300,7 @@ document.addEventListener("DOMContentLoaded", function(e) { }); var expanded = false; var windowWidth; + var bodyHeight; function collapse(e) { if (expanded) { mainnav.removeAttribute("style"); @@ -365,6 +366,7 @@ document.addEventListener("DOMContentLoaded", function(e) { var scrollTimeoutNeeded; var prevHash; function initSectionData() { + bodyHeight = document.body.offsetHeight; sections = [{ id: "", top: 0 }].concat(Array.from(main.querySelectorAll("section[id], h2[id], h2 a[id], div[id]")) .filter((e) => { return sidebar.querySelector("a[href=\"#" + encodeURI(e.getAttribute("id")) + "\"]") !== null @@ -469,7 +471,7 @@ document.addEventListener("DOMContentLoaded", function(e) { expand(); } } - if (sections) { + if (sections && document.body.offsetHeight !== bodyHeight) { initSectionData(); prevHash = null; handleScroll(); From 013250e4a7bc2fa83c6e57bb8fad6002dbe3176c Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Thu, 3 Oct 2024 16:46:46 +0000 Subject: [PATCH 125/188] 8340432: Open source some MenuBar tests - Set2 Reviewed-by: prr, psadhukhan --- .../MenuBarAddRemoveTest.java | 72 +++++++++++++++ .../MenuBarOnDisabledFrame.java | 77 ++++++++++++++++ .../MenuBarVisuals/MenuBarVisuals.java | 88 +++++++++++++++++++ .../SetHelpMenuTest/SetHelpMenuTest.java | 88 +++++++++++++++++++ 4 files changed, 325 insertions(+) create mode 100644 test/jdk/java/awt/MenuBar/MenuBarAddRemoveTest/MenuBarAddRemoveTest.java create mode 100644 test/jdk/java/awt/MenuBar/MenuBarOnDisabledFrame/MenuBarOnDisabledFrame.java create mode 100644 test/jdk/java/awt/MenuBar/MenuBarVisuals/MenuBarVisuals.java create mode 100644 test/jdk/java/awt/MenuBar/SetHelpMenuTest/SetHelpMenuTest.java diff --git a/test/jdk/java/awt/MenuBar/MenuBarAddRemoveTest/MenuBarAddRemoveTest.java b/test/jdk/java/awt/MenuBar/MenuBarAddRemoveTest/MenuBarAddRemoveTest.java new file mode 100644 index 0000000000000..fdb9f06e98c76 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/MenuBarAddRemoveTest/MenuBarAddRemoveTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4028130 4112308 + * @summary Test for location of Frame/MenuBar when MenuBar is re-added + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarAddRemoveTest + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; + +public class MenuBarAddRemoveTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Click the left mouse button on the "Re-Add MenuBar" + button several times. + 3. The Frame/MenuBar may repaint or flash, but the location + of its upper left corner should never change. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MenuBarAddRemoveTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("Re-Add MenuBar Test Frame"); + Button b = new Button("Re-Add MenuBar"); + b.addActionListener(e -> f.setMenuBar(createMenuBar())); + f.setMenuBar(createMenuBar()); + f.add(b); + f.pack(); + return f; + } + + private static MenuBar createMenuBar() { + MenuBar bar = new MenuBar(); + bar.add(new Menu("foo")); + return bar; + } +} diff --git a/test/jdk/java/awt/MenuBar/MenuBarOnDisabledFrame/MenuBarOnDisabledFrame.java b/test/jdk/java/awt/MenuBar/MenuBarOnDisabledFrame/MenuBarOnDisabledFrame.java new file mode 100644 index 0000000000000..06f5d96c19e32 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/MenuBarOnDisabledFrame/MenuBarOnDisabledFrame.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6185057 + * @summary Disabling a frame does not disable the menus on the frame, on + * solaris/linux + * @requires os.family != "mac" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarOnDisabledFrame + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +public class MenuBarOnDisabledFrame { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Check if MenuBar is disabled on 'Disabled frame' + Press pass if menu bar is disabled, fail otherwise + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MenuBarOnDisabledFrame::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Disabled frame"); + MenuBar mb = new MenuBar(); + Menu m1 = new Menu("Disabled Menu 1"); + Menu m2 = new Menu("Disabled Menu 2"); + MenuItem m11 = new MenuItem("MenuItem 1.1"); + MenuItem m21 = new MenuItem("MenuItem 2.1"); + Button b = new Button("Disabled button"); + + m1.add(m11); + m2.add(m21); + mb.add(m1); + mb.add(m2); + f.setMenuBar(mb); + f.add(b); + f.setEnabled(false); + f.setSize(300, 300); + return f; + } +} diff --git a/test/jdk/java/awt/MenuBar/MenuBarVisuals/MenuBarVisuals.java b/test/jdk/java/awt/MenuBar/MenuBarVisuals/MenuBarVisuals.java new file mode 100644 index 0000000000000..7663dd0d99be1 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/MenuBarVisuals/MenuBarVisuals.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6180416 + * @summary Tests MenuBar and drop down menu visuals + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarVisuals + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.event.KeyEvent; + +public class MenuBarVisuals { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Look at the MenuBar and traverse the menus using mouse and + keyboard. Then check if following is showing correctly: + 1. Mnemonic label Ctrl+A is NOT drawn for Menu 1/Submenu 1.1 + 2. Mnemonic label Ctrl+B is drawn for + Menu 1/Submenu 1.1/Item 1.1.1 + 3. Mnemonic label Ctrl+C is drawn for Menu1/Item 1.2 + Press PASS if Menu is drawing correctly, FAIL otherwise. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MenuBarVisuals::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("MenuBar Visuals Test"); + MenuBar mb = new MenuBar(); + Menu menu1 = new Menu("Menu 1"); + Menu submenu11 = new Menu("Submenu 1.1"); + MenuItem item111 = new MenuItem("Item 1.1.1"); + MenuItem item112 = new MenuItem("Item 1.1.2"); + MenuItem item12 = new MenuItem("Item 1.2"); + Menu menu2 = new Menu("Menu 2"); + MenuItem item21 = new MenuItem("Item 2.1"); + MenuItem item22 = new MenuItem("Item 2.2"); + item111.setShortcut(new MenuShortcut(KeyEvent.VK_B, false)); + submenu11.add(item111); + submenu11.add(item112); + submenu11.setShortcut(new MenuShortcut(KeyEvent.VK_A, false)); + menu1.add(submenu11); + item12.setShortcut(new MenuShortcut(KeyEvent.VK_C, false)); + menu1.add(item12); + mb.add(menu1); + menu2.add(item21); + menu2.add(item22); + mb.add(menu2); + f.setMenuBar(mb); + f.setSize(300, 300); + return f; + } +} diff --git a/test/jdk/java/awt/MenuBar/SetHelpMenuTest/SetHelpMenuTest.java b/test/jdk/java/awt/MenuBar/SetHelpMenuTest/SetHelpMenuTest.java new file mode 100644 index 0000000000000..fcfc3e80ed34c --- /dev/null +++ b/test/jdk/java/awt/MenuBar/SetHelpMenuTest/SetHelpMenuTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4275843 + * @summary MenuBar doesn't display all of its Menus correctly on Windows + * @requires os.family == "windows" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetHelpMenuTest + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +public class SetHelpMenuTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + An empty frame should be visible. When focused, the MenuBar + should have 5 menus ("one", "two", "three", "Help 2", + "four"). If so, then the test passed. Otherwise, the test + failed. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(SetHelpMenuTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("Help MenuBar Test"); + f.setSize(100, 100); + + MenuBar mb = new MenuBar(); + Menu h1, h2; + + f.setMenuBar(mb); + mb.add(createMenu("one", false)); + mb.add(createMenu("two", false)); + mb.add(createMenu("three", true)); + + mb.add(h1 = createMenu("Help 1", false)); // h1 is HelpMenu + mb.setHelpMenu(h1); + + mb.add(h2 = createMenu("Help 2", false)); // h2 replaced h1 + mb.setHelpMenu(h2); + + mb.add(createMenu("four", false)); + + return f; + } + + private static Menu createMenu(String name, boolean tearOff) { + Menu m = new Menu(name, tearOff); + m.add(new MenuItem(name + " item 1")); + m.add(new MenuItem(name + " item 2")); + m.add(new MenuItem(name + " item 3")); + return m; + } +} From b6e72ff971455f7768c2e1c0fe53d922e5deed38 Mon Sep 17 00:00:00 2001 From: Jamil Nimeh Date: Thu, 3 Oct 2024 17:16:31 +0000 Subject: [PATCH 126/188] 8339403: sun.security.ssl.StatusResponseManager.get swallows interrupt status Reviewed-by: valeriep --- .../security/ssl/StatusResponseManager.java | 28 +++++++++++---- .../ssl/Stapling/StatusResponseManager.java | 4 +-- .../ssl/StatusResponseManagerTests.java | 35 ++++++++++++++++++- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java b/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java index 0632f846cbf71..1baf3264122e4 100644 --- a/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java +++ b/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -257,7 +257,20 @@ Map get(CertStatusRequestType type, } if (!task.isCancelled()) { - StatusInfo info = task.get(); + StatusInfo info; + try { + info = task.get(); + } catch (ExecutionException exc) { + // Check for an underlying cause available and log + // that, otherwise just log the ExecutionException + Throwable cause = Optional.ofNullable( + exc.getCause()).orElse(exc); + if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { + SSLLogger.fine("Exception during OCSP fetch: " + + cause); + } + continue; + } if (info != null && info.responseData != null) { responseMap.put(info.cert, info.responseData.ocspBytes); @@ -272,10 +285,12 @@ Map get(CertStatusRequestType type, } } } - } catch (InterruptedException | ExecutionException exc) { - // Not sure what else to do here + } catch (InterruptedException intex) { + // Log and reset the interrupt state + Thread.currentThread().interrupt(); if (SSLLogger.isOn && SSLLogger.isOn("respmgr")) { - SSLLogger.fine("Exception when getting data: ", exc); + SSLLogger.fine("Interrupt occurred while fetching: " + + intex); } } } @@ -582,8 +597,7 @@ private void addToCache(CertId certId, ResponseCacheEntry entry) { } - static final StaplingParameters processStapling( - ServerHandshakeContext shc) { + static StaplingParameters processStapling(ServerHandshakeContext shc) { StaplingParameters params = null; SSLExtension ext = null; CertStatusRequestType type = null; diff --git a/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java b/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java index 58ebb5b876af8..5555363374ca9 100644 --- a/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java +++ b/test/jdk/sun/security/ssl/Stapling/StatusResponseManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8046321 + * @bug 8046321 8339403 * @library ../../../../java/security/testlibrary * @build CertificateBuilder SimpleOCSPServer * @run main/othervm -Djavax.net.debug=ssl:respmgr java.base/sun.security.ssl.StatusResponseManagerTests diff --git a/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java b/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java index f6b0d1f10e20f..b210cfb26eaed 100644 --- a/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java +++ b/test/jdk/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,7 @@ public static void main(String[] args) throws Exception { put("Clear StatusResponseManager cache", testClearSRM); put("Basic OCSP_MULTI fetch test", testOcspMultiFetch); put("Test Cache Expiration", testCacheExpiry); + put("Test Interrupt while fetching", forceInterruptMainThread); }}; // Create the CAs and OCSP responders @@ -262,6 +263,38 @@ public Map.Entry runTest() { } }; + public static final TestCase forceInterruptMainThread = new TestCase() { + @Override + public Map.Entry runTest() { + StatusResponseManager srm = new StatusResponseManager(); + Boolean pass = Boolean.FALSE; + String message = null; + CertStatusRequest oReq = OCSPStatusRequest.EMPTY_OCSP; + + try { + // Force the interrupt flag to be set on the thread that + // performs the invokeAll in the SRM. + Thread.currentThread().interrupt(); + + // Get OCSP responses for non-root certs in the chain + Map responseMap = srm.get( + CertStatusRequestType.OCSP, oReq, chain, 5000, + TimeUnit.MILLISECONDS); + if (Thread.currentThread().isInterrupted()) { + pass = Boolean.TRUE; + message = "Thread is in expected interrupted state."; + } else { + message = "Missing expectedInterruptedException."; + } + message += " Number of SRM entries: " + responseMap.size(); + } catch (Exception exc) { + message = "Unexpected exception: " + exc; + } + + return new AbstractMap.SimpleEntry<>(pass, message); + } + }; + /** * Creates the PKI components necessary for this test, including * Root CA, Intermediate CA and SSL server certificates, the keystores From 6f459aff453679ee89fd80bb325737d76288e4d2 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Thu, 3 Oct 2024 18:01:22 +0000 Subject: [PATCH 127/188] 8340077: Open source few Checkbox tests - Set2 Reviewed-by: prr, azvegint, psadhukhan --- test/jdk/ProblemList.txt | 3 + .../awt/Checkbox/CheckboxBoxSizeTest.java | 71 ++++++++ .../Checkbox/CheckboxIndicatorSizeTest.java | 168 ++++++++++++++++++ .../awt/Checkbox/CheckboxNullLabelTest.java | 95 ++++++++++ .../Checkbox/CheckboxPreferredSizeTest.java | 67 +++++++ 5 files changed, 404 insertions(+) create mode 100644 test/jdk/java/awt/Checkbox/CheckboxBoxSizeTest.java create mode 100644 test/jdk/java/awt/Checkbox/CheckboxIndicatorSizeTest.java create mode 100644 test/jdk/java/awt/Checkbox/CheckboxNullLabelTest.java create mode 100644 test/jdk/java/awt/Checkbox/CheckboxPreferredSizeTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index bf1c9bd31e7a6..b44eef1e1284c 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -800,3 +800,6 @@ java/awt/PopupMenu/PopupHangTest.java 8340022 windows-all java/awt/Focus/MinimizeNonfocusableWindowTest.java 8024487 windows-all java/awt/Focus/InactiveFocusRace.java 8023263 linux-all java/awt/List/HandlingKeyEventIfMousePressedTest.java 6848358 macosx-all,windows-all +java/awt/Checkbox/CheckboxBoxSizeTest.java 8340870 windows-all +java/awt/Checkbox/CheckboxIndicatorSizeTest.java 8340870 windows-all +java/awt/Checkbox/CheckboxNullLabelTest.java 8340870 windows-all diff --git a/test/jdk/java/awt/Checkbox/CheckboxBoxSizeTest.java b/test/jdk/java/awt/Checkbox/CheckboxBoxSizeTest.java new file mode 100644 index 0000000000000..0d500e5daa16d --- /dev/null +++ b/test/jdk/java/awt/Checkbox/CheckboxBoxSizeTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Checkbox; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; + +/* + * @test + * @bug 4410522 + * @requires (os.family == "windows") + * @summary The box size of the Checkbox control should be the same as + * in Windows native applications. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckboxBoxSizeTest + */ + +public class CheckboxBoxSizeTest { + private static final String INSTRUCTIONS = """ + This test must be run at UI Scale of 100% AND + 150% or greater. + Compare the size of box to any of native apps on Windows + (Eg. Font Dialog Settings on Word). + They should be the same. + + If the sizes are same Press PASS, else Press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("CheckboxBoxSizeTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(CheckboxBoxSizeTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("CheckboxBoxSizeTest"); + Panel panel = new Panel(new FlowLayout()); + Checkbox checkbox = new Checkbox("Compare the box size"); + panel.add(checkbox); + frame.add(panel); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/Checkbox/CheckboxIndicatorSizeTest.java b/test/jdk/java/awt/Checkbox/CheckboxIndicatorSizeTest.java new file mode 100644 index 0000000000000..3456e7e040d17 --- /dev/null +++ b/test/jdk/java/awt/Checkbox/CheckboxIndicatorSizeTest.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4090493 + * @summary Test for Checkbox indicator size + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckboxIndicatorSizeTest + */ + +public class CheckboxIndicatorSizeTest implements ActionListener { + private static final String INSTRUCTIONS = """ + Indicator size of Checkbox depends + on the platform font used to render the label. + + In the frame you can see a group of checkboxes + and radio buttons. + Verify that all checkboxes and radio buttons have + indicators of the same size and proportional to + the uiScale and/or font-size. + + Use menu to change the font size and the indicators + should scale proportionally. + + If there is a bug, the checkbox/radiobutton with + dingbats label will have a smaller indicator. + + Press PASS if the above conditions are true else Press FAIL. + """; + private static Frame frame; + private static Panel testPanel; + + public static void main(String[] args) throws Exception { + + CheckboxIndicatorSizeTest obj = new CheckboxIndicatorSizeTest(); + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 3) + .columns(60) + .testUI(obj::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private Frame createAndShowUI() { + frame = new Frame("CheckboxIndicatorSizeTest"); + + testPanel = new Panel(new GridLayout(0, 1)); + testPanel.setFont(new Font("Dialog", Font.PLAIN, 12)); + frame.add(testPanel); + + MenuBar menuBar = new MenuBar(); + Menu fontSizeMenu = new Menu("FontSize"); + + MenuItem size10 = new MenuItem("10"); + size10.addActionListener(this); + fontSizeMenu.add(size10); + + MenuItem size12 = new MenuItem("12"); + size12.addActionListener(this); + fontSizeMenu.add(size12); + + MenuItem size14 = new MenuItem("14"); + size14.addActionListener(this); + fontSizeMenu.add(size14); + + MenuItem size18 = new MenuItem("18"); + size18.addActionListener(this); + fontSizeMenu.add(size18); + + MenuItem size24 = new MenuItem("24"); + size24.addActionListener(this); + fontSizeMenu.add(size24); + + MenuItem size36 = new MenuItem("36"); + size36.addActionListener(this); + fontSizeMenu.add(size36); + + menuBar.add(fontSizeMenu); + frame.setMenuBar(menuBar); + + Checkbox cbEnglishOnly + = new Checkbox("Toggle", true); + Checkbox cbDingbatsOnly + = new Checkbox("\u274a\u274b\u274c\u274d", true); + Checkbox cbEnglishDingbats + = new Checkbox("Toggle \u274a\u274d", true); + Checkbox cbDingbatsEnglish + = new Checkbox("\u274a\u274d toggle", true); + + CheckboxGroup radioGroup = new CheckboxGroup(); + Checkbox rbEnglishOnly + = new Checkbox("Radio", true, radioGroup); + Checkbox rbDingbatsOnly + = new Checkbox("\u274a\u274b\u274c\u274d", false, radioGroup); + Checkbox rbEnglishDingbats + = new Checkbox("Radio \u274a\u274d", false, radioGroup); + Checkbox rbDingbatsEnglish + = new Checkbox("\u274a\u274d radio", false, radioGroup); + + Label cbLabel = new Label("Checkboxes"); + cbLabel.setBackground(Color.YELLOW); + testPanel.add(cbLabel); + testPanel.add(cbEnglishOnly); + testPanel.add(cbDingbatsOnly); + testPanel.add(cbEnglishDingbats); + testPanel.add(cbDingbatsEnglish); + + Label rbLabel = new Label("Radio buttons"); + rbLabel.setBackground(Color.YELLOW); + testPanel.add(rbLabel); + testPanel.add(rbEnglishOnly); + testPanel.add(rbDingbatsOnly); + testPanel.add(rbEnglishDingbats); + testPanel.add(rbDingbatsEnglish); + + frame.pack(); + return frame; + } + + @Override + public void actionPerformed(ActionEvent e) { + String sizeStr = e.getActionCommand(); + int size = Integer.parseInt(sizeStr); + Font oldFont = testPanel.getFont(); + Font newFont = new Font(oldFont.getName(), oldFont.getStyle(), size); + testPanel.setFont(newFont); + frame.pack(); + frame.setVisible(true); + } +} diff --git a/test/jdk/java/awt/Checkbox/CheckboxNullLabelTest.java b/test/jdk/java/awt/Checkbox/CheckboxNullLabelTest.java new file mode 100644 index 0000000000000..c5cb7c278297a --- /dev/null +++ b/test/jdk/java/awt/Checkbox/CheckboxNullLabelTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Panel; + +/* + * @test + * @bug 4383735 + * @summary Checkbox buttons are too small with java 1.3 and 1.4 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckboxNullLabelTest + */ + +public class CheckboxNullLabelTest { + private static final String INSTRUCTIONS = """ + Please look at the frame titled 'CheckboxNullLabelTest'. + Check if all the check boxes in each group + (of 3 check boxes) have the same size. + + If the size of labeled check box is NOT the same as + the size of non-labeled Press FAIL otherwise Press PASS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(35) + .testUI(CheckboxNullLabelTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame f = new Frame("CheckboxNullLabelTest"); + f.setLayout(new BorderLayout()); + f.add(new CheckboxTest(Color.gray, new Font(null, 0, 12)), "North"); + f.add(new CheckboxTest(Color.green, new Font(null, 0, 18)), "South"); + f.add(new CheckboxTest(Color.red, new Font(null, 0, 24)), "East"); + f.add(new CheckboxTest(Color.white, new Font(null, 0, 30)), "West"); + f.add(new CheckboxTest(f.getBackground(), new Font(null, 0, 36)), "Center"); + f.setSize(600, 450); + return f; + } + + private static class CheckboxTest extends Panel { + Checkbox cb1, cb2, cb3; + + CheckboxTest(Color background, Font font) { + setBackground(background); + CheckboxGroup cbg = new CheckboxGroup(); + + cb1 = new Checkbox(null, cbg, true); + cb1.setFont(font); + + cb2 = new Checkbox("", cbg, true); + cb2.setFont(font); + + cb3 = new Checkbox("Label", cbg, false); + cb3.setFont(font); + + add(cb1); + add(cb2); + add(cb3); + } + } +} diff --git a/test/jdk/java/awt/Checkbox/CheckboxPreferredSizeTest.java b/test/jdk/java/awt/Checkbox/CheckboxPreferredSizeTest.java new file mode 100644 index 0000000000000..dd61b52aaedbe --- /dev/null +++ b/test/jdk/java/awt/Checkbox/CheckboxPreferredSizeTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Checkbox; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; + +/* + * @test + * @bug 4304049 + * @summary tests that Checkbox fits into its preferred size entirely + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckboxPreferredSizeTest + */ + +public class CheckboxPreferredSizeTest { + private static final String INSTRUCTIONS = """ + As the test starts, ensure that the + whole checkbox with all its text is visible. + If the checkbox is entirely visible, press PASS else, + press FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(35) + .testUI(CheckboxPreferredSizeTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame frame = new Frame("Checkbox Preferred Size Test"); + frame.setBackground(Color.BLUE); + Checkbox box = new Checkbox("Checkbox_With_Some_Size"); + box.setFont(new Font("Helvetica", Font.PLAIN, 36)); + box.setBackground(Color.RED); + frame.add(box); + frame.pack(); + return frame; + } +} From e89fd1d2ceff82952a4859c0febe902412fcf064 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Thu, 3 Oct 2024 19:22:28 +0000 Subject: [PATCH 128/188] 8341128: open source some 2d graphics tests Reviewed-by: psadhukhan --- .../awt/Graphics2D/BasicStrokeValidate.java | 87 +++++++++ .../DrawImageIAETest/DrawImageIAETest.java | 169 ++++++++++++++++++ .../awt/Graphics2D/DrawImageIAETest/duke.gif | Bin 0 -> 1929 bytes .../ImageRendering/ImageRendering.java | 66 +++++++ .../awt/Graphics2D/ImageRendering/snooze.gif | Bin 0 -> 2859 bytes .../awt/Graphics2D/ScaledThinLineTest.java | 82 +++++++++ test/jdk/java/awt/Graphics2D/TextPerf.java | 159 ++++++++++++++++ 7 files changed, 563 insertions(+) create mode 100644 test/jdk/java/awt/Graphics2D/BasicStrokeValidate.java create mode 100644 test/jdk/java/awt/Graphics2D/DrawImageIAETest/DrawImageIAETest.java create mode 100644 test/jdk/java/awt/Graphics2D/DrawImageIAETest/duke.gif create mode 100644 test/jdk/java/awt/Graphics2D/ImageRendering/ImageRendering.java create mode 100644 test/jdk/java/awt/Graphics2D/ImageRendering/snooze.gif create mode 100644 test/jdk/java/awt/Graphics2D/ScaledThinLineTest.java create mode 100644 test/jdk/java/awt/Graphics2D/TextPerf.java diff --git a/test/jdk/java/awt/Graphics2D/BasicStrokeValidate.java b/test/jdk/java/awt/Graphics2D/BasicStrokeValidate.java new file mode 100644 index 0000000000000..251f14e5081bd --- /dev/null +++ b/test/jdk/java/awt/Graphics2D/BasicStrokeValidate.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4363534 + * @summary This test verifies that setting a non-thin-line BasicStroke + * on a Graphics2D obtained from a BufferedImage will correctly validate + * the pipelines for the line-widening pipeline even if that is the only + * non-default attribute on the graphics. + * + */ + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; + +public class BasicStrokeValidate { + + public static final int TESTW = 100; + public static final int TESTH = 100; + + public static void main(String[] args) { + BufferedImage bi1 = createImage(false); + BufferedImage bi2 = createImage(true); + compare(bi1, bi2); // images should differ + } + + static BufferedImage createImage(boolean dashed) { + BufferedImage bi = new BufferedImage(TESTW, TESTH, BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = bi.createGraphics(); + g2d.setColor(Color.white); + g2d.fillRect(0, 0, TESTW, TESTH); + g2d.setColor(Color.black); + if (dashed) { + g2d.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_SQUARE, + BasicStroke.JOIN_MITER, 10.0f, + new float[] {2.5f, 3.5f}, + 0.0f)); + } + g2d.drawRect(10, 10, TESTW-20, TESTH-20); + g2d.setStroke(new BasicStroke(10f)); + g2d.drawRect(20, 20, TESTW-40, TESTH-40); + return bi; + } + + static void compare(BufferedImage i1, BufferedImage i2) { + boolean same = true; + int w = i1.getWidth(), h = i1.getHeight(); + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + int p1 = i1.getRGB(x, y); + int p2 = i2.getRGB(x, y); + if (p1 != p2) { + same = false; + } + } + if (!same) { + break; + } + } + if (same) { + throw new RuntimeException("No difference"); + } + } +} diff --git a/test/jdk/java/awt/Graphics2D/DrawImageIAETest/DrawImageIAETest.java b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/DrawImageIAETest.java new file mode 100644 index 0000000000000..af7ebae72a6c8 --- /dev/null +++ b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/DrawImageIAETest.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4191004 + * @summary Tests that no IllegalArgumentException is thrown when calling + * drawImage with certain conditions + * @key headful + */ + +import java.awt.AlphaComposite; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.awt.geom.GeneralPath; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.JFrame; +import javax.swing.JPanel; + +public class DrawImageIAETest extends Frame { + + static String filename = "/duke.gif"; + private volatile Image dimg; + private volatile BufferedImage bimg; + static volatile DrawImageIAETest app; + static volatile JFrame jframe; + static volatile boolean passed = true; + static volatile Exception exception = null; + static volatile CountDownLatch imageLatch = new CountDownLatch(1); + + DrawImageIAETest(String title) { + super(title); + } + + public static void main(final String[] args) throws Exception { + EventQueue.invokeAndWait(DrawImageIAETest:: createUI); + imageLatch.await(3, TimeUnit.MILLISECONDS); + try { + if (!passed) { + throw new RuntimeException("Test FAILED: exception caught:" + exception); + } + } finally { + if (jframe != null) { + EventQueue.invokeAndWait(jframe::dispose); + } + if (app != null) { + EventQueue.invokeAndWait(app::dispose); + } + } + } + + static void createUI() { + app = new DrawImageIAETest("DrawImageIAETest"); + app.setLayout (new BorderLayout()); + app.setSize(200,200); + app.setLocationRelativeTo(null); + app.setVisible(true); + + String file; + try { + String dir = System.getProperty("test.src", + System.getProperty("user.dir")); + file = dir + filename; + } catch (Exception e) { + file = "." + filename; + } + + Image textureAlphaSource = null; + MediaTracker tracker = new MediaTracker(app); + app.dimg = Toolkit.getDefaultToolkit().getImage(file); + tracker.addImage(app.dimg, 1); + try { + tracker.waitForAll(); + imageLatch.countDown(); + } catch (Exception e) { + System.err.println("Can't load images"); + } + + if (app.dimg == null) { + passed = false; + return; + } + + jframe = new JFrame("Test DrawImageIAETest"); + jframe.setSize(300, 300); + JPanel jpanel; + jframe.getContentPane().add("Center", jpanel = new JPanel() { + public void paint(Graphics _g) { + Graphics2D g = (Graphics2D)_g; + Dimension d = getSize(); + Graphics2D g2 = app.createGraphics2D(d.width, d.height); + app.drawDemo(d.width, d.height, g2); + g2.dispose(); + g.drawImage(app.bimg, 0, 0, app); + } + }); + jpanel.setSize(140, 140); + jframe.setVisible(true); + } + + public void drawDemo(int w, int h, Graphics2D g2) { + GeneralPath p1 = new GeneralPath(); + GeneralPath p2 = new GeneralPath(); + + int dukeX = 73; + int dukeY = 26; + + double x = 118; + double y = 17; + double ew = 50; + double eh = 48; + + p1.append(new Ellipse2D.Double(x, y, ew, eh), false); + p2.append(new Rectangle2D.Double(x+5, y+5, ew-10, eh-10),false); + + g2.setClip(p1); + g2.clip(p2); + try { + g2.drawImage(dimg, dukeX, dukeY, null); + } catch (IllegalArgumentException e) { + passed = false; + exception = e; + } + } + + public Graphics2D createGraphics2D(int w, int h) { + Graphics2D g2 = null; + if (bimg == null || bimg.getWidth() != w || bimg.getHeight() != h) { + bimg = (BufferedImage) createImage(w, h); + } + g2 = bimg.createGraphics(); + g2.setBackground(getBackground()); + g2.clearRect(0, 0, w, h); + g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); + return g2; + } +} diff --git a/test/jdk/java/awt/Graphics2D/DrawImageIAETest/duke.gif b/test/jdk/java/awt/Graphics2D/DrawImageIAETest/duke.gif new file mode 100644 index 0000000000000000000000000000000000000000..ed32e0ff79b05c07b82863ce6fb07fa9898adaa2 GIT binary patch literal 1929 zcmWlYe^AtB8pi`HvM4_?{J2I$8$dLc1#@!R2zwgXMWdj^k;9xr+bDW&4{JlE8WpDj z7F-cwwK{H<)?L&#SJz$!;hJ{%BY2FYf)Wp^xl?aq!5Xcdi$c#hV~>m9_n-Hl=Xsy+ z=li^?*Q~;pZ+R1N1J40KRkeWM7ew3~jLM24A{CM-A}~TzqzYpq&od0GC=z71!w_=b z-==B0rt2t*nA}((5YSLs6a*Z@X__WqiSjTW6oLo{5km&|K1mGAimYjhs#wwZtvV8SV~7LCFpgub+-TTAk%UQb0dE_cj+pc?!+0o?qG$?% zVFD)%!w7Z;g)ndE8Uk6Aky=+kLaUQ{UW`XS?Nn*s@SQ{VmFgGdkV{&&98EcEQ5hjc@H$`e)fX zj@&GdchxpMUo|-A^M4iBP3(#Ib53Ap?5{nGT7SBA_V!o!TTzL5R~FUWe)4X?@iTd8 z1;TcF^rQLj?4p0uy?@ikb2eUSXdHVa_jIn=@W%a<6~57D>am6&Z!{lzc=@ZbuGB8` zpU38H8d~@82Da!+qdYG5ls&Cx?~|oPMnbqTHMw%I*KlV~?fc{rSwe29?Om}fsknG# z@n5IwY=4Mx>>0WJLG>=yJX^WbHA30iQ$H!X)3<4K zBe1|sf3NKKTS;)mg{$k(2eDJG^u5=&x{@M!V>EWgzRA((>}?o{WQBehp1mIHU!BGG zYz5_6B(+KIVdCVoum2ItM&gXZd+SB^vQTN=a zeYbbah=i-xCho2{4Pazv_i%2mH`EkM{r8XYDLbdY@(a7Ud}$%!$QrTN_DqwNXA9~g zTGKxKyfto7NDp;5A3O5zgb(hyxjN@OAG!(zy^*Ug4!yjF=Y*8aHA@ovB1({&a4;sR zTf1CVC{>Pgy`m$lG;P1$pC_6F7u%iP+qz0q4{lXT`i9g-ThiYgO^GXC`f?JNo*|@p zr{b%U-tSKw99q0|YJa9{Va?`H{IaNICo>p5lGEY*+IDR4bfIUwq~CTRuC_mGWA%~W zea{@eKJ(Iq^7MvdsPsR%&vt$@4i&s?bPptz#y#!FcRZEaMS0WFTyXMCUEfsNxnJ_9 zPwpt`Er4O>``2G{7=4r1GCSTO8#0xw+{<^L4X(K8y1wKj72KLrYD}Y7SJuY7y==wf z;UkI5?(v?h+4r;vR{P*U`ul~=D@U7K5$eV8c!%rX-38vE>azU80UrhFXCv#d`(ylZS4+i2a^vI91MTIxCx%9gd2&N&D9RC&xcpx8#f=GZv%9;F z#?CEVT%UV$nk;L%RJA+d=f8ZB@U*Xz-TZbG?HKKT(VJZMBH!)$#qRuwbFc%Aljqha zoNBs8od~V$_^vux0ZSk!iP!hI($t35SxY8`FV{pxCjpU}Ova2VIg1&>V)CvvMb_ 2000) { + throw new RuntimeException("Paint time is " + paintTime + "ms"); + } + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + + static void createUI() { + frame = new Frame("TextPerf"); + frame.setLayout(new BorderLayout()); + TextPerf tp = new TextPerf(); + frame.add(tp, BorderLayout.CENTER); + frame.pack(); + frame.setVisible(true); + } + + public Dimension getPreferredSize() { + Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); + return new Dimension(d.width - 50, d.height - 50); + } + + static Font[] fonts = { + new Font(Font.SERIF, Font.PLAIN, 10), + new Font(Font.SANS_SERIF, Font.PLAIN, 10), + new Font(Font.MONOSPACED, Font.ITALIC, 10), + new Font(Font.SERIF, Font.PLAIN, 14), + new Font(Font.SERIF, Font.BOLD, 12), + }; + + public void paint(Graphics g1) { + + Graphics2D g = (Graphics2D)g1; + String text = "Hello,_Wgjpqy!"; + Toolkit.getDefaultToolkit().sync(); + long startTime = System.currentTimeMillis(); + FontMetrics[] cachedMetrics = new FontMetrics[fonts.length]; + Dimension size = getSize(); + int prim = 0; + int spaceWidth = 5; + Color cols[] = { Color.red, Color.blue, Color.yellow, + Color.green, Color.pink, Color.orange} ; + + for (int y = 20; y < size.height; y += 20) { + int i = 0; + for (int x = 0; x < size.width; i++) { + Font font = fonts[i % fonts.length]; + FontMetrics metrics = cachedMetrics[i % fonts.length]; + if (metrics == null) { + metrics = g.getFontMetrics(font); + cachedMetrics[i % fonts.length] = metrics; + } + + g.setFont(font); + g.setColor(cols[i % cols.length]); + switch (prim++) { + case 0: g.drawString(text, x, y); + break; + case 1: g.drawBytes(text.getBytes(), 0, text.length(), x, y); + break; + case 2: char[] chs= new char[text.length()]; + text.getChars(0,text.length(), chs, 0); + g.drawChars(chs, 0, text.length(), x, y); + break; + case 3: GlyphVector gv = font.createGlyphVector( + g.getFontRenderContext(), text); + g.drawGlyphVector(gv, (float)x, (float)y); + default: prim = 0; + } + + x += metrics.stringWidth(text) + spaceWidth; + } + } + + // Draw some transformed text to verify correct bounds calculated + AffineTransform at = AffineTransform.getTranslateInstance(50, 50); + at.scale(7.0,7.0); + at.rotate(1.0); + g.transform(at); + g.setColor(Color.black); + Font font = new Font(Font.SERIF, Font.PLAIN, 20); + RenderingHints hints = new RenderingHints(null); + hints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.setRenderingHints(hints); + g.setFont(font); + FontMetrics metrics = g.getFontMetrics(font); + g.drawString("Java", 5,5); + + Toolkit.getDefaultToolkit().sync(); + long endTime = System.currentTimeMillis(); + paintTime = endTime - startTime; + String msg = "repainted in " + paintTime + " milliseconds"; + System.out.println(msg); + System.out.flush(); + + paintLatch.countDown(); + } +} From 6bc3971f646031194a1e30f175a69a0202dc4947 Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Thu, 3 Oct 2024 19:36:06 +0000 Subject: [PATCH 129/188] 8341316: [macos] javax/swing/ProgressMonitor/ProgressMonitorEscapeKeyPress.java fails sometimes in macos Reviewed-by: prr --- .../ProgressMonitorEscapeKeyPress.java | 121 +++++++++--------- 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/test/jdk/javax/swing/ProgressMonitor/ProgressMonitorEscapeKeyPress.java b/test/jdk/javax/swing/ProgressMonitor/ProgressMonitorEscapeKeyPress.java index 4ea1f48ae7a34..77fac43d26263 100644 --- a/test/jdk/javax/swing/ProgressMonitor/ProgressMonitorEscapeKeyPress.java +++ b/test/jdk/javax/swing/ProgressMonitor/ProgressMonitorEscapeKeyPress.java @@ -29,66 +29,64 @@ * @run main ProgressMonitorEscapeKeyPress */ -import java.awt.AWTException; -import java.awt.EventQueue; -import java.awt.Robot; -import java.awt.event.KeyEvent; + import javax.swing.JFrame; import javax.swing.ProgressMonitor; import javax.swing.SwingUtilities; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; public class ProgressMonitorEscapeKeyPress { + static volatile int counter = 0; static ProgressMonitor monitor; - static int counter = 0; - static TestThread robotThread; + static TestThread testThread; static JFrame frame; + static CountDownLatch progressLatch; + static Robot robot; public static void main(String[] args) throws Exception { - - createTestUI(); - - monitor = new ProgressMonitor(frame, "Progress", null, 0, 100); - - robotThread = new TestThread(); - robotThread.start(); - - for (counter = 0; counter <= 100; counter += 10) { - Thread.sleep(1000); - - EventQueue.invokeAndWait(new Runnable() { - @Override - public void run() { - if (!monitor.isCanceled()) { - monitor.setProgress(counter); - System.out.println("Progress bar is in progress"); - } - } - }); - - if (monitor.isCanceled()) { - break; + try { + progressLatch = new CountDownLatch(20); + createTestUI(); + robot = new Robot(); + robot.setAutoDelay(50); + robot.setAutoWaitForIdle(true); + testThread = new TestThread(); + testThread.start(); + Thread.sleep(100); + if (progressLatch.await(15, TimeUnit.SECONDS)) { + System.out.println("Progress monitor completed 20%, lets press Esc..."); + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + System.out.println("ESC pressed...."); + } else { + System.out.println("Failure : No status available from Progress monitor..."); + throw new RuntimeException( + "Can't get the status from Progress monitor even after waiting too long.."); } - } - - disposeTestUI(); - if (counter >= monitor.getMaximum()) { - throw new RuntimeException("Escape key did not cancel the ProgressMonitor"); + if (counter >= monitor.getMaximum()) { + throw new RuntimeException("Escape key did not cancel the ProgressMonitor"); + } + System.out.println("Test Passed..."); + } finally { + disposeTestUI(); } } - private static void createTestUI() throws Exception { - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - frame = new JFrame("Test"); - frame.setSize(300, 300); - frame.setLocationByPlatform(true); - frame.setVisible(true); - }}); - } + private static void createTestUI() throws Exception { + SwingUtilities.invokeAndWait(() -> { + frame = new JFrame("Test"); + frame.setSize(300, 300); + monitor = new ProgressMonitor(frame, "Progress", "1", 0, 100); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setLocationByPlatform(true); + }); + } private static void disposeTestUI() throws Exception { @@ -100,26 +98,25 @@ private static void disposeTestUI() throws Exception { class TestThread extends Thread { - - Robot testRobot; - - TestThread() throws AWTException { - super(); - testRobot = new Robot(); - } - @Override public void run() { - try { - // Sleep for 5 seconds - so that the ProgressMonitor starts - Thread.sleep(5000); - - // Press and release Escape key - testRobot.keyPress(KeyEvent.VK_ESCAPE); - testRobot.delay(20); - testRobot.keyRelease(KeyEvent.VK_ESCAPE); - } catch (InterruptedException ex) { - throw new RuntimeException("Exception in TestThread"); + System.out.println("TestThread started........."); + for (ProgressMonitorEscapeKeyPress.counter = 0; + ProgressMonitorEscapeKeyPress.counter <= 100; + ProgressMonitorEscapeKeyPress.counter += 1) { + ProgressMonitorEscapeKeyPress.robot.delay(100); + ProgressMonitor monitor = ProgressMonitorEscapeKeyPress.monitor; + if (!monitor.isCanceled()) { + monitor.setNote("" + ProgressMonitorEscapeKeyPress.counter); + monitor.setProgress(ProgressMonitorEscapeKeyPress.counter); + ProgressMonitorEscapeKeyPress.progressLatch.countDown(); + System.out.println("Progress bar is in progress....." + + ProgressMonitorEscapeKeyPress.counter + "%"); + } + if (monitor.isCanceled()) { + System.out.println("$$$$$$$$$$$$$$$ Monitor canceled"); + break; + } } } } From 10402b43c764456f2ec358a8b434654df545a8a1 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Thu, 3 Oct 2024 20:25:47 +0000 Subject: [PATCH 130/188] 8341489: ProblemList runtime/cds/appcds/DumpRuntimeClassesTest.java in Xcomp mode Reviewed-by: matsaave --- test/hotspot/jtreg/ProblemList-Xcomp.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index cb6bb2b4cca58..ab227d7b0243f 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -54,4 +54,6 @@ compiler/cha/TypeProfileFinalMethod.java 8341039 generic-all gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64 +runtime/cds/appcds/DumpRuntimeClassesTest.java 8341452 generic-all + runtime/condy/escapeAnalysis/TestEscapeCondy.java 8339694 generic-all From 4ded28380b6756e0679d80706f76bd6e78c370b9 Mon Sep 17 00:00:00 2001 From: Dhamoder Nalla Date: Fri, 4 Oct 2024 04:50:54 +0000 Subject: [PATCH 131/188] 8338136: Hotspot should support multiple large page sizes on Windows Reviewed-by: dholmes, djelinski --- src/hotspot/os/windows/globals_windows.hpp | 4 + src/hotspot/os/windows/os_windows.cpp | 51 +++++++-- src/hotspot/os/windows/os_windows.hpp | 2 + .../hotspot/gtest/runtime/test_os_windows.cpp | 108 ++++++++++++++++++ 4 files changed, 153 insertions(+), 12 deletions(-) diff --git a/src/hotspot/os/windows/globals_windows.hpp b/src/hotspot/os/windows/globals_windows.hpp index 78cbac6e9ccc5..8f0a6261cc0db 100644 --- a/src/hotspot/os/windows/globals_windows.hpp +++ b/src/hotspot/os/windows/globals_windows.hpp @@ -38,6 +38,10 @@ product(bool, UseAllWindowsProcessorGroups, false, \ "Use all processor groups on supported Windows versions") \ \ +product(bool, EnableAllLargePageSizesForWindows, false, \ + "Enable support for multiple large page sizes on " \ + "Windows Server") \ + \ product(bool, UseOSErrorReporting, false, \ "Let VM fatal error propagate to the OS (ie. WER on Windows)") diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 817757f1ac6a2..6b935f06fa357 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3126,7 +3126,7 @@ class NUMANodeListHolder { static size_t _large_page_size = 0; -static bool request_lock_memory_privilege() { +bool os::win32::request_lock_memory_privilege() { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, os::current_process_id()); @@ -3310,14 +3310,14 @@ static char* allocate_pages_individually(size_t bytes, char* addr, DWORD flags, return p_buf; } -static size_t large_page_init_decide_size() { +size_t os::win32::large_page_init_decide_size() { // print a warning if any large page related flag is specified on command line bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) || !FLAG_IS_DEFAULT(LargePageSizeInBytes); -#define WARN(msg) if (warn_on_failure) { warning(msg); } +#define WARN(...) if (warn_on_failure) { warning(__VA_ARGS__); } - if (!request_lock_memory_privilege()) { + if (!os::win32::request_lock_memory_privilege()) { WARN("JVM cannot use large page memory because it does not have enough privilege to lock pages in memory."); return 0; } @@ -3328,15 +3328,26 @@ static size_t large_page_init_decide_size() { return 0; } -#if defined(IA32) || defined(AMD64) - if (size > 4*M || LargePageSizeInBytes > 4*M) { +#if defined(IA32) + if (size > 4 * M || LargePageSizeInBytes > 4 * M) { WARN("JVM cannot use large pages bigger than 4mb."); return 0; } +#elif defined(AMD64) + if (!EnableAllLargePageSizesForWindows) { + if (size > 4 * M || LargePageSizeInBytes > 4 * M) { + WARN("JVM cannot use large pages bigger than 4mb."); + return 0; + } + } #endif - if (LargePageSizeInBytes > 0 && LargePageSizeInBytes % size == 0) { - size = LargePageSizeInBytes; + if (LargePageSizeInBytes > 0) { + if (LargePageSizeInBytes % size == 0) { + size = LargePageSizeInBytes; + } else { + WARN("The specified large page size (%d) is not a multiple of the minimum large page size (%d), defaulting to minimum page size.", LargePageSizeInBytes, size); + } } #undef WARN @@ -3349,12 +3360,23 @@ void os::large_page_init() { return; } - _large_page_size = large_page_init_decide_size(); + _large_page_size = os::win32::large_page_init_decide_size(); const size_t default_page_size = os::vm_page_size(); if (_large_page_size > default_page_size) { +#if !defined(IA32) + if (EnableAllLargePageSizesForWindows) { + size_t min_size = GetLargePageMinimum(); + + // Populate _page_sizes with large page sizes less than or equal to _large_page_size, ensuring each page size is double the size of the previous one. + for (size_t page_size = min_size; page_size < _large_page_size; page_size *= 2) { + _page_sizes.add(page_size); + } + } +#endif + _page_sizes.add(_large_page_size); } - + // Set UseLargePages based on whether a large page size was successfully determined UseLargePages = _large_page_size != 0; } @@ -3618,7 +3640,6 @@ static char* reserve_large_pages_aligned(size_t size, size_t alignment, bool exe char* os::pd_reserve_memory_special(size_t bytes, size_t alignment, size_t page_size, char* addr, bool exec) { assert(UseLargePages, "only for large pages"); - assert(page_size == os::large_page_size(), "Currently only support one large page size on Windows"); assert(is_aligned(addr, alignment), "Must be"); assert(is_aligned(addr, page_size), "Must be"); @@ -3627,11 +3648,17 @@ char* os::pd_reserve_memory_special(size_t bytes, size_t alignment, size_t page_ return nullptr; } + // Ensure GetLargePageMinimum() returns a valid positive value + size_t large_page_min = GetLargePageMinimum(); + if (large_page_min <= 0) { + return nullptr; + } + // The requested alignment can be larger than the page size, for example with G1 // the alignment is bound to the heap region size. So this reservation needs to // ensure that the requested alignment is met. When there is a requested address // this solves it self, since it must be properly aligned already. - if (addr == nullptr && alignment > page_size) { + if (addr == nullptr && alignment > large_page_min) { return reserve_large_pages_aligned(bytes, alignment, exec); } diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp index 3bc5ab9eef1f3..1d5237243000b 100644 --- a/src/hotspot/os/windows/os_windows.hpp +++ b/src/hotspot/os/windows/os_windows.hpp @@ -65,6 +65,8 @@ class os::win32 { static void setmode_streams(); static bool is_windows_11_or_greater(); static bool is_windows_server_2022_or_greater(); + static bool request_lock_memory_privilege(); + static size_t large_page_init_decide_size(); static int windows_major_version() { assert(_major_version > 0, "windows version not initialized."); return _major_version; diff --git a/test/hotspot/gtest/runtime/test_os_windows.cpp b/test/hotspot/gtest/runtime/test_os_windows.cpp index d611b5287a9da..c7e99bcdbc5dd 100644 --- a/test/hotspot/gtest/runtime/test_os_windows.cpp +++ b/test/hotspot/gtest/runtime/test_os_windows.cpp @@ -722,6 +722,114 @@ TEST_VM(os_windows, processor_count) { } } +TEST_VM(os_windows, large_page_init_multiple_sizes) { + // Call request_lock_memory_privilege() and check the result + if (!os::win32::request_lock_memory_privilege()) { + GTEST_SKIP() << "Skipping test because lock memory privilege is not granted."; + } + // Set globals to make sure we hit the correct code path + AutoSaveRestore guardUseLargePages(UseLargePages); + AutoSaveRestore guardEnableAllLargePageSizesForWindows(EnableAllLargePageSizesForWindows); + AutoSaveRestore guardLargePageSizeInBytes(LargePageSizeInBytes); + FLAG_SET_CMDLINE(UseLargePages, true); + FLAG_SET_CMDLINE(EnableAllLargePageSizesForWindows, true); + + // Determine the minimum page size + const size_t min_size = GetLargePageMinimum(); + + // End the test if GetLargePageMinimum returns 0 + if (min_size == 0) { + GTEST_SKIP() << "Large pages are not supported on this system."; + return; + } + + // Set LargePageSizeInBytes to 4 times the minimum page size + FLAG_SET_CMDLINE(LargePageSizeInBytes, 4 * min_size); // Set a value for multiple page sizes + + // Initialize large page settings + os::large_page_init(); + + // Verify that large pages are enabled + EXPECT_TRUE(UseLargePages) << "UseLargePages should be true after initialization for LargePageSizeInBytes = 4 * min_size"; + + // Verify that decided_large_page_size is greater than the default page size + const size_t default_page_size = os::vm_page_size(); + size_t decided_large_page_size = os::win32::large_page_init_decide_size(); + EXPECT_GT(decided_large_page_size, default_page_size) << "Large page size should be greater than the default page size for LargePageSizeInBytes = 4 * min_size"; + +#if !defined(IA32) + size_t page_size_count = 0; + size_t page_size = os::page_sizes().largest(); + + do { + ++page_size_count; + page_size = os::page_sizes().next_smaller(page_size); + } while (page_size >= os::page_sizes().smallest()); + + EXPECT_GT(page_size_count, 1u) << "There should be multiple large page sizes available."; + + size_t large_page_size = decided_large_page_size; + + for (size_t page_size = os::page_sizes().largest(); page_size >= min_size; page_size = os::page_sizes().next_smaller(page_size)) { + EXPECT_TRUE(page_size % min_size == 0) << "Each page size should be a multiple of the minimum large page size."; + EXPECT_LE(page_size, large_page_size) << "Page size should not exceed the determined large page size."; + } +#endif +} + +TEST_VM(os_windows, large_page_init_decide_size) { + // Initial setup + // Call request_lock_memory_privilege() and check the result + if (!os::win32::request_lock_memory_privilege()) { + GTEST_SKIP() << "Skipping test because lock memory privilege is not granted."; + } + AutoSaveRestore guardUseLargePages(UseLargePages); + AutoSaveRestore guardLargePageSizeInBytes(LargePageSizeInBytes); + FLAG_SET_CMDLINE(UseLargePages, true); + FLAG_SET_CMDLINE(LargePageSizeInBytes, 0); // Reset to default + + // Test for large page support + size_t decided_size = os::win32::large_page_init_decide_size(); + size_t min_size = GetLargePageMinimum(); + if (min_size == 0) { + EXPECT_EQ(decided_size, 0) << "Expected decided size to be 0 when large page is not supported by the processor"; + return; + } + + // Scenario 1: Test with 2MB large page size + if (min_size == 2 * M) { + FLAG_SET_CMDLINE(LargePageSizeInBytes, 2 * M); // Set large page size to 2MB + decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size + EXPECT_EQ(decided_size, 2 * M) << "Expected decided size to be 2M when large page and OS reported size are both 2M"; + } + + // Scenario 2: Test with 1MB large page size + if (min_size == 2 * M) { + FLAG_SET_CMDLINE(LargePageSizeInBytes, 1 * M); // Set large page size to 1MB + decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size + EXPECT_EQ(decided_size, 2 * M) << "Expected decided size to be 2M when large page is 1M and OS reported size is 2M"; + } + +#if defined(IA32) || defined(AMD64) + FLAG_SET_CMDLINE(LargePageSizeInBytes, 5 * M); // Set large page size to 5MB + if (!EnableAllLargePageSizesForWindows) { + decided_size = os::win32::large_page_init_decide_size(); // Recalculate decided size + EXPECT_EQ(decided_size, 0) << "Expected decided size to be 0 for large pages bigger than 4mb on IA32 or AMD64"; + } +#endif + + // Additional check for non-multiple of minimum size + // Set an arbitrary large page size which is not a multiple of min_size + FLAG_SET_CMDLINE(LargePageSizeInBytes, 5 * min_size + 1); + + // Recalculate decided size + decided_size = os::win32::large_page_init_decide_size(); + + // Assert that the decided size defaults to minimum page size when LargePageSizeInBytes + // is not a multiple of the minimum size, assuming conditions are always met + EXPECT_EQ(decided_size, 0) << "Expected decided size to default to 0 when LargePageSizeInBytes is not a multiple of minimum size"; +} + class ReserveMemorySpecialRunnable : public TestRunnable { public: void runUnitTest() const { From d3139b4c3682defab2a8bfa0a24890232c3f00a3 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Fri, 4 Oct 2024 06:49:54 +0000 Subject: [PATCH 132/188] 8341000: Open source some of the AWT Window tests Reviewed-by: psadhukhan, abhiscxk --- .../awt/Window/BadConfigure/BadConfigure.java | 71 ++++++++++++ .../InvalidFocusLostEventTest.java | 101 ++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 test/jdk/java/awt/Window/BadConfigure/BadConfigure.java create mode 100644 test/jdk/java/awt/Window/InvalidFocusLostEventTest/InvalidFocusLostEventTest.java diff --git a/test/jdk/java/awt/Window/BadConfigure/BadConfigure.java b/test/jdk/java/awt/Window/BadConfigure/BadConfigure.java new file mode 100644 index 0000000000000..a25ab9b91b9a5 --- /dev/null +++ b/test/jdk/java/awt/Window/BadConfigure/BadConfigure.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6261336 + * @summary Tests that Choice inside ScrollPane opens at the right location + * after resize + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BadConfigure +*/ + +import java.awt.BorderLayout; +import java.awt.Choice; +import java.awt.Frame; + +public class BadConfigure +{ + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Please resize the BadConfigure window using the left border. + Now click on choice. Its popup will be opened. + Please verify that the popup is opened right under the choice. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + private static Frame initialize() { + Frame f = new Frame("BadConfigure"); + f.setLayout(new BorderLayout()); + Choice ch = new Choice(); + f.add(ch, BorderLayout.NORTH); + ch.add("One"); + ch.add("One"); + ch.add("One"); + ch.add("One"); + ch.add("One"); + ch.add("One"); + f.setSize(200, 200); + f.validate(); + return f; + } +} diff --git a/test/jdk/java/awt/Window/InvalidFocusLostEventTest/InvalidFocusLostEventTest.java b/test/jdk/java/awt/Window/InvalidFocusLostEventTest/InvalidFocusLostEventTest.java new file mode 100644 index 0000000000000..569d59f146d38 --- /dev/null +++ b/test/jdk/java/awt/Window/InvalidFocusLostEventTest/InvalidFocusLostEventTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4397883 + * @summary Tests that non-focusable Window doesn't grab focus + * @key headful + * @run main InvalidFocusLostEventTest + */ + +import java.awt.Button; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; + +public class InvalidFocusLostEventTest implements ActionListener { + private static Frame f; + private static Button b; + private static KeyboardFocusManager fm; + private static volatile Point bp; + private static volatile int width, height; + private static Robot robot; + + public static void main(String[] args) throws Exception { + try { + InvalidFocusLostEventTest test = new InvalidFocusLostEventTest(); + EventQueue.invokeAndWait(() -> test.createUI()); + runTest(); + // we should check focus after all events are processed, + // since focus transfers are asynchronous + robot.waitForIdle(); + if (fm.getFocusOwner() != b) { + throw new RuntimeException("Failed: focus was lost"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private void createUI() { + f = new Frame("InvalidFocusLostEventTest"); + b = new Button("Press me"); + fm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + b.addActionListener(this); + f.add(b); + f.pack(); + f.setLocationRelativeTo(null); + f.setVisible(true); + } + + private static void runTest() throws Exception { + robot = new Robot(); + robot.setAutoDelay(100); + robot.setAutoWaitForIdle(true); + EventQueue.invokeAndWait(() -> { + bp = b.getLocationOnScreen(); + width = b.getWidth(); + height = b.getHeight(); + }); + robot.mouseMove(bp.x + width / 2, bp.y + height / 2 ); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + public void actionPerformed(ActionEvent ev) { + // pop up a non-focusable window + Window win = new Window(f); + win.setFocusableWindowState(false); + } +} From 3f420fac842153372e17222e7153cbc71c5789a7 Mon Sep 17 00:00:00 2001 From: Axel Boldt-Christmas Date: Fri, 4 Oct 2024 06:55:53 +0000 Subject: [PATCH 133/188] 8341451: Remove C2HandleAnonOMOwnerStub Reviewed-by: fyang, chagedorn --- .../cpu/aarch64/c2_CodeStubs_aarch64.cpp | 27 ------------------ src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp | 28 ------------------- src/hotspot/share/opto/c2_CodeStubs.hpp | 15 ---------- 3 files changed, 70 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp index dabafb9288b83..4bd509880f29c 100644 --- a/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_CodeStubs_aarch64.cpp @@ -64,31 +64,4 @@ void C2EntryBarrierStub::emit(C2_MacroAssembler& masm) { __ emit_int32(0); // nmethod guard value } -int C2HandleAnonOMOwnerStub::max_size() const { - // Max size of stub has been determined by testing with 0, in which case - // C2CodeStubList::emit() will throw an assertion and report the actual size that - // is needed. - return 24; -} - -void C2HandleAnonOMOwnerStub::emit(C2_MacroAssembler& masm) { - __ bind(entry()); - Register mon = monitor(); - Register t = tmp(); - assert(t != noreg, "need tmp register"); - - // Fix owner to be the current thread. - __ str(rthread, Address(mon, ObjectMonitor::owner_offset())); - - // Pop owner object from lock-stack. - __ ldrw(t, Address(rthread, JavaThread::lock_stack_top_offset())); - __ subw(t, t, oopSize); -#ifdef ASSERT - __ str(zr, Address(rthread, t)); -#endif - __ strw(t, Address(rthread, JavaThread::lock_stack_top_offset())); - - __ b(continuation()); -} - #undef __ diff --git a/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp index 7995750aba96b..db18525b89c76 100644 --- a/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_CodeStubs_riscv.cpp @@ -71,32 +71,4 @@ void C2EntryBarrierStub::emit(C2_MacroAssembler& masm) { __ emit_int32(0); // nmethod guard value } -int C2HandleAnonOMOwnerStub::max_size() const { - // Max size of stub has been determined by testing with 0 without using RISC-V compressed - // instruction-set extension, in which case C2CodeStubList::emit() will throw an assertion - // and report the actual size that is needed. - return 20 DEBUG_ONLY(+8); -} - -void C2HandleAnonOMOwnerStub::emit(C2_MacroAssembler& masm) { - __ bind(entry()); - Register mon = monitor(); - Register t = tmp(); - assert(t != noreg, "need tmp register"); - - // Fix owner to be the current thread. - __ sd(xthread, Address(mon, ObjectMonitor::owner_offset())); - - // Pop owner object from lock-stack. - __ lwu(t, Address(xthread, JavaThread::lock_stack_top_offset())); - __ subw(t, t, oopSize); -#ifdef ASSERT - __ add(t0, xthread, t); - __ sd(zr, Address(t0, 0)); -#endif - __ sw(t, Address(xthread, JavaThread::lock_stack_top_offset())); - - __ j(continuation()); -} - #undef __ diff --git a/src/hotspot/share/opto/c2_CodeStubs.hpp b/src/hotspot/share/opto/c2_CodeStubs.hpp index 318bc2f45fc76..e778cfcde47e6 100644 --- a/src/hotspot/share/opto/c2_CodeStubs.hpp +++ b/src/hotspot/share/opto/c2_CodeStubs.hpp @@ -117,21 +117,6 @@ class C2FastUnlockLightweightStub : public C2CodeStub { Label& slow_path_continuation() { return continuation(); } }; -#ifdef _LP64 -class C2HandleAnonOMOwnerStub : public C2CodeStub { -private: - Register _monitor; - Register _tmp; -public: - C2HandleAnonOMOwnerStub(Register monitor, Register tmp = noreg) : C2CodeStub(), - _monitor(monitor), _tmp(tmp) {} - Register monitor() { return _monitor; } - Register tmp() { return _tmp; } - int max_size() const; - void emit(C2_MacroAssembler& masm); -}; -#endif - //-----------------------------C2GeneralStub----------------------------------- // A generalized stub that can be used to implement an arbitrary stub in a // type-safe manner. An example: From a63ac5a699a5d40c76d14f94a502b8003753f4dd Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Fri, 4 Oct 2024 08:26:15 +0000 Subject: [PATCH 134/188] 8340792: -XX:+PrintInterpreter: instructions should only be printed if printing all InterpreterCodelets Reviewed-by: mdoerr, coleenp --- src/hotspot/share/interpreter/abstractInterpreter.cpp | 4 ++++ src/hotspot/share/interpreter/abstractInterpreter.hpp | 3 +++ src/hotspot/share/interpreter/interpreter.cpp | 6 +++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/interpreter/abstractInterpreter.cpp b/src/hotspot/share/interpreter/abstractInterpreter.cpp index 9d72f9ba0edec..616ba29c62b33 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.cpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.cpp @@ -74,7 +74,9 @@ void AbstractInterpreter::print() { tty->print_cr("avg codelet size = %6d bytes", _code->used_space() / _code->number_of_stubs()); tty->cr(); } + _should_print_instructions = PrintInterpreter; _code->print(); + _should_print_instructions = false; tty->print_cr("----------------------------------------------------------------------"); tty->cr(); } @@ -91,6 +93,8 @@ address AbstractInterpreter::_slow_signature_handler; address AbstractInterpreter::_entry_table [AbstractInterpreter::number_of_method_entries]; address AbstractInterpreter::_native_abi_to_tosca [AbstractInterpreter::number_of_result_handlers]; +bool AbstractInterpreter::_should_print_instructions = false; + //------------------------------------------------------------------------------------------------------------------------ // Generation of complete interpreter diff --git a/src/hotspot/share/interpreter/abstractInterpreter.hpp b/src/hotspot/share/interpreter/abstractInterpreter.hpp index 790706c2de3cd..55fb58021a0d4 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.hpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.hpp @@ -126,6 +126,8 @@ class AbstractInterpreter: AllStatic { static address _rethrow_exception_entry; // rethrows an activation in previous frame + static bool _should_print_instructions; // only with PrintInterpreter and when printing all InterpreterCodelet + friend class AbstractInterpreterGenerator; friend class InterpreterMacroAssembler; @@ -133,6 +135,7 @@ class AbstractInterpreter: AllStatic { // Initialization/debugging static void initialize(); static StubQueue* code() { return _code; } + static bool should_print_instructions() { return _should_print_instructions; } // Method activation diff --git a/src/hotspot/share/interpreter/interpreter.cpp b/src/hotspot/share/interpreter/interpreter.cpp index 3c4ff4c1749e9..cba26f5aa6a6d 100644 --- a/src/hotspot/share/interpreter/interpreter.cpp +++ b/src/hotspot/share/interpreter/interpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -66,7 +66,7 @@ void InterpreterCodelet::verify() {} void InterpreterCodelet::print_on(outputStream* st) const { ttyLocker ttyl; - if (PrintInterpreter) { + if (AbstractInterpreter::should_print_instructions()) { st->cr(); st->print_cr("----------------------------------------------------------------------"); } @@ -76,7 +76,7 @@ void InterpreterCodelet::print_on(outputStream* st) const { st->print_cr("[" INTPTR_FORMAT ", " INTPTR_FORMAT "] %d bytes", p2i(code_begin()), p2i(code_end()), code_size()); - if (PrintInterpreter) { + if (AbstractInterpreter::should_print_instructions()) { st->cr(); Disassembler::decode(code_begin(), code_end(), st NOT_PRODUCT(COMMA &_asm_remarks)); } From ec020f3fc988553ad1eda460d889b5ba24e76e8e Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Fri, 4 Oct 2024 08:26:35 +0000 Subject: [PATCH 135/188] 8340426: ZGC: Move defragment out of the allocation path Reviewed-by: aboldtch, jsikstro, eosterlund --- src/hotspot/share/gc/z/zHeap.cpp | 6 +- src/hotspot/share/gc/z/zHeap.hpp | 2 +- src/hotspot/share/gc/z/zPageAllocator.cpp | 91 ++++++++++++++++------- src/hotspot/share/gc/z/zPageAllocator.hpp | 7 +- src/hotspot/share/gc/z/zRelocate.cpp | 4 +- 5 files changed, 77 insertions(+), 33 deletions(-) diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 40aa76867f424..1e917bb5ee39d 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -241,10 +241,10 @@ void ZHeap::undo_alloc_page(ZPage* page) { log_trace(gc)("Undo page allocation, thread: " PTR_FORMAT " (%s), page: " PTR_FORMAT ", size: " SIZE_FORMAT, p2i(Thread::current()), ZUtils::thread_name(), p2i(page), page->size()); - free_page(page); + free_page(page, false /* allow_defragment */); } -void ZHeap::free_page(ZPage* page) { +void ZHeap::free_page(ZPage* page, bool allow_defragment) { // Remove page table entry _page_table.remove(page); @@ -253,7 +253,7 @@ void ZHeap::free_page(ZPage* page) { } // Free page - _page_allocator.free_page(page); + _page_allocator.free_page(page, allow_defragment); } size_t ZHeap::free_empty_pages(const ZArray* pages) { diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 18fa0d6349bea..7b75c63cf8ce0 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -104,7 +104,7 @@ class ZHeap { // Page allocation ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); void undo_alloc_page(ZPage* page); - void free_page(ZPage* page); + void free_page(ZPage* page, bool allow_defragment); size_t free_empty_pages(const ZArray* pages); // Object allocation diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index 01200f76b519e..010241294a701 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -275,7 +275,7 @@ bool ZPageAllocator::prime_cache(ZWorkers* workers, size_t size) { workers->run_all(&task); } - free_page(page); + free_page(page, false /* allow_defragment */); return true; } @@ -462,6 +462,38 @@ void ZPageAllocator::destroy_page(ZPage* page) { safe_destroy_page(page); } +bool ZPageAllocator::should_defragment(const ZPage* page) const { + // A small page can end up at a high address (second half of the address space) + // if we've split a larger page or we have a constrained address space. To help + // fight address space fragmentation we remap such pages to a lower address, if + // a lower address is available. + return page->type() == ZPageType::small && + page->start() >= to_zoffset(_virtual.reserved() / 2) && + page->start() > _virtual.lowest_available_address(); +} + +ZPage* ZPageAllocator::defragment_page(ZPage* page) { + // Harvest the physical memory (which is committed) + ZPhysicalMemory pmem; + ZPhysicalMemory& old_pmem = page->physical_memory(); + pmem.add_segments(old_pmem); + old_pmem.remove_segments(); + + _unmapper->unmap_and_destroy_page(page); + + // Allocate new virtual memory at a low address + const ZVirtualMemory vmem = _virtual.alloc(pmem.size(), true /* force_low_address */); + + // Create the new page and map it + ZPage* new_page = new ZPage(ZPageType::small, vmem, pmem); + map_page(new_page); + + // Update statistics + ZStatInc(ZCounterDefragment); + + return new_page; +} + bool ZPageAllocator::is_alloc_allowed(size_t size) const { const size_t available = _current_max_capacity - _used - _claimed; return available >= size; @@ -623,16 +655,6 @@ ZPage* ZPageAllocator::alloc_page_create(ZPageAllocation* allocation) { return new ZPage(allocation->type(), vmem, pmem); } -bool ZPageAllocator::should_defragment(const ZPage* page) const { - // A small page can end up at a high address (second half of the address space) - // if we've split a larger page or we have a constrained address space. To help - // fight address space fragmentation we remap such pages to a lower address, if - // a lower address is available. - return page->type() == ZPageType::small && - page->start() >= to_zoffset(_virtual.reserved() / 2) && - page->start() > _virtual.lowest_available_address(); -} - bool ZPageAllocator::is_alloc_satisfied(ZPageAllocation* allocation) const { // The allocation is immediately satisfied if the list of pages contains // exactly one page, with the type and size that was requested. However, @@ -652,12 +674,6 @@ bool ZPageAllocator::is_alloc_satisfied(ZPageAllocation* allocation) const { return false; } - if (should_defragment(page)) { - // Defragment address space - ZStatInc(ZCounterDefragment); - return false; - } - // Allocation immediately satisfied return true; } @@ -773,6 +789,18 @@ void ZPageAllocator::satisfy_stalled() { } } +ZPage* ZPageAllocator::prepare_to_recycle(ZPage* page, bool allow_defragment) { + // Make sure we have a page that is safe to recycle + ZPage* const to_recycle = _safe_recycle.register_and_clone_if_activated(page); + + // Defragment the page before recycle if allowed and needed + if (allow_defragment && should_defragment(to_recycle)) { + return defragment_page(to_recycle); + } + + return to_recycle; +} + void ZPageAllocator::recycle_page(ZPage* page) { // Set time when last used page->set_last_used(); @@ -781,9 +809,11 @@ void ZPageAllocator::recycle_page(ZPage* page) { _cache.free_page(page); } -void ZPageAllocator::free_page(ZPage* page) { +void ZPageAllocator::free_page(ZPage* page, bool allow_defragment) { const ZGenerationId generation_id = page->generation_id(); - ZPage* const to_recycle = _safe_recycle.register_and_clone_if_activated(page); + + // Prepare page for recycling before taking the lock + ZPage* const to_recycle = prepare_to_recycle(page, allow_defragment); ZLocker locker(&_lock); @@ -800,11 +830,12 @@ void ZPageAllocator::free_page(ZPage* page) { } void ZPageAllocator::free_pages(const ZArray* pages) { - ZArray to_recycle; + ZArray to_recycle_pages; size_t young_size = 0; size_t old_size = 0; + // Prepare pages for recycling before taking the lock ZArrayIterator pages_iter(pages); for (ZPage* page; pages_iter.next(&page);) { if (page->is_young()) { @@ -812,7 +843,12 @@ void ZPageAllocator::free_pages(const ZArray* pages) { } else { old_size += page->size(); } - to_recycle.push(_safe_recycle.register_and_clone_if_activated(page)); + + // Prepare to recycle + ZPage* const to_recycle = prepare_to_recycle(page, true /* allow_defragment */); + + // Register for recycling + to_recycle_pages.push(to_recycle); } ZLocker locker(&_lock); @@ -823,7 +859,7 @@ void ZPageAllocator::free_pages(const ZArray* pages) { decrease_used_generation(ZGenerationId::old, old_size); // Free pages - ZArrayIterator iter(&to_recycle); + ZArrayIterator iter(&to_recycle_pages); for (ZPage* page; iter.next(&page);) { recycle_page(page); } @@ -833,11 +869,16 @@ void ZPageAllocator::free_pages(const ZArray* pages) { } void ZPageAllocator::free_pages_alloc_failed(ZPageAllocation* allocation) { - ZArray to_recycle; + ZArray to_recycle_pages; + // Prepare pages for recycling before taking the lock ZListRemoveIterator allocation_pages_iter(allocation->pages()); for (ZPage* page; allocation_pages_iter.next(&page);) { - to_recycle.push(_safe_recycle.register_and_clone_if_activated(page)); + // Prepare to recycle + ZPage* const to_recycle = prepare_to_recycle(page, false /* allow_defragment */); + + // Register for recycling + to_recycle_pages.push(to_recycle); } ZLocker locker(&_lock); @@ -849,7 +890,7 @@ void ZPageAllocator::free_pages_alloc_failed(ZPageAllocation* allocation) { size_t freed = 0; // Free any allocated/flushed pages - ZArrayIterator iter(&to_recycle); + ZArrayIterator iter(&to_recycle_pages); for (ZPage* page; iter.next(&page);) { freed += page->size(); recycle_page(page); diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index 5d3d59a416344..7df83a10eaf5a 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -104,13 +104,15 @@ class ZPageAllocator { void destroy_page(ZPage* page); + bool should_defragment(const ZPage* page) const; + ZPage* defragment_page(ZPage* page); + bool is_alloc_allowed(size_t size) const; bool alloc_page_common_inner(ZPageType type, size_t size, ZList* pages); bool alloc_page_common(ZPageAllocation* allocation); bool alloc_page_stall(ZPageAllocation* allocation); bool alloc_page_or_stall(ZPageAllocation* allocation); - bool should_defragment(const ZPage* page) const; bool is_alloc_satisfied(ZPageAllocation* allocation) const; ZPage* alloc_page_create(ZPageAllocation* allocation); ZPage* alloc_page_finalize(ZPageAllocation* allocation); @@ -149,9 +151,10 @@ class ZPageAllocator { void reset_statistics(ZGenerationId id); ZPage* alloc_page(ZPageType type, size_t size, ZAllocationFlags flags, ZPageAge age); + ZPage* prepare_to_recycle(ZPage* page, bool allow_defragment); void recycle_page(ZPage* page); void safe_destroy_page(ZPage* page); - void free_page(ZPage* page); + void free_page(ZPage* page, bool allow_defragment); void free_pages(const ZArray* pages); void enable_safe_destroy() const; diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 33304bcefd37f..7f69c0752bc5a 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -411,7 +411,7 @@ static void retire_target_page(ZGeneration* generation, ZPage* page) { // relocate the remaining objects, leaving the target page empty when // relocation completed. if (page->used() == 0) { - ZHeap::heap()->free_page(page); + ZHeap::heap()->free_page(page, true /* allow_defragment */); } } @@ -1012,7 +1012,7 @@ class ZRelocateWork : public StackObj { page->log_msg(" (relocate page done normal)"); // Free page - ZHeap::heap()->free_page(page); + ZHeap::heap()->free_page(page, true /* allow_defragment */); } } }; From 1bdd79e7b2086197ab64161e89bbe8cc180f07ed Mon Sep 17 00:00:00 2001 From: "Todd V. Jonker" Date: Fri, 4 Oct 2024 09:01:41 +0000 Subject: [PATCH 136/188] 8341261: Tests assume UnlockExperimentalVMOptions is disabled by default Reviewed-by: stefank, mli, ysr --- .../BlackholeExperimentalUnlockTest.java | 1 + .../runtime/CommandLine/VMOptionWarning.java | 76 ++++++++++++++----- test/jtreg-ext/requires/VMProps.java | 1 + 3 files changed, 58 insertions(+), 20 deletions(-) diff --git a/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java b/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java index 6597b2186f266..0a403a784506f 100644 --- a/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java +++ b/test/hotspot/jtreg/compiler/blackhole/BlackholeExperimentalUnlockTest.java @@ -25,6 +25,7 @@ * @test * @library /test/lib / * @requires vm.flagless + * @requires ! vm.opt.final.UnlockExperimentalVMOptions * @requires vm.compMode != "Xint" * @run driver compiler.blackhole.BlackholeExperimentalUnlockTest */ diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java b/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java index aaee80169eb06..90b309069ac4f 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java +++ b/test/hotspot/jtreg/runtime/CommandLine/VMOptionWarning.java @@ -22,14 +22,37 @@ */ /* - * @test + * @test VMOptionWarningExperimental * @bug 8027314 - * @summary Warn if diagnostic or experimental vm option is used and -XX:+UnlockDiagnosticVMOptions or -XX:+UnlockExperimentalVMOptions, respectively, isn't specified. Warn if develop vm option is used with product version of VM. + * @summary Warn if experimental vm option is used and -XX:+UnlockExperimentalVMOptions isn't specified. * @requires vm.flagless + * @requires ! vm.opt.final.UnlockExperimentalVMOptions * @library /test/lib * @modules java.base/jdk.internal.misc * java.management - * @run driver VMOptionWarning + * @run driver VMOptionWarning Experimental + */ + +/* @test VMOptionWarningDiagnostic + * @bug 8027314 + * @summary Warn if diagnostic vm option is used and -XX:+UnlockDiagnosticVMOptions isn't specified. + * @requires vm.flagless + * @requires ! vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver VMOptionWarning Diagnostic + */ + +/* @test VMOptionWarningDevelop + * @bug 8027314 + * @summary Warn if develop vm option is used with product version of VM. + * @requires vm.flagless + * @requires ! vm.debug + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver VMOptionWarning Develop */ import jdk.test.lib.process.ProcessTools; @@ -38,24 +61,37 @@ public class VMOptionWarning { public static void main(String[] args) throws Exception { - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+AlwaysSafeConstructors", "-version"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldNotHaveExitValue(0); - output.shouldContain("Error: VM option 'AlwaysSafeConstructors' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions."); - - if (Platform.isDebugBuild()) { - System.out.println("Skip the rest of the tests on debug builds since diagnostic, and develop options are available on debug builds."); - return; + if (args.length != 1) { + throw new RuntimeException("wrong number of args: " + args.length); } - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+PrintInlining", "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldNotHaveExitValue(0); - output.shouldContain("Error: VM option 'PrintInlining' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions."); - - pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+VerifyStack", "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldNotHaveExitValue(0); - output.shouldContain("Error: VM option 'VerifyStack' is develop and is available only in debug version of VM."); + ProcessBuilder pb; + OutputAnalyzer output; + switch (args[0]) { + case "Experimental": { + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+AlwaysSafeConstructors", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); + output.shouldContain("Error: VM option 'AlwaysSafeConstructors' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions."); + break; + } + case "Diagnostic": { + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+PrintInlining", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); + output.shouldContain("Error: VM option 'PrintInlining' is diagnostic and must be enabled via -XX:+UnlockDiagnosticVMOptions."); + break; + } + case "Develop": { + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+VerifyStack", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); + output.shouldContain("Error: VM option 'VerifyStack' is develop and is available only in debug version of VM."); + break; + } + default: { + throw new RuntimeException("Invalid argument: " + args[0]); + } + } } } diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 539a1f23208c3..137cfbfec3ea4 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -384,6 +384,7 @@ protected void vmOptFinalFlags(SafeMap map) { vmOptFinalFlag(map, "CriticalJNINatives"); vmOptFinalFlag(map, "EnableJVMCI"); vmOptFinalFlag(map, "EliminateAllocations"); + vmOptFinalFlag(map, "UnlockExperimentalVMOptions"); vmOptFinalFlag(map, "UseCompressedOops"); vmOptFinalFlag(map, "UseLargePages"); vmOptFinalFlag(map, "UseVectorizedMismatchIntrinsic"); From 7fa2f229fbee68112cbdd18b811d95721adfe2ec Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Fri, 4 Oct 2024 09:45:50 +0000 Subject: [PATCH 137/188] 8341127: Extra call to MethodHandle::asType from memory segment var handles fails to inline Reviewed-by: psandoz, redestad, jvernee --- .../java/lang/invoke/MethodHandle.java | 16 +- .../foreign/LoopOverNonConstantAsType.java | 138 ++++++++++++++++++ 2 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index 104248c27e61a..d327060070741 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -27,6 +27,8 @@ import jdk.internal.loader.ClassLoaders; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import java.lang.constant.ClassDesc; @@ -856,6 +858,7 @@ public Object invokeWithArguments(java.util.List arguments) throws Throwable * @throws WrongMethodTypeException if the conversion cannot be made * @see MethodHandles#explicitCastArguments */ + @ForceInline public final MethodHandle asType(MethodType newType) { // Fast path alternative to a heavyweight {@code asType} call. // Return 'this' if the conversion will be a no-op. @@ -867,7 +870,7 @@ public final MethodHandle asType(MethodType newType) { if (at != null) { return at; } - return setAsTypeCache(asTypeUncached(newType)); + return setAsTypeCache(newType); } private MethodHandle asTypeCached(MethodType newType) { @@ -885,7 +888,16 @@ private MethodHandle asTypeCached(MethodType newType) { return null; } - private MethodHandle setAsTypeCache(MethodHandle at) { + /* + * We disable inlining here to prevent complex code in the slow path + * of MethodHandle::asType from being inlined into that method. + * Excessive inlining into MethodHandle::asType can cause that method + * to become too big, which will then cause performance issues during + * var handle and method handle calls. + */ + @DontInline + private MethodHandle setAsTypeCache(MethodType newType) { + MethodHandle at = asTypeUncached(newType); // Don't introduce a strong reference in the cache if newType depends on any class loader other than // current method handle already does to avoid class loader leaks. if (isSafeToCache(at.type)) { diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java new file mode 100644 index 0000000000000..1fbe431b2f23a --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/foreign/LoopOverNonConstantAsType.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.foreign; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.CompilerControl; +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.Param; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; +import sun.misc.Unsafe; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Proxy; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; + +import static java.lang.foreign.ValueLayout.*; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(org.openjdk.jmh.annotations.Scope.Thread) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Fork(value = 3, jvmArgsAppend = { "-XX:-TieredCompilation" }) +public class LoopOverNonConstantAsType extends JavaLayouts { + + static final Unsafe unsafe = Utils.unsafe; + + static final int ELEM_SIZE = 1_000_000; + static final int CARRIER_SIZE = (int)JAVA_LONG.byteSize(); + static final int ALLOC_SIZE = ELEM_SIZE * CARRIER_SIZE; + + @Param({"false", "true"}) + public boolean asTypeCompiled; + + Arena arena; + MemorySegment segment; + long unsafe_addr; + + @Setup + public void setup() { + unsafe_addr = unsafe.allocateMemory(ALLOC_SIZE); + for (int i = 0; i < ELEM_SIZE; i++) { + unsafe.putInt(unsafe_addr + (i * CARRIER_SIZE) , i); + } + arena = Arena.ofConfined(); + segment = arena.allocate(ALLOC_SIZE, 1); + for (int i = 0; i < ELEM_SIZE; i++) { + VH_INT.set(segment, (long) i, i); + } + if (asTypeCompiled) { + compileAsType(); + } + } + + public interface T { } + + static final int TYPE_SIZE = 100; + static final Class[] types; + + static { + types = new Class[TYPE_SIZE]; + ClassLoader customLoader = new URLClassLoader(new URL[0], LoopOverNonConstantAsType.class.getClassLoader()); + for (int i = 0 ; i < TYPE_SIZE ; i++) { + types[i] = Proxy.newProxyInstance(customLoader, + new Class[] { T.class }, (_, _, _) -> null).getClass(); + } + } + + void compileAsType() { + for (Class type : types) { + MethodHandle handle = MethodHandles.zero(Object.class); + Class[] args = new Class[254]; + Arrays.fill(args, Object.class); + handle = MethodHandles.dropArguments(handle, 0, args); + for (int j = 0; j < args.length ; j++) { + handle = handle.asType(handle.type().changeParameterType(j, type)); + } + } + } + + @TearDown + public void tearDown() { + arena.close(); + unsafe.freeMemory(unsafe_addr); + } + + @Benchmark + public long unsafe_loop() { + long res = 0; + for (int i = 0; i < ELEM_SIZE; i ++) { + res += unsafe.getLong(unsafe_addr + (i * CARRIER_SIZE)); + } + return res; + } + + @Benchmark + public long segment_loop() { + long sum = 0; + for (int i = 0; i < ELEM_SIZE; i++) { + sum += segment.get(JAVA_LONG, i * CARRIER_SIZE); + } + return sum; + } +} From 72ac72fe1f3faca299d3fb2b20d3af29c3fa1e56 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 4 Oct 2024 11:43:11 +0000 Subject: [PATCH 138/188] 8341413: Stop including osThread_os.hpp in the middle of the OSThread class Reviewed-by: coleenp, dholmes --- src/hotspot/os/aix/osThread_aix.cpp | 38 +++--- src/hotspot/os/aix/osThread_aix.hpp | 61 +++++----- src/hotspot/os/aix/vmStructs_aix.hpp | 17 ++- src/hotspot/os/bsd/osThread_bsd.cpp | 36 +++--- src/hotspot/os/bsd/osThread_bsd.hpp | 56 ++++----- src/hotspot/os/bsd/vmStructs_bsd.hpp | 18 ++- src/hotspot/os/linux/osThread_linux.cpp | 28 ++--- src/hotspot/os/linux/osThread_linux.hpp | 55 +++++---- src/hotspot/os/linux/os_linux.cpp | 2 +- src/hotspot/os/linux/vmStructs_linux.hpp | 19 ++- src/hotspot/os/windows/osThread_windows.cpp | 16 +-- src/hotspot/os/windows/osThread_windows.hpp | 30 +++-- src/hotspot/os/windows/os_windows.cpp | 3 +- src/hotspot/os/windows/vmStructs_windows.hpp | 15 ++- .../os_cpu/aix_ppc/vmStructs_aix_ppc.hpp | 16 +-- .../bsd_aarch64/vmStructs_bsd_aarch64.hpp | 17 +-- .../os_cpu/bsd_x86/vmStructs_bsd_x86.hpp | 17 +-- .../linux_aarch64/vmStructs_linux_aarch64.hpp | 18 +-- .../os_cpu/linux_arm/vmStructs_linux_arm.hpp | 17 +-- .../os_cpu/linux_ppc/vmStructs_linux_ppc.hpp | 18 +-- .../linux_riscv/vmStructs_linux_riscv.hpp | 18 +-- .../linux_s390/vmStructs_linux_s390.hpp | 18 +-- .../os_cpu/linux_x86/vmStructs_linux_x86.hpp | 18 +-- .../vmStructs_windows_aarch64.hpp | 13 +- .../windows_x86/vmStructs_windows_x86.hpp | 13 +- .../share/interpreter/bytecodeTracer.cpp | 4 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 1 + src/hotspot/share/runtime/osThread.hpp | 105 +--------------- .../{osThread.cpp => osThreadBase.cpp} | 16 +-- src/hotspot/share/runtime/osThreadBase.hpp | 115 ++++++++++++++++++ 30 files changed, 368 insertions(+), 450 deletions(-) rename src/hotspot/share/runtime/{osThread.cpp => osThreadBase.cpp} (87%) create mode 100644 src/hotspot/share/runtime/osThreadBase.hpp diff --git a/src/hotspot/os/aix/osThread_aix.cpp b/src/hotspot/os/aix/osThread_aix.cpp index 4049d6b58b777..b9c5f16a62251 100644 --- a/src/hotspot/os/aix/osThread_aix.cpp +++ b/src/hotspot/os/aix/osThread_aix.cpp @@ -23,32 +23,28 @@ * */ -// no precompiled headers - -#include "memory/allocation.inline.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/os.hpp" +#include "precompiled.hpp" +#include "memory/allocation.hpp" +#include "runtime/mutex.hpp" #include "runtime/osThread.hpp" -#include "runtime/safepoint.hpp" -#include "runtime/vmThread.hpp" - -void OSThread::pd_initialize() { - _thread_id = 0; - _kernel_thread_id = 0; - _siginfo = nullptr; - _ucontext = nullptr; - _expanding_stack = 0; - _alt_sig_stack = nullptr; - _last_cpu_times.sys = _last_cpu_times.user = 0L; +#include +OSThread::OSThread() + : _thread_id(0), + _thread_type(), + _kernel_thread_id(0), + _caller_sigmask(), + sr(), + _siginfo(nullptr), + _ucontext(nullptr), + _expanding_stack(0), + _alt_sig_stack(nullptr), + _last_cpu_times(), + _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) { sigemptyset(&_caller_sigmask); - - _startThread_lock = new Monitor(Mutex::event, "startThread_lock"); - assert(_startThread_lock != nullptr, "check"); } -void OSThread::pd_destroy() { +OSThread::~OSThread() { delete _startThread_lock; } diff --git a/src/hotspot/os/aix/osThread_aix.hpp b/src/hotspot/os/aix/osThread_aix.hpp index 5feb3c5799aa0..acbe1d37684cf 100644 --- a/src/hotspot/os/aix/osThread_aix.hpp +++ b/src/hotspot/os/aix/osThread_aix.hpp @@ -26,22 +26,17 @@ #ifndef OS_AIX_OSTHREAD_AIX_HPP #define OS_AIX_OSTHREAD_AIX_HPP - public: - typedef pthread_t thread_id_t; - - private: - int _thread_type; +#include "runtime/osThreadBase.hpp" +#include "suspendResume_posix.hpp" +#include "utilities/globalDefinitions.hpp" - public: +class OSThread : public OSThreadBase { + friend class VMStructs; - int thread_type() const { - return _thread_type; - } - void set_thread_type(int type) { - _thread_type = type; - } + typedef pthread_t thread_id_t; - private: + thread_id_t _thread_id; + int _thread_type; // On AIX, we use the pthread id as OSThread::thread_id and keep the kernel thread id // separately for diagnostic purposes. @@ -54,15 +49,27 @@ sigset_t _caller_sigmask; // Caller's signal mask public: + OSThread(); + ~OSThread(); + + int thread_type() const { + return _thread_type; + } + void set_thread_type(int type) { + _thread_type = type; + } // Methods to save/restore caller's signal mask sigset_t caller_sigmask() const { return _caller_sigmask; } void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; } -#ifndef PRODUCT - // Used for debugging, return a unique integer for each thread. - int thread_identifier() const { return _thread_id; } -#endif + thread_id_t thread_id() const { + return _thread_id; + } + void set_thread_id(thread_id_t id) { + _thread_id = id; + } + tid_t kernel_thread_id() const { return _kernel_thread_id; } @@ -71,7 +78,7 @@ } pthread_t pthread_id() const { - // Here: same as OSThread::thread_id() + // Here: same as thread_id() return _thread_id; } @@ -79,7 +86,6 @@ // suspension support. // *************************************************************** - public: // flags that support signal based suspend/resume on Aix are in a // separate class to avoid confusion with many flags in OSThread that // are used by VM level suspend/resume. @@ -125,17 +131,6 @@ return _startThread_lock; } - // *************************************************************** - // Platform dependent initialization and cleanup - // *************************************************************** - - private: - - void pd_initialize(); - void pd_destroy(); - - public: - // The last measured values of cpu timing to prevent the "stale // value return" bug in thread_cpu_time. volatile struct { @@ -143,4 +138,10 @@ jlong user; } _last_cpu_times; + // Printing + uintx thread_id_for_printing() const override { + return (uintx)_thread_id; + } +}; + #endif // OS_AIX_OSTHREAD_AIX_HPP diff --git a/src/hotspot/os/aix/vmStructs_aix.hpp b/src/hotspot/os/aix/vmStructs_aix.hpp index 1a2f4c4bf6e21..f3bbc80e62c72 100644 --- a/src/hotspot/os/aix/vmStructs_aix.hpp +++ b/src/hotspot/os/aix/vmStructs_aix.hpp @@ -29,9 +29,20 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + \ + /******************************/ \ + /* Threads (NOTE: incomplete) */ \ + /******************************/ \ + nonstatic_field(OSThread, _thread_id, pthread_t) \ + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + \ + /**********************/ \ + /* Posix Thread IDs */ \ + /**********************/ \ + \ + declare_unsigned_integer_type(pthread_t) #define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os/bsd/osThread_bsd.cpp b/src/hotspot/os/bsd/osThread_bsd.cpp index 7b9ad1f76a855..4080ea1bf297b 100644 --- a/src/hotspot/os/bsd/osThread_bsd.cpp +++ b/src/hotspot/os/bsd/osThread_bsd.cpp @@ -22,30 +22,32 @@ * */ -// no precompiled headers -#include "memory/allocation.inline.hpp" -#include "runtime/mutexLocker.hpp" +#include "precompiled.hpp" +#include "memory/allocation.hpp" +#include "runtime/mutex.hpp" #include "runtime/osThread.hpp" #include -void OSThread::pd_initialize() { +OSThread::OSThread() + : _thread_id( #ifdef __APPLE__ - _thread_id = 0; + 0 #else - _thread_id = nullptr; + nullptr #endif - _unique_thread_id = 0; - _pthread_id = nullptr; - _siginfo = nullptr; - _ucontext = nullptr; - _expanding_stack = 0; - _alt_sig_stack = nullptr; - + ), + _thread_type(), + _pthread_id(nullptr), + _unique_thread_id(0), + _caller_sigmask(), + sr(), + _siginfo(nullptr), + _ucontext(nullptr), + _expanding_stack(0), + _alt_sig_stack(nullptr), + _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) { sigemptyset(&_caller_sigmask); - - _startThread_lock = new Monitor(Mutex::event, "startThread_lock"); - assert(_startThread_lock !=nullptr, "check"); } // Additional thread_id used to correlate threads in SA @@ -64,6 +66,6 @@ void OSThread::set_unique_thread_id() { #endif } -void OSThread::pd_destroy() { +OSThread::~OSThread() { delete _startThread_lock; } diff --git a/src/hotspot/os/bsd/osThread_bsd.hpp b/src/hotspot/os/bsd/osThread_bsd.hpp index 11376835063c4..e54e7195f9870 100644 --- a/src/hotspot/os/bsd/osThread_bsd.hpp +++ b/src/hotspot/os/bsd/osThread_bsd.hpp @@ -25,19 +25,12 @@ #ifndef OS_BSD_OSTHREAD_BSD_HPP #define OS_BSD_OSTHREAD_BSD_HPP - private: - int _thread_type; +#include "runtime/osThreadBase.hpp" +#include "suspendResume_posix.hpp" +#include "utilities/globalDefinitions.hpp" - public: - - int thread_type() const { - return _thread_type; - } - void set_thread_type(int type) { - _thread_type = type; - } - - private: +class OSThread : public OSThreadBase { + friend class VMStructs; #ifdef __APPLE__ typedef thread_t thread_id_t; @@ -45,6 +38,9 @@ typedef pid_t thread_id_t; #endif + thread_id_t _thread_id; + int _thread_type; + // _pthread_id is the pthread id, which is used by library calls // (e.g. pthread_kill). pthread_t _pthread_id; @@ -57,15 +53,26 @@ sigset_t _caller_sigmask; // Caller's signal mask public: + OSThread(); + ~OSThread(); + + int thread_type() const { + return _thread_type; + } + void set_thread_type(int type) { + _thread_type = type; + } // Methods to save/restore caller's signal mask sigset_t caller_sigmask() const { return _caller_sigmask; } void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; } -#ifndef PRODUCT - // Used for debugging, return a unique integer for each thread. - intptr_t thread_identifier() const { return (intptr_t)_pthread_id; } -#endif + thread_id_t thread_id() const { + return _thread_id; + } + void set_thread_id(thread_id_t id) { + _thread_id = id; + } pthread_t pthread_id() const { return _pthread_id; @@ -80,7 +87,6 @@ // suspension support. // *************************************************************** -public: // flags that support signal based suspend/resume on Bsd are in a // separate class to avoid confusion with many flags in OSThread that // are used by VM level suspend/resume. @@ -126,17 +132,9 @@ return _startThread_lock; } - // *************************************************************** - // Platform dependent initialization and cleanup - // *************************************************************** - -private: - - void pd_initialize(); - void pd_destroy(); - -// Reconciliation History -// osThread_solaris.hpp 1.24 99/08/27 13:11:54 -// End + uintx thread_id_for_printing() const override { + return (uintx)_thread_id; + } +}; #endif // OS_BSD_OSTHREAD_BSD_HPP diff --git a/src/hotspot/os/bsd/vmStructs_bsd.hpp b/src/hotspot/os/bsd/vmStructs_bsd.hpp index 84c1be77374d0..8c9c132e1c25c 100644 --- a/src/hotspot/os/bsd/vmStructs_bsd.hpp +++ b/src/hotspot/os/bsd/vmStructs_bsd.hpp @@ -31,9 +31,21 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + \ + /******************************/ \ + /* Threads (NOTE: incomplete) */ \ + /******************************/ \ + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ + nonstatic_field(OSThread, _unique_thread_id, uint64_t) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + \ + /**********************/ \ + /* Thread IDs */ \ + /**********************/ \ + \ + declare_unsigned_integer_type(OSThread::thread_id_t) #define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os/linux/osThread_linux.cpp b/src/hotspot/os/linux/osThread_linux.cpp index 9c77cb32f6d1c..3dd6e3bbcd15c 100644 --- a/src/hotspot/os/linux/osThread_linux.cpp +++ b/src/hotspot/os/linux/osThread_linux.cpp @@ -22,27 +22,27 @@ * */ -// no precompiled headers -#include "memory/allocation.inline.hpp" +#include "precompiled.hpp" +#include "memory/allocation.hpp" #include "runtime/mutex.hpp" #include "runtime/osThread.hpp" #include -void OSThread::pd_initialize() { - _thread_id = 0; - _pthread_id = 0; - _siginfo = nullptr; - _ucontext = nullptr; - _expanding_stack = 0; - _alt_sig_stack = nullptr; - +OSThread::OSThread() + : _thread_id(0), + _thread_type(), + _pthread_id(0), + _caller_sigmask(), + sr(), + _siginfo(nullptr), + _ucontext(nullptr), + _expanding_stack(0), + _alt_sig_stack(nullptr), + _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) { sigemptyset(&_caller_sigmask); - - _startThread_lock = new Monitor(Mutex::event, "startThread_lock"); - assert(_startThread_lock !=nullptr, "check"); } -void OSThread::pd_destroy() { +OSThread::~OSThread() { delete _startThread_lock; } diff --git a/src/hotspot/os/linux/osThread_linux.hpp b/src/hotspot/os/linux/osThread_linux.hpp index a849673af62db..f8dfd5a213bbb 100644 --- a/src/hotspot/os/linux/osThread_linux.hpp +++ b/src/hotspot/os/linux/osThread_linux.hpp @@ -24,13 +24,28 @@ #ifndef OS_LINUX_OSTHREAD_LINUX_HPP #define OS_LINUX_OSTHREAD_LINUX_HPP - public: + +#include "runtime/osThreadBase.hpp" +#include "suspendResume_posix.hpp" +#include "utilities/globalDefinitions.hpp" + +class OSThread : public OSThreadBase { + friend class VMStructs; + typedef pid_t thread_id_t; - private: + thread_id_t _thread_id; int _thread_type; + // _pthread_id is the pthread id, which is used by library calls + // (e.g. pthread_kill). + pthread_t _pthread_id; + + sigset_t _caller_sigmask; // Caller's signal mask + public: + OSThread(); + ~OSThread(); int thread_type() const { return _thread_type; @@ -39,22 +54,16 @@ _thread_type = type; } - // _pthread_id is the pthread id, which is used by library calls - // (e.g. pthread_kill). - pthread_t _pthread_id; - - sigset_t _caller_sigmask; // Caller's signal mask - - public: - // Methods to save/restore caller's signal mask sigset_t caller_sigmask() const { return _caller_sigmask; } void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; } -#ifndef PRODUCT - // Used for debugging, return a unique integer for each thread. - int thread_identifier() const { return _thread_id; } -#endif + thread_id_t thread_id() const { + return _thread_id; + } + void set_thread_id(thread_id_t id) { + _thread_id = id; + } pthread_t pthread_id() const { return _pthread_id; @@ -67,7 +76,6 @@ // suspension support. // *************************************************************** -public: // flags that support signal based suspend/resume on Linux are in a // separate class to avoid confusion with many flags in OSThread that // are used by VM level suspend/resume. @@ -113,17 +121,10 @@ return _startThread_lock; } - // *************************************************************** - // Platform dependent initialization and cleanup - // *************************************************************** - -private: - - void pd_initialize(); - void pd_destroy(); - -// Reconciliation History -// osThread_solaris.hpp 1.24 99/08/27 13:11:54 -// End + // Printing + uintx thread_id_for_printing() const override { + return (uintx)_thread_id; + } +}; #endif // OS_LINUX_OSTHREAD_LINUX_HPP diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 609317df45fc2..c9968fc9f3580 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -817,7 +817,7 @@ static void *thread_native_entry(Thread *thread) { OSThread* osthread = thread->osthread(); Monitor* sync = osthread->startThread_lock(); - osthread->set_thread_id(checked_cast(os::current_thread_id())); + osthread->set_thread_id(checked_cast(os::current_thread_id())); if (UseNUMA) { int lgrp_id = os::numa_get_group_id(); diff --git a/src/hotspot/os/linux/vmStructs_linux.hpp b/src/hotspot/os/linux/vmStructs_linux.hpp index 818f6bb188fe8..3b82ac58ac697 100644 --- a/src/hotspot/os/linux/vmStructs_linux.hpp +++ b/src/hotspot/os/linux/vmStructs_linux.hpp @@ -31,9 +31,22 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + \ + /******************************/ \ + /* Threads (NOTE: incomplete) */ \ + /******************************/ \ + nonstatic_field(OSThread, _thread_id, pid_t) \ + nonstatic_field(OSThread, _pthread_id, pthread_t) + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + \ + /**********************/ \ + /* Posix Thread IDs */ \ + /**********************/ \ + \ + declare_integer_type(pid_t) \ + declare_unsigned_integer_type(pthread_t) #define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os/windows/osThread_windows.cpp b/src/hotspot/os/windows/osThread_windows.cpp index 5f369bb7aa05b..922b4b0104be4 100644 --- a/src/hotspot/os/windows/osThread_windows.cpp +++ b/src/hotspot/os/windows/osThread_windows.cpp @@ -22,17 +22,17 @@ * */ -// no precompiled headers -#include "runtime/os.hpp" +#include "precompiled.hpp" #include "runtime/osThread.hpp" -void OSThread::pd_initialize() { - set_thread_handle(nullptr); - set_thread_id(0); - set_interrupt_event(nullptr); -} +#include + +OSThread::OSThread() + : _thread_id(0), + _thread_handle(nullptr), + _interrupt_event(nullptr) {} -void OSThread::pd_destroy() { +OSThread::~OSThread() { if (_interrupt_event != nullptr) { CloseHandle(_interrupt_event); } diff --git a/src/hotspot/os/windows/osThread_windows.hpp b/src/hotspot/os/windows/osThread_windows.hpp index 5bd07646b1718..e54783aef1c15 100644 --- a/src/hotspot/os/windows/osThread_windows.hpp +++ b/src/hotspot/os/windows/osThread_windows.hpp @@ -25,17 +25,29 @@ #ifndef OS_WINDOWS_OSTHREAD_WINDOWS_HPP #define OS_WINDOWS_OSTHREAD_WINDOWS_HPP - typedef void* HANDLE; - public: +#include "runtime/osThreadBase.hpp" +#include "utilities/globalDefinitions.hpp" + +class OSThread : public OSThreadBase { + friend class VMStructs; + typedef unsigned long thread_id_t; + typedef void* HANDLE; + + thread_id_t _thread_id; - private: // Win32-specific thread information HANDLE _thread_handle; // Win32 thread handle HANDLE _interrupt_event; // Event signalled on thread interrupt for use by // Process.waitFor(). public: + OSThread(); + ~OSThread(); + + thread_id_t thread_id() const { return _thread_id; } + void set_thread_id(thread_id_t id) { _thread_id = id; } + // The following will only apply in the Win32 implementation, and should only // be visible in the concrete class, not this which should be an abstract base class HANDLE thread_handle() const { return _thread_handle; } @@ -45,13 +57,9 @@ // This is specialized on Windows to interact with the _interrupt_event. void set_interrupted(bool z); -#ifndef PRODUCT - // Used for debugging, return a unique integer for each thread. - int thread_identifier() const { return _thread_id; } -#endif - - private: - void pd_initialize(); - void pd_destroy(); + uintx thread_id_for_printing() const override { + return (uintx)_thread_id; + } +}; #endif // OS_WINDOWS_OSTHREAD_WINDOWS_HPP diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 6b935f06fa357..0d5727b98f443 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -63,6 +63,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/statSampler.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/suspendedThreadTask.hpp" #include "runtime/threadCritical.hpp" #include "runtime/threads.hpp" #include "runtime/timer.hpp" @@ -5992,7 +5993,7 @@ static void do_resume(HANDLE* h) { // retrieve a suspend/resume context capable handle // from the tid. Caller validates handle return value. void get_thread_handle_for_extended_context(HANDLE* h, - OSThread::thread_id_t tid) { + DWORD tid) { if (h != nullptr) { *h = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, tid); } diff --git a/src/hotspot/os/windows/vmStructs_windows.hpp b/src/hotspot/os/windows/vmStructs_windows.hpp index 2550e685f16e2..93f4ea7c8111d 100644 --- a/src/hotspot/os/windows/vmStructs_windows.hpp +++ b/src/hotspot/os/windows/vmStructs_windows.hpp @@ -29,9 +29,18 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) +#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + \ + /******************************/ \ + /* Threads (NOTE: incomplete) */ \ + /******************************/ \ + \ + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ + unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */ + +#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + \ + declare_unsigned_integer_type(OSThread::thread_id_t) #define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp b/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp index 157d57f8e0fa2..123cd67248f86 100644 --- a/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp +++ b/src/hotspot/os_cpu/aix_ppc/vmStructs_aix_ppc.hpp @@ -30,21 +30,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, pthread_t) \ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp b/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp index 07b878106cfcd..c384afac7ecff 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp +++ b/src/hotspot/os_cpu/bsd_aarch64/vmStructs_bsd_aarch64.hpp @@ -31,22 +31,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _unique_thread_id, uint64_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp index fb43541fa775a..b48ea82712ecd 100644 --- a/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/vmStructs_bsd_x86.hpp @@ -29,22 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _unique_thread_id, uint64_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Thread IDs */ \ - /**********************/ \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp index f2ad002996b5c..3c8e9c4441477 100644 --- a/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp +++ b/src/hotspot/os_cpu/linux_aarch64/vmStructs_linux_aarch64.hpp @@ -30,23 +30,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp index 9b4bd0faf0ad9..120726bf55fcd 100644 --- a/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp +++ b/src/hotspot/os_cpu/linux_arm/vmStructs_linux_arm.hpp @@ -29,22 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp index 9464c35977078..ae948c7303101 100644 --- a/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp +++ b/src/hotspot/os_cpu/linux_ppc/vmStructs_linux_ppc.hpp @@ -30,23 +30,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, pid_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(pid_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp index 6cf7683a58602..3946394c19b1f 100644 --- a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp +++ b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp @@ -30,23 +30,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp b/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp index 0442510fa247a..a0fb5eb1a6ab9 100644 --- a/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp +++ b/src/hotspot/os_cpu/linux_s390/vmStructs_linux_s390.hpp @@ -30,23 +30,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, pid_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(pid_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp index 277486549c035..8f6d365723700 100644 --- a/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/vmStructs_linux_x86.hpp @@ -29,23 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - nonstatic_field(OSThread, _pthread_id, pthread_t) +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) - -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - /**********************/ \ - /* Posix Thread IDs */ \ - /**********************/ \ - \ - declare_integer_type(OSThread::thread_id_t) \ - declare_unsigned_integer_type(pthread_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp b/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp index 220787823dc69..18a5588b743b9 100644 --- a/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp +++ b/src/hotspot/os_cpu/windows_aarch64/vmStructs_windows_aarch64.hpp @@ -29,18 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp index 9f50a7ed9ae29..985a6a331daba 100644 --- a/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp +++ b/src/hotspot/os_cpu/windows_x86/vmStructs_windows_x86.hpp @@ -29,18 +29,9 @@ // constants required by the Serviceability Agent. This file is // referenced by vmStructs.cpp. -#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ - \ - /******************************/ \ - /* Threads (NOTE: incomplete) */ \ - /******************************/ \ - \ - nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ - unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */ +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ - \ - declare_unsigned_integer_type(OSThread::thread_id_t) +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) #define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) diff --git a/src/hotspot/share/interpreter/bytecodeTracer.cpp b/src/hotspot/share/interpreter/bytecodeTracer.cpp index e5a3e9c16f4a1..cdb53b62f8c40 100644 --- a/src/hotspot/share/interpreter/bytecodeTracer.cpp +++ b/src/hotspot/share/interpreter/bytecodeTracer.cpp @@ -105,7 +105,7 @@ class BytecodePrinter { // the incoming method. We could lose a line of trace output. // This is acceptable in a debug-only feature. st->cr(); - st->print("[%ld] ", (long) Thread::current()->osthread()->thread_id()); + st->print("[" UINTX_FORMAT "] ", Thread::current()->osthread()->thread_id_for_printing()); method->print_name(st); st->cr(); _current_method = method(); @@ -128,7 +128,7 @@ class BytecodePrinter { code == Bytecodes::_return_register_finalizer || (code >= Bytecodes::_ireturn && code <= Bytecodes::_return)) { int bci = (int)(bcp - method->code_base()); - st->print("[%ld] ", (long) Thread::current()->osthread()->thread_id()); + st->print("[" UINTX_FORMAT "] ", Thread::current()->osthread()->thread_id_for_printing()); if (Verbose) { st->print("%8d %4d " INTPTR_FORMAT " " INTPTR_FORMAT " %s", BytecodeCounter::counter_value(), bci, tos, tos2, Bytecodes::name(code)); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 13b208932199a..5452cca96b8c0 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -38,6 +38,7 @@ #include "runtime/continuationEntry.hpp" #include "runtime/deoptimization.hpp" #include "runtime/flags/jvmFlag.hpp" +#include "runtime/objectMonitor.hpp" #include "runtime/osThread.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" diff --git a/src/hotspot/share/runtime/osThread.hpp b/src/hotspot/share/runtime/osThread.hpp index b0e0588a6a2b6..597cf8e4d3fcb 100644 --- a/src/hotspot/share/runtime/osThread.hpp +++ b/src/hotspot/share/runtime/osThread.hpp @@ -25,111 +25,8 @@ #ifndef SHARE_RUNTIME_OSTHREAD_HPP #define SHARE_RUNTIME_OSTHREAD_HPP -#include "runtime/frame.hpp" -#include "runtime/handles.hpp" -#include "runtime/javaFrameAnchor.hpp" -#include "runtime/objectMonitor.hpp" -#include "runtime/suspendedThreadTask.hpp" #include "utilities/macros.hpp" - -#if defined(LINUX) || defined(AIX) || defined(BSD) -#include "suspendResume_posix.hpp" -#endif - -class Monitor; - -// The OSThread class holds OS-specific thread information. It is equivalent -// to the sys_thread_t structure of the classic JVM implementation. - -// The thread states represented by the ThreadState values are platform-specific -// and are likely to be only approximate, because most OSes don't give you access -// to precise thread state information. - -// Note: the ThreadState is legacy code and is not correctly implemented. -// Uses of ThreadState need to be replaced by the state in the JavaThread. - -enum ThreadState { - ALLOCATED, // Memory has been allocated but not initialized - INITIALIZED, // The thread has been initialized but yet started - RUNNABLE, // Has been started and is runnable, but not necessarily running - MONITOR_WAIT, // Waiting on a contended monitor lock - CONDVAR_WAIT, // Waiting on a condition variable - OBJECT_WAIT, // Waiting on an Object.wait() call - BREAKPOINTED, // Suspended at breakpoint - SLEEPING, // Thread.sleep() - ZOMBIE // All done, but not reclaimed yet -}; - -typedef int (*OSThreadStartFunc)(void*); - -class OSThread: public CHeapObj { - friend class VMStructs; - friend class JVMCIVMStructs; - private: - volatile ThreadState _state; // Thread state *hint* - - // Methods - public: - void set_state(ThreadState state) { _state = state; } - ThreadState get_state() { return _state; } - - OSThread(); - ~OSThread(); - - // Printing - void print_on(outputStream* st) const; - void print() const; - - // Platform dependent stuff +// The actual class declaration is platform specific. #include OS_HEADER(osThread) - public: - - thread_id_t thread_id() const { return _thread_id; } - - void set_thread_id(thread_id_t id) { _thread_id = id; } - - private: - // _thread_id is kernel thread id (similar to LWP id on Solaris). Each - // thread has a unique thread_id (BsdThreads or NPTL). It can be used - // to access /proc. - thread_id_t _thread_id; -}; - - -// Utility class for use with condition variables: -class OSThreadWaitState : public StackObj { - OSThread* _osthread; - ThreadState _old_state; - public: - OSThreadWaitState(OSThread* osthread, bool is_object_wait) { - _osthread = osthread; - _old_state = osthread->get_state(); - if (is_object_wait) { - osthread->set_state(OBJECT_WAIT); - } else { - osthread->set_state(CONDVAR_WAIT); - } - } - ~OSThreadWaitState() { - _osthread->set_state(_old_state); - } -}; - - -// Utility class for use with contended monitors: -class OSThreadContendState : public StackObj { - OSThread* _osthread; - ThreadState _old_state; - public: - OSThreadContendState(OSThread* osthread) { - _osthread = osthread; - _old_state = osthread->get_state(); - osthread->set_state(MONITOR_WAIT); - } - ~OSThreadContendState() { - _osthread->set_state(_old_state); - } -}; - #endif // SHARE_RUNTIME_OSTHREAD_HPP diff --git a/src/hotspot/share/runtime/osThread.cpp b/src/hotspot/share/runtime/osThreadBase.cpp similarity index 87% rename from src/hotspot/share/runtime/osThread.cpp rename to src/hotspot/share/runtime/osThreadBase.cpp index edaefaa1070d2..7bb7ae6aa69f8 100644 --- a/src/hotspot/share/runtime/osThread.cpp +++ b/src/hotspot/share/runtime/osThreadBase.cpp @@ -24,19 +24,11 @@ #include "precompiled.hpp" #include "oops/oop.inline.hpp" -#include "runtime/osThread.hpp" - -OSThread::OSThread() { - pd_initialize(); -} - -OSThread::~OSThread() { - pd_destroy(); -} +#include "runtime/osThreadBase.hpp" // Printing -void OSThread::print_on(outputStream *st) const { - st->print("nid=" UINT64_FORMAT " ", (uint64_t)thread_id()); +void OSThreadBase::print_on(outputStream *st) const { + st->print("nid=" UINTX_FORMAT " ", thread_id_for_printing()); switch (_state) { case ALLOCATED: st->print("allocated "); break; case INITIALIZED: st->print("initialized "); break; @@ -51,4 +43,4 @@ void OSThread::print_on(outputStream *st) const { } } -void OSThread::print() const { print_on(tty); } +void OSThreadBase::print() const { print_on(tty); } diff --git a/src/hotspot/share/runtime/osThreadBase.hpp b/src/hotspot/share/runtime/osThreadBase.hpp new file mode 100644 index 0000000000000..4063da18519d5 --- /dev/null +++ b/src/hotspot/share/runtime/osThreadBase.hpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_OSTHREAD_BASE_HPP +#define SHARE_RUNTIME_OSTHREAD_BASE_HPP + +#include "memory/allocation.hpp" + +class Monitor; + +// The OSThread class holds OS-specific thread information. It is equivalent +// to the sys_thread_t structure of the classic JVM implementation. + +// The thread states represented by the ThreadState values are platform-specific +// and are likely to be only approximate, because most OSes don't give you access +// to precise thread state information. + +// Note: the ThreadState is legacy code and is not correctly implemented. +// Uses of ThreadState need to be replaced by the state in the JavaThread. + +enum ThreadState { + ALLOCATED, // Memory has been allocated but not initialized + INITIALIZED, // The thread has been initialized but yet started + RUNNABLE, // Has been started and is runnable, but not necessarily running + MONITOR_WAIT, // Waiting on a contended monitor lock + CONDVAR_WAIT, // Waiting on a condition variable + OBJECT_WAIT, // Waiting on an Object.wait() call + BREAKPOINTED, // Suspended at breakpoint + SLEEPING, // Thread.sleep() + ZOMBIE // All done, but not reclaimed yet +}; + +typedef int (*OSThreadStartFunc)(void*); + +class OSThreadBase: public CHeapObj { + friend class VMStructs; + friend class JVMCIVMStructs; + private: + volatile ThreadState _state; // Thread state *hint* + + // Methods + public: + OSThreadBase() {} + virtual ~OSThreadBase() {} + NONCOPYABLE(OSThreadBase); + + void set_state(ThreadState state) { _state = state; } + ThreadState get_state() { return _state; } + + + virtual uintx thread_id_for_printing() const = 0; + + // Printing + void print_on(outputStream* st) const; + void print() const; +}; + + +// Utility class for use with condition variables: +class OSThreadWaitState : public StackObj { + OSThreadBase* _osthread; + ThreadState _old_state; + public: + OSThreadWaitState(OSThreadBase* osthread, bool is_object_wait) { + _osthread = osthread; + _old_state = osthread->get_state(); + if (is_object_wait) { + osthread->set_state(OBJECT_WAIT); + } else { + osthread->set_state(CONDVAR_WAIT); + } + } + ~OSThreadWaitState() { + _osthread->set_state(_old_state); + } +}; + + +// Utility class for use with contended monitors: +class OSThreadContendState : public StackObj { + OSThreadBase* _osthread; + ThreadState _old_state; + public: + OSThreadContendState(OSThreadBase* osthread) { + _osthread = osthread; + _old_state = osthread->get_state(); + osthread->set_state(MONITOR_WAIT); + } + ~OSThreadContendState() { + _osthread->set_state(_old_state); + } +}; + +#endif // SHARE_RUNTIME_OSTHREAD_BASE_HPP From db61458da840123925cb3ba079cfaf8277880320 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Fri, 4 Oct 2024 11:55:21 +0000 Subject: [PATCH 139/188] 8341298: Open source more AWT window tests Reviewed-by: abhiscxk --- .../TestLocationByPlatformWithControls.java | 270 ++++++++++++++++++ .../Window/NoResizeEvent/NoResizeEvent.java | 82 ++++++ .../Window/ProxyCrash/PopupProxyCrash.java | 192 +++++++++++++ .../WindowToFrontTest/WindowToFrontTest.java | 83 ++++++ 4 files changed, 627 insertions(+) create mode 100644 test/jdk/java/awt/Window/LocationByPlatformWithControls/TestLocationByPlatformWithControls.java create mode 100644 test/jdk/java/awt/Window/NoResizeEvent/NoResizeEvent.java create mode 100644 test/jdk/java/awt/Window/ProxyCrash/PopupProxyCrash.java create mode 100644 test/jdk/java/awt/Window/WindowToFrontTest/WindowToFrontTest.java diff --git a/test/jdk/java/awt/Window/LocationByPlatformWithControls/TestLocationByPlatformWithControls.java b/test/jdk/java/awt/Window/LocationByPlatformWithControls/TestLocationByPlatformWithControls.java new file mode 100644 index 0000000000000..bfdba97e4eb99 --- /dev/null +++ b/test/jdk/java/awt/Window/LocationByPlatformWithControls/TestLocationByPlatformWithControls.java @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4102292 + * @summary Tests that location by platform works with other APIs + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestLocationByPlatformWithControls + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.util.Vector; + +public class TestLocationByPlatformWithControls extends Frame + implements ActionListener, ItemListener { + Panel northP; + Panel centerP; + Checkbox undecoratedCB; + Checkbox defaultLocationCB; + Checkbox visibleCB; + Checkbox iconifiedCB; + Checkbox maximizedCB; + Button createB; + Button packB; + Button moveB; + Button resizeB; + Button reshapeB; + Button disposeB; + Vector frames; + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test is to check that LocationByPlatform works with other + controls API. + 1) Create New Frame by clicking on "Create" Button in + "TestLocationByPlatformWithControls" window. + 2) Initially this Frame will not be visible, Click on checkbox + "LocationByPlatform" to set default platform location for the frame + and then click on checkbox "Visible" to see that Frame is displayed + at default offsets. + 3) Now you can play with different controls like Iconified, + Maximized, Pack, Move, Resize and Reshape to verify that these + controls work properly with the Frame. + 4) At the end dispose the Frame by clicking on "Dispose" button. + 5) Also we can do verify this for Undecorated Frame but for that we + need to follow same steps but in step 2 before we click on checkbox + "Visible", select "Undecorated" checkbox along with + "LocationByPlatform". + 6) If everything works properly test is passed, otherwise failed. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TestLocationByPlatformWithControls::new) + .logArea(4) + .build() + .awaitAndCheck(); + } + + public TestLocationByPlatformWithControls() { + northP = new Panel(); + centerP = new Panel(); + + undecoratedCB = new Checkbox("Undecorated"); + defaultLocationCB = new Checkbox("LocationByPlatform"); + visibleCB = new Checkbox("Visible"); + iconifiedCB = new Checkbox("Iconified"); + maximizedCB = new Checkbox("Maximized"); + + createB = new Button("Create"); + packB = new Button("Pack"); + moveB = new Button("Move"); + resizeB = new Button("Resize"); + reshapeB = new Button("Reshape"); + disposeB = new Button("Dispose"); + + frames = new Vector(10); + this.setTitle("TestLocationByPlatformWithControls"); + this.setLayout(new BorderLayout()); + this.add(northP, BorderLayout.NORTH); + + northP.add(new Label("New Frame")); + + createB.addActionListener(this); + northP.add(createB); + + centerP.setEnabled(false); + this.add(centerP, BorderLayout.CENTER); + + centerP.add(new Label("Last Frame")); + + centerP.add(defaultLocationCB); + defaultLocationCB.addItemListener(this); + + centerP.add(undecoratedCB); + undecoratedCB.addItemListener(this); + + centerP.add(iconifiedCB); + iconifiedCB.addItemListener(this); + + centerP.add(maximizedCB); + maximizedCB.addItemListener(this); + + centerP.add(visibleCB); + visibleCB.addItemListener(this); + + packB.addActionListener(this); + centerP.add(packB); + + moveB.addActionListener(this); + centerP.add(moveB); + + resizeB.addActionListener(this); + centerP.add(resizeB); + + reshapeB.addActionListener(this); + centerP.add(reshapeB); + + disposeB.addActionListener(this); + centerP.add(disposeB); + this.pack(); + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == createB) { + Frame frame = new Frame(); + frame.setSize(200, 200); + frames.add(frame); + updateControls(frame); + Panel panel = new Panel(); + frame.add(panel); + panel.add(new Button ("Test Button")); + panel.add(new Button ("Test Button 1")); + panel.add(new Button ("Test Button 2")); + panel.add(new Button ("Test Button 3")); + centerP.setEnabled(true); + return; + } + + if (frames.isEmpty()) { + return; + } + + Frame last = (Frame)frames.lastElement(); + + if (e.getSource() == packB) { + last.pack(); + } else + if (e.getSource() == moveB) { + int x = (int)(Math.random() * 200); + int y = (int)(Math.random() * 200); + last.setLocation(x, y); + } else + if (e.getSource() == resizeB) { + int w = (int)(Math.random() * 200); + int h = (int)(Math.random() * 200); + last.setSize(w, h); + } else + if (e.getSource() == reshapeB) { + int x = (int)(Math.random() * 200); + int y = (int)(Math.random() * 200); + int w = (int)(Math.random() * 200); + int h = (int)(Math.random() * 200); + last.setBounds(x, y, w, h); + } else + if (e.getSource() == disposeB) { + last.dispose(); + frames.remove(frames.size() - 1); + if (frames.isEmpty()) { + updateControls(null); + centerP.setEnabled(false); + return; + } + last = (Frame)frames.lastElement(); + } + updateControls(last); + } + + public void updateControls(Frame f) { + undecoratedCB.setState(f != null ? + f.isUndecorated() : false); + defaultLocationCB.setState(f != null ? + f.isLocationByPlatform() : false); + visibleCB.setState(f != null ? + f.isVisible() : false); + iconifiedCB.setState(f != null ? + (f.getExtendedState() & Frame.ICONIFIED) != 0 : false); + maximizedCB.setState(f != null ? + (f.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0 : false); + } + + public void itemStateChanged(ItemEvent e) { + Frame last = (Frame)frames.lastElement(); + try { + boolean state = e.getStateChange() == ItemEvent.SELECTED; + if (e.getSource() == visibleCB) { + last.setVisible(state); + } else + if (e.getSource() == defaultLocationCB) { + last.setLocationByPlatform(state); + } else + if (e.getSource() == undecoratedCB) { + last.setUndecorated(state); + } else + if (e.getSource() == iconifiedCB) { + if (state) { + last.setExtendedState(last.getExtendedState() | + Frame.ICONIFIED); + } else { + last.setExtendedState(last.getExtendedState() & + ~Frame.ICONIFIED); + } + } else + if (e.getSource() == maximizedCB) { + if (state) { + last.setExtendedState(last.getExtendedState() | + Frame.MAXIMIZED_BOTH); + } else { + last.setExtendedState(last.getExtendedState() & + ~Frame.MAXIMIZED_BOTH); + } + } + } catch (Throwable ex) { + PassFailJFrame.log(ex.getMessage()); + } finally { + updateControls(last); + } + } + + @Override + public void dispose() { + while (!frames.isEmpty()) { + Frame last = (Frame)frames.lastElement(); + last.dispose(); + frames.remove(frames.size() - 1); + } + } +} diff --git a/test/jdk/java/awt/Window/NoResizeEvent/NoResizeEvent.java b/test/jdk/java/awt/Window/NoResizeEvent/NoResizeEvent.java new file mode 100644 index 0000000000000..50b264acde970 --- /dev/null +++ b/test/jdk/java/awt/Window/NoResizeEvent/NoResizeEvent.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4942457 + * @key headful + * @summary Verifies that filtering of resize events on native level works. + * I.E.after Frame is shown no additional resize events are generated. + * @library /java/awt/patchlib ../../regtesthelpers + * @build java.desktop/java.awt.Helper + * @build Util + * @run main NoResizeEvent + */ + +import test.java.awt.regtesthelpers.Util; + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; + +public class NoResizeEvent { + //Mutter can send window insets too late, causing additional resize events. + private static final boolean IS_MUTTER = Util.getWMID() == Util.MUTTER_WM; + private static final int RESIZE_COUNT_LIMIT = IS_MUTTER ? 5 : 3; + private static Frame frame; + static int resize_count = 0; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(() -> createUI()); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + if (resize_count > RESIZE_COUNT_LIMIT) { + throw new RuntimeException("Resize event arrived: " + + resize_count + " times."); + } + } + } + + private static void createUI() { + frame = new Frame("NoResizeEvent"); + frame.addComponentListener(new ComponentAdapter() { + public void componentResized(ComponentEvent e) { + System.out.println(e); + resize_count++; + } + }); + frame.setVisible(true); + + try { + Thread.sleep(3000); + } catch (InterruptedException ie) { + } + System.out.println("Resize count: " + resize_count); + } +} diff --git a/test/jdk/java/awt/Window/ProxyCrash/PopupProxyCrash.java b/test/jdk/java/awt/Window/ProxyCrash/PopupProxyCrash.java new file mode 100644 index 0000000000000..b17b934a70280 --- /dev/null +++ b/test/jdk/java/awt/Window/ProxyCrash/PopupProxyCrash.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4381561 + * @key headful + * @summary Tests that when we show the popup window AWT doesn't crash due to + * the problems with focus proxy window code + * @run main PopupProxyCrash + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; + +import javax.swing.Box; +import javax.swing.JComboBox; +import javax.swing.JTextField; +import javax.swing.plaf.basic.BasicComboBoxUI; +import javax.swing.plaf.basic.BasicComboPopup; +import javax.swing.plaf.basic.ComboPopup; + +public class PopupProxyCrash implements ActionListener { + private static JTextField jtf; + private static Button tf; + private static Panel panel; + private static Font[] fonts; + private static Robot robot; + + private static JComboBox cb; + + private static MyComboBoxUI comboBoxUI; + private static Frame frame; + private static int TEST_COUNT = 10; + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + robot.setAutoDelay(100); + EventQueue.invokeAndWait(() -> createUI()); + robot.waitForIdle(); + runTest(); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createUI() { + frame = new Frame("PopupProxyCrash"); + Font dialog = new Font("Dialog", Font.PLAIN, 12); + Font serif = new Font("Serif", Font.PLAIN, 12); + Font monospaced = new Font("Monospaced", Font.PLAIN, 12); + + fonts = new Font[] { dialog, serif, monospaced }; + + cb = new JComboBox(fonts); + + cb.setLightWeightPopupEnabled(false); + comboBoxUI = new MyComboBoxUI(); + cb.setUI(comboBoxUI); + jtf = new JTextField("JTextField"); + jtf.setFont(fonts[1]); + tf = new Button("TextField"); + tf.setFont(fonts[1]); + cb.addActionListener(new PopupProxyCrash()); + + panel = new Panel() { + public Dimension getPreferredSize() { + return new Dimension(100, 20); + } + public void paint(Graphics g) { + System.out.println("Painting with font " + getFont()); + g.setColor(Color.white); + g.fillRect(0, 0, getWidth(), getHeight()); + g.setColor(Color.black); + g.setFont(getFont()); + g.drawString("LightWeight", 10, 10); + } + }; + panel.setFont(fonts[1]); + + Container parent = Box.createVerticalBox(); + parent.add(jtf); + parent.add(tf); + parent.add(panel); + parent.add(cb); + + frame.add(parent, BorderLayout.CENTER); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static Point getComboBoxLocation() throws Exception { + final Point[] result = new Point[1]; + + EventQueue.invokeAndWait(() -> { + Point point = cb.getLocationOnScreen(); + Dimension size = cb.getSize(); + + point.x += size.width / 2; + point.y += size.height / 2; + result[0] = point; + }); + return result[0]; + } + + private static Point getItemPointToClick(final int item) throws Exception { + final Point[] result = new Point[1]; + + EventQueue.invokeAndWait(() -> { + BasicComboPopup popup = (BasicComboPopup)comboBoxUI.getComboPopup(); + Point point = popup.getLocationOnScreen(); + Dimension size = popup.getSize(); + + int step = size.height / fonts.length; + point.x += size.width / 2; + point.y += step / 2 + step * item; + result[0] = point; + }); + return result[0]; + } + + static void runTest() throws Exception { + for (int i = 0; i < TEST_COUNT; i++) { + Point point = getComboBoxLocation(); + robot.mouseMove(point.x, point.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(500); + + point = getItemPointToClick(i % fonts.length); + robot.mouseMove(point.x, point.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(500); + } + } + public void actionPerformed(ActionEvent ae) { + System.out.println("Font selected"); + Font font = fonts[((JComboBox)ae.getSource()).getSelectedIndex()]; + + tf.setFont(font); + jtf.setFont(font); + panel.setFont(font); + panel.repaint(); + } + + private static class MyComboBoxUI extends BasicComboBoxUI { + public ComboPopup getComboPopup() { + return popup; + } + } +} diff --git a/test/jdk/java/awt/Window/WindowToFrontTest/WindowToFrontTest.java b/test/jdk/java/awt/Window/WindowToFrontTest/WindowToFrontTest.java new file mode 100644 index 0000000000000..e6bbadcb546db --- /dev/null +++ b/test/jdk/java/awt/Window/WindowToFrontTest/WindowToFrontTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4488209 + * @summary JFrame toFront causes the entire frame to be repainted, causes UI + * to flash + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual WindowToFrontTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class WindowToFrontTest implements ActionListener { + static Frame frame; + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1) Click the "toFront" button, this causes the + "WindowToFrontTest" frame to move front and gets repainted + completely. + 2) Move "WindowToFrontTest" window and continue to click on "toFront + multiple times. If the "WindowToFrontTest" Frame content is not + drawn properly and continues to blink, test is failed + otherwise passed. + """; + + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows(13) + .columns(40) + .build(); + EventQueue.invokeAndWait(() -> createUI()); + passFailJFrame.awaitAndCheck(); + } + + private static void createUI() { + frame = new Frame("WindowToFrontTest"); + frame.setLayout(new BorderLayout()); + frame.setSize(512, 512); + PassFailJFrame.addTestWindow(frame); + frame.setVisible(true); + + Frame buttonFrame = new Frame("Test Button"); + Button push = new Button("toFront"); + push.addActionListener(new WindowToFrontTest()); + buttonFrame.add(push); + buttonFrame.pack(); + PassFailJFrame.addTestWindow(buttonFrame); + buttonFrame.setVisible(true); + } + + public void actionPerformed(ActionEvent e) { + frame.toFront(); + } +} From feb6a830e291ff71e2803e37be6c35c237f7c1cf Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Fri, 4 Oct 2024 15:58:22 +0000 Subject: [PATCH 140/188] 8340945: Ubsan: oopStorage.cpp:374:8: runtime error: applying non-zero offset 18446744073709551168 to null pointer Reviewed-by: tschatzl, mbaesken --- src/hotspot/share/gc/shared/oopStorage.cpp | 35 +++++++----- src/hotspot/share/gc/shared/oopStorage.hpp | 2 +- .../share/gc/shared/oopStorage.inline.hpp | 5 +- .../gtest/gc/shared/test_oopStorage.cpp | 55 +++++++++++++------ 4 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/hotspot/share/gc/shared/oopStorage.cpp b/src/hotspot/share/gc/shared/oopStorage.cpp index 568888ac7d97e..2373d6b1d93a8 100644 --- a/src/hotspot/share/gc/shared/oopStorage.cpp +++ b/src/hotspot/share/gc/shared/oopStorage.cpp @@ -300,7 +300,12 @@ void OopStorage::Block::set_active_index(size_t index) { size_t OopStorage::Block::active_index_safe(const Block* block) { STATIC_ASSERT(sizeof(intptr_t) == sizeof(block->_active_index)); - return SafeFetchN((intptr_t*)&block->_active_index, 0); + // Be careful, because block could be a false positive from block_for_ptr. + assert(block != nullptr, "precondition"); + uintptr_t block_addr = reinterpret_cast(block); + uintptr_t index_loc = block_addr + offset_of(Block, _active_index); + static_assert(sizeof(size_t) == sizeof(intptr_t), "assumption"); + return static_cast(SafeFetchN(reinterpret_cast(index_loc), 0)); } unsigned OopStorage::Block::get_index(const oop* ptr) const { @@ -366,21 +371,23 @@ void OopStorage::Block::delete_block(const Block& block) { OopStorage::Block* OopStorage::Block::block_for_ptr(const OopStorage* owner, const oop* ptr) { STATIC_ASSERT(_data_pos == 0); - // Const-ness of ptr is not related to const-ness of containing block. + assert(ptr != nullptr, "precondition"); // Blocks are allocated section-aligned, so get the containing section. - oop* section_start = align_down(const_cast(ptr), block_alignment); + uintptr_t section_start = align_down(reinterpret_cast(ptr), block_alignment); // Start with a guess that the containing section is the last section, // so the block starts section_count-1 sections earlier. - oop* section = section_start - (section_size * (section_count - 1)); + size_t section_size_in_bytes = sizeof(oop) * section_size; + uintptr_t section = section_start - (section_size_in_bytes * (section_count - 1)); // Walk up through the potential block start positions, looking for // the owner in the expected location. If we're below the actual block // start position, the value at the owner position will be some oop // (possibly null), which can never match the owner. intptr_t owner_addr = reinterpret_cast(owner); - for (unsigned i = 0; i < section_count; ++i, section += section_size) { - Block* candidate = reinterpret_cast(section); - if (SafeFetchN(&candidate->_owner_address, 0) == owner_addr) { - return candidate; + for (unsigned i = 0; i < section_count; ++i, section += section_size_in_bytes) { + uintptr_t owner_loc = section + offset_of(Block, _owner_address); + static_assert(sizeof(OopStorage*) == sizeof(intptr_t), "assumption"); + if (SafeFetchN(reinterpret_cast(owner_loc), 0) == owner_addr) { + return reinterpret_cast(section); } } return nullptr; @@ -643,8 +650,7 @@ class OopStorage::WithActiveArray : public StackObj { } }; -OopStorage::Block* OopStorage::find_block_or_null(const oop* ptr) const { - assert(ptr != nullptr, "precondition"); +OopStorage::Block* OopStorage::block_for_ptr(const oop* ptr) const { return Block::block_for_ptr(this, ptr); } @@ -771,7 +777,7 @@ static inline void check_release_entry(const oop* entry) { void OopStorage::release(const oop* ptr) { check_release_entry(ptr); - Block* block = find_block_or_null(ptr); + Block* block = block_for_ptr(ptr); assert(block != nullptr, "%s: invalid release " PTR_FORMAT, name(), p2i(ptr)); log_trace(oopstorage, ref)("%s: releasing " PTR_FORMAT, name(), p2i(ptr)); block->release_entries(block->bitmask_for_entry(ptr), this); @@ -782,7 +788,7 @@ void OopStorage::release(const oop* const* ptrs, size_t size) { size_t i = 0; while (i < size) { check_release_entry(ptrs[i]); - Block* block = find_block_or_null(ptrs[i]); + Block* block = block_for_ptr(ptrs[i]); assert(block != nullptr, "%s: invalid release " PTR_FORMAT, name(), p2i(ptrs[i])); size_t count = 0; uintx releasing = 0; @@ -989,7 +995,8 @@ bool OopStorage::delete_empty_blocks() { } OopStorage::EntryStatus OopStorage::allocation_status(const oop* ptr) const { - const Block* block = find_block_or_null(ptr); + if (ptr == nullptr) return INVALID_ENTRY; + const Block* block = block_for_ptr(ptr); if (block != nullptr) { // Prevent block deletion and _active_array modification. MutexLocker ml(_allocation_mutex, Mutex::_no_safepoint_check_flag); @@ -1137,7 +1144,7 @@ const char* OopStorage::name() const { return _name; } bool OopStorage::print_containing(const oop* addr, outputStream* st) { if (addr != nullptr) { - Block* block = find_block_or_null(addr); + Block* block = block_for_ptr(addr); if (block != nullptr && block->print_containing(addr, st)) { st->print(" in oop storage \"%s\"", name()); return true; diff --git a/src/hotspot/share/gc/shared/oopStorage.hpp b/src/hotspot/share/gc/shared/oopStorage.hpp index 96cc5a23d6a91..34c980a058659 100644 --- a/src/hotspot/share/gc/shared/oopStorage.hpp +++ b/src/hotspot/share/gc/shared/oopStorage.hpp @@ -288,7 +288,7 @@ class OopStorage : public CHeapObjBase { Block* block_for_allocation(); void log_block_transition(Block* block, const char* new_state) const; - Block* find_block_or_null(const oop* ptr) const; + Block* block_for_ptr(const oop* ptr) const; void delete_empty_block(const Block& block); bool reduce_deferred_updates(); void record_needs_cleanup(); diff --git a/src/hotspot/share/gc/shared/oopStorage.inline.hpp b/src/hotspot/share/gc/shared/oopStorage.inline.hpp index 545da0be0a76e..da0926a20b6e2 100644 --- a/src/hotspot/share/gc/shared/oopStorage.inline.hpp +++ b/src/hotspot/share/gc/shared/oopStorage.inline.hpp @@ -184,7 +184,10 @@ class OopStorage::Block /* No base class, to avoid messing up alignment. */ { void set_active_index(size_t index); static size_t active_index_safe(const Block* block); // Returns 0 if access fails. - // Returns null if ptr is not in a block or not allocated in that block. + // Return block of owner containing ptr, if ptr is a valid entry of owner. + // If ptr is not a valid entry of owner then returns either null or a "false + // positive" pointer; see allocation_status. + // precondition: ptr != nullptr static Block* block_for_ptr(const OopStorage* owner, const oop* ptr); oop* allocate(); diff --git a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp index a4ac2fee66ba4..d55d6dbfc2320 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp @@ -93,6 +93,18 @@ class OopStorage::TestAccess : public AllStatic { static void block_array_set_block_count(ActiveArray* blocks, size_t count) { blocks->_block_count = count; } + + static const oop* get_block_pointer(const Block& block, unsigned index) { + return block.get_pointer(index); + } + + static Block* new_block(const OopStorage& owner) { + return Block::new_block(&owner); + } + + static void delete_block(const Block& block) { + Block::delete_block(block); + } }; typedef OopStorage::TestAccess TestAccess; @@ -518,24 +530,35 @@ TEST_VM_F(OopStorageTest, bulk_allocation) { } } -#ifndef DISABLE_GARBAGE_ALLOCATION_STATUS_TESTS -TEST_VM_F(OopStorageTest, invalid_pointer) { - { - char* mem = NEW_C_HEAP_ARRAY(char, 1000, mtInternal); - oop* ptr = reinterpret_cast(align_down(mem + 250, sizeof(oop))); - // Predicate returns false for some malloc'ed block. - EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); - FREE_C_HEAP_ARRAY(char, mem); - } +TEST_VM_F(OopStorageTest, invalid_malloc_pointer) { + char* mem = NEW_C_HEAP_ARRAY(char, 1000, mtInternal); + oop* ptr = reinterpret_cast(align_down(mem + 250, sizeof(oop))); + // Predicate returns false for some malloc'ed block. + EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); + FREE_C_HEAP_ARRAY(char, mem); +} - { - oop obj; - oop* ptr = &obj; - // Predicate returns false for some "random" location. - EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); - } +TEST_VM_F(OopStorageTest, invalid_random_pointer) { + oop obj; + oop* ptr = &obj; + // Predicate returns false for some "random" location. + EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); +} + +TEST_VM_F(OopStorageTest, invalid_block_pointer) { + // Allocate a block for storage, but don't insert it into the storage. This + // also tests the false positive case of block_for_ptr where we have a + // reference to storage at just the "right" place. + const OopBlock* block = TestAccess::new_block(storage()); + ASSERT_NE(block, NULL_BLOCK); + const oop* ptr = TestAccess::get_block_pointer(*block, 0); + EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); + TestAccess::delete_block(*block); +} + +TEST_VM_F(OopStorageTest, invalid_null_pointer) { + EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(nullptr)); } -#endif // DISABLE_GARBAGE_ALLOCATION_STATUS_TESTS class OopStorageTest::CountingIterateClosure { public: From 42f32551cd2aaa4b7609cc887cb33fc58ac12779 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Fri, 4 Oct 2024 16:14:51 +0000 Subject: [PATCH 141/188] 8341053: Two CDS tests fail again with -UseCompressedOops and UseSerialGC/UseParallelGC Reviewed-by: iklam, matsaave --- src/hotspot/share/prims/whitebox.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index ca440b69913fa..24f6156224d26 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2159,7 +2159,8 @@ WB_ENTRY(jboolean, WB_IsJVMCISupportedByGC(JNIEnv* env)) WB_END WB_ENTRY(jboolean, WB_CanWriteJavaHeapArchive(JNIEnv* env)) - return HeapShared::can_write(); + return HeapShared::can_write() + && ArchiveHeapLoader::can_use(); // work-around JDK-8341371 WB_END From beb2a51b126671d1fac8d4b473ad8042a22f9ff5 Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Fri, 4 Oct 2024 16:20:01 +0000 Subject: [PATCH 142/188] 8341377: Update VMProps.isCDSRuntimeOptionsCompatible to include Parallel and Serial GC Reviewed-by: dholmes, shade --- test/jtreg-ext/requires/VMProps.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 137cfbfec3ea4..0457fb7e3c528 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -479,12 +479,14 @@ protected boolean isCDSRuntimeOptionsCompatible() { } String CCP_DISABLED = "-XX:-UseCompressedClassPointers"; String G1GC_ENABLED = "-XX:+UseG1GC"; + String PARALLELGC_ENABLED = "-XX:+UseParallelGC"; + String SERIALGC_ENABLED = "-XX:+UseSerialGC"; for (String opt : jtropts.split(",")) { if (opt.equals(CCP_DISABLED)) { return false; } if (opt.startsWith(GC_PREFIX) && opt.endsWith(GC_SUFFIX) && - !opt.equals(G1GC_ENABLED)) { + !opt.equals(G1GC_ENABLED) && !opt.equals(PARALLELGC_ENABLED) && !opt.equals(SERIALGC_ENABLED)) { return false; } } From 0dd49970428e08d35996752ba0878a97fb6f8530 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Fri, 4 Oct 2024 16:38:31 +0000 Subject: [PATCH 143/188] 8340555: Open source DnD tests - Set4 Reviewed-by: aivanov, azvegint --- test/jdk/ProblemList.txt | 3 + .../DnDHTMLToOutlookTest.java | 82 ++++++ .../dnd/DnDHTMLToOutlookTest/DnDSource.html | 25 ++ .../dnd/DnDHTMLToOutlookTest/DnDSource.java | 142 ++++++++++ .../awt/dnd/DragSourceMotionListenerTest.java | 242 ++++++++++++++++++ .../java/awt/dnd/DragToAnotherScreenTest.java | 169 ++++++++++++ test/jdk/java/awt/dnd/RejectDragTest.java | 174 +++++++++++++ 7 files changed, 837 insertions(+) create mode 100644 test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java create mode 100644 test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.html create mode 100644 test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.java create mode 100644 test/jdk/java/awt/dnd/DragSourceMotionListenerTest.java create mode 100644 test/jdk/java/awt/dnd/DragToAnotherScreenTest.java create mode 100644 test/jdk/java/awt/dnd/RejectDragTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index b44eef1e1284c..12954e6174daa 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -467,6 +467,9 @@ java/awt/KeyboardFocusmanager/ConsumeNextMnemonicKeyTypedTest/ConsumeNextMnemoni java/awt/Window/GetScreenLocation/GetScreenLocationTest.java 8225787 linux-x64 java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64 java/awt/dnd/BadSerializationTest/BadSerializationTest.java 8277817 linux-x64,windows-x64 +java/awt/dnd/DragSourceMotionListenerTest.java 8225131 windows-all +java/awt/dnd/RejectDragTest.java 7124259 macosx-all +java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java 8027424 generic-all java/awt/GraphicsDevice/DisplayModes/UnknownRefrshRateTest.java 8286436 macosx-aarch64 java/awt/image/multiresolution/MultiresolutionIconTest.java 8291979 linux-x64,windows-all java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java 8305061 macosx-x64 diff --git a/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java new file mode 100644 index 0000000000000..8a39ce537056e --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDHTMLToOutlookTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Frame; +import java.awt.Panel; + + +/* + * @test + * @bug 6392086 + * @summary Tests dnd to another screen + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DnDHTMLToOutlookTest + */ + +public class DnDHTMLToOutlookTest { + + private static final String INSTRUCTIONS = """ + The window contains a yellow button. Click on the button + to copy HTML from DnDSource.html file into the clipboard or drag + HTML context. Paste into or drop over the HTML capable editor in + external application such as Outlook, Word. + + When the mouse enters the editor, cursor should change to indicate + that copy operation is about to happen and then release the mouse + button. HTML text without tags should appear inside the document. + + You should be able to repeat this operation multiple times. + If the above is true Press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(DnDHTMLToOutlookTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame frame = new Frame("DnDHTMLToOutlookTest"); + Panel mainPanel; + Component dragSource; + + mainPanel = new Panel(); + mainPanel.setLayout(new BorderLayout()); + + mainPanel.setBackground(Color.YELLOW); + dragSource = new DnDSource("Drag ME (HTML)!"); + + mainPanel.add(dragSource, BorderLayout.CENTER); + frame.add(mainPanel); + frame.setSize(200, 200); + return frame; + } +} diff --git a/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.html b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.html new file mode 100644 index 0000000000000..0f1b9751decdb --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.html @@ -0,0 +1,25 @@ + + +

              DnDHTMLToOutlookTest
              HTML Drag & Paste problem

              +

              if you see the bold header above without HTML tags and without StartHTML as the first word, press PASS

              diff --git a/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.java b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.java new file mode 100644 index 0000000000000..58f17e9415c50 --- /dev/null +++ b/test/jdk/java/awt/dnd/DnDHTMLToOutlookTest/DnDSource.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; + +class DnDSource extends Button implements Transferable, + DragGestureListener, + DragSourceListener { + private DataFlavor m_df; + private transient int m_dropAction; + private ByteArrayInputStream m_data = null; + + DnDSource(String label) { + super(label); + setBackground(Color.yellow); + setForeground(Color.blue); + setSize(200, 120); + + try { + m_df = new DataFlavor("text/html; Class=" + InputStream.class.getName() + "; charset=UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } + + DragSource dragSource = new DragSource(); + dragSource.createDefaultDragGestureRecognizer( + this, + DnDConstants.ACTION_COPY_OR_MOVE, + this + ); + dragSource.addDragSourceListener(this); + + String dir = System.getProperty("test.src", "."); + + try { + m_data = new ByteArrayInputStream(Files.readAllBytes( + Paths.get(dir, "DnDSource.html"))); + m_data.mark(m_data.available()); + addActionListener( + new ActionListener(){ + public void actionPerformed(ActionEvent ae){ + Toolkit.getDefaultToolkit().getSystemClipboard() + .setContents( DnDSource.this, null); + } + } + ); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void dragGestureRecognized(DragGestureEvent dge) { + System.err.println("starting Drag"); + try { + dge.startDrag(null, this, this); + } catch (InvalidDnDOperationException e) { + e.printStackTrace(); + } + } + + public void dragEnter(DragSourceDragEvent dsde) { + System.err.println("[Source] dragEnter"); + } + + public void dragOver(DragSourceDragEvent dsde) { + System.err.println("[Source] dragOver"); + m_dropAction = dsde.getDropAction(); + System.out.println("m_dropAction = " + m_dropAction); + } + + public void dragExit(DragSourceEvent dsde) { + System.err.println("[Source] dragExit"); + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + System.err.println("[Source] dragDropEnd"); + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + System.err.println("[Source] dropActionChanged"); + m_dropAction = dsde.getDropAction(); + System.out.println("m_dropAction = " + m_dropAction); + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] {m_df}; + } + + public boolean isDataFlavorSupported(DataFlavor sdf) { + System.err.println("[Source] isDataFlavorSupported" + m_df.equals(sdf)); + return m_df.equals(sdf); + } + + public Object getTransferData(DataFlavor tdf) throws UnsupportedFlavorException { + if (!m_df.equals(tdf)) { + throw new UnsupportedFlavorException(tdf); + } + System.err.println("[Source] Ok"); + m_data.reset(); + return m_data; + } +} diff --git a/test/jdk/java/awt/dnd/DragSourceMotionListenerTest.java b/test/jdk/java/awt/dnd/DragSourceMotionListenerTest.java new file mode 100644 index 0000000000000..25bf7ef03fd1e --- /dev/null +++ b/test/jdk/java/awt/dnd/DragSourceMotionListenerTest.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.AWTEventListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/* + * @test + * @key headful + * @bug 4422345 + * @summary tests that DragSourceMotionListeners work correctly and + DragSourceEvents position is correct + */ + +public class DragSourceMotionListenerTest implements AWTEventListener { + static class TestPanel extends Panel { + final Dimension preferredDimension = new Dimension(200, 200); + public Dimension getPreferredSize() { + return preferredDimension; + } + } + + private static Frame frame; + private static final Panel source = new TestPanel(); + private static final Panel target = new TestPanel(); + private static final DragSource ds = DragSource.getDefaultDragSource(); + private static volatile CountDownLatch mouseReleaseEvent; + + static volatile boolean passedTest1 = false; + static volatile boolean passedTest2 = false; + + private static final Point testPoint1 = new Point(); + private static final Point testPoint2 = new Point(); + private static volatile Point srcPoint; + private static volatile Point dstOutsidePoint; + private static volatile Point dstInsidePoint; + + private static final Transferable t = new StringSelection("TEXT"); + private static final DragGestureListener gestureListener = e -> e.startDrag(null, t); + + private static final DragSourceAdapter sourceAdapter = new DragSourceAdapter() { + public void dragMouseMoved(DragSourceDragEvent dsde) { + if (Math.abs(dsde.getX() - testPoint1.getX()) < 5) { + passedTest1 = true; + } + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + if (Math.abs(dsde.getX() - testPoint2.getX()) < 5) { + passedTest2 = true; + } + } + }; + + private static final DropTargetListener targetAdapter = new DropTargetAdapter() { + public void drop(DropTargetDropEvent e) { + e.acceptDrop(DnDConstants.ACTION_COPY); + try { + final Transferable t = e.getTransferable(); + final String str = + (String) t.getTransferData(DataFlavor.stringFlavor); + e.dropComplete(true); + } catch (Exception ex) { + ex.printStackTrace(); + e.dropComplete(false); + } + } + }; + + private static final DropTarget dropTarget = new DropTarget(target, targetAdapter); + Component clickedComponent = null; + + private void createAndShowUI() { + frame = new Frame("DragSourceMotionListenerTest"); + ds.addDragSourceListener(sourceAdapter); + ds.addDragSourceMotionListener(sourceAdapter); + ds.createDefaultDragGestureRecognizer(source, DnDConstants.ACTION_COPY, gestureListener); + target.setDropTarget(dropTarget); + + frame.setLayout(new GridLayout(1, 2)); + + frame.add(source); + frame.add(target); + + Toolkit.getDefaultToolkit() + .addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK); + frame.pack(); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(10); + + DragSourceMotionListenerTest dsmObj = new DragSourceMotionListenerTest(); + EventQueue.invokeAndWait(dsmObj::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + srcPoint = getPoint(source, 1); + + dstOutsidePoint = getPoint(frame, 3); + testPoint1.setLocation(dstOutsidePoint); + + dstInsidePoint = getPoint(target, 1); + testPoint2.setLocation(dstInsidePoint); + }); + robot.waitForIdle(); + + if (!dsmObj.pointInComponent(robot, srcPoint, source)) { + throw new RuntimeException("WARNING: Couldn't locate source panel."); + } + + if (!dsmObj.pointInComponent(robot, dstInsidePoint, target)) { + throw new RuntimeException("WARNING: Couldn't locate target panel."); + } + + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (; !srcPoint.equals(dstOutsidePoint); + srcPoint.translate(sign(dstOutsidePoint.x - srcPoint.x), + sign(dstOutsidePoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + } + + for (int i = 0; i < 10; i++) { + robot.mouseMove(srcPoint.x, srcPoint.y++); + } + + for (;!srcPoint.equals(dstInsidePoint); + srcPoint.translate(sign(dstInsidePoint.x - srcPoint.x), + sign(dstInsidePoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + robot.delay(1000); + + if (!passedTest1) { + throw new RuntimeException("Failed first test."); + } + + if (!passedTest2) { + throw new RuntimeException("Failed second test."); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static Point getPoint(Container container, int multiple) { + Point p = container.getLocationOnScreen(); + Dimension d = container.getSize(); + p.translate(multiple * d.width / 2, d.height / 2); + return p; + } + + public static int sign(int n) { + return Integer.compare(n, 0); + } + + public void eventDispatched(AWTEvent e) { + if (e.getID() == MouseEvent.MOUSE_RELEASED) { + clickedComponent = (Component)e.getSource(); + mouseReleaseEvent.countDown(); + } + } + + boolean pointInComponent(Robot robot, Point p, Component comp) throws Exception { + robot.waitForIdle(); + clickedComponent = null; + mouseReleaseEvent = new CountDownLatch(1); + robot.mouseMove(p.x, p.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + if (!mouseReleaseEvent.await(2, TimeUnit.SECONDS)) { + throw new RuntimeException("Mouse Release Event not received"); + } + + Component c = clickedComponent; + while (c != null && c != comp) { + c = c.getParent(); + } + return c == comp; + } +} diff --git a/test/jdk/java/awt/dnd/DragToAnotherScreenTest.java b/test/jdk/java/awt/dnd/DragToAnotherScreenTest.java new file mode 100644 index 0000000000000..89f18061845fe --- /dev/null +++ b/test/jdk/java/awt/dnd/DragToAnotherScreenTest.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Label; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDropEvent; +import java.util.List; + +import javax.swing.JOptionPane; + +/* + * @test + * @bug 6179157 + * @key multimon + * @summary Tests dnd to another screen + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DragToAnotherScreenTest + */ + +public class DragToAnotherScreenTest { + private static Label label0; + private static Label label1; + private static final int HGAP = 20; + + private static final String INSTRUCTIONS = """ + The following test is applicable for Single as well + as Multi-monitor screens. + + It is a semi-automated test, the test will prompt + the user whether the drag and drop action was successful or not + and automatically PASS/FAIL the test. + + If on multi-monitor screens then please position + the drag and drop windows on different screens. + + If you can not move the mouse from the frame "Drag Source" + to the frame "Drop Target" press PASS, + else proceed to the next step. + + Drag the label "Drag me" and drop it on the + label "Drop on me". + + If you can not drag to the second label (for example + if you can not drag across screens) press FAIL. + + After the drag and drop action, the test displays + Success/Failure msg in JOptionPane. + Click on OK button and the test is configured to + automatically PASS/FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(DragToAnotherScreenTest::createAndShowUI) + .positionTestUI(DragToAnotherScreenTest::positionMultiTestUI) + .logArea(10) + .build() + .awaitAndCheck(); + } + + private static List createAndShowUI() { + PassFailJFrame.log("----- System Configuration ----"); + PassFailJFrame.log("Toolkit:" + Toolkit.getDefaultToolkit() + .getClass() + .getName()); + + GraphicsDevice[] gd = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getScreenDevices(); + if (gd.length == 1) { + PassFailJFrame.log("Single Monitor"); + } else { + PassFailJFrame.log("Multi-Monitor"); + } + PassFailJFrame.log("--------------"); + PassFailJFrame.log("Test logs:\n"); + Frame frame0 = new Frame("Drag Source", gd[0].getDefaultConfiguration()); + frame0.setSize(300, 300); + label0 = new Label("Drag me"); + frame0.add(label0); + + Frame frame1 = new Frame("Drop Target", gd[(gd.length > 1 ? 1 : 0)].getDefaultConfiguration()); + frame1.setSize(300, 300); + label1 = new Label("Drop on me"); + frame1.add(label1); + + DragGestureListener dragGestureListener = dge -> dge.startDrag(null, new StringSelection(label0.getText()), null); + new DragSource().createDefaultDragGestureRecognizer(label0, + DnDConstants.ACTION_COPY, dragGestureListener); + + DropTargetAdapter dropTargetAdapter = new DropTargetAdapter() { + public void drop(DropTargetDropEvent dtde) { + Transferable t = dtde.getTransferable(); + if (t.isDataFlavorSupported(DataFlavor.stringFlavor)) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + try { + String str = (String) t.getTransferData(DataFlavor.stringFlavor); + label1.setText(str); + JOptionPane.showMessageDialog(frame0, + "getTransferData was successful", + "Test Passed", JOptionPane.PLAIN_MESSAGE); + } catch (Exception e) { + dtde.dropComplete(false); + e.printStackTrace(); + PassFailJFrame.log("getTransferData() Failed"); + JOptionPane.showMessageDialog(frame0, + "getTransferData() Failed", + "Test Failed", JOptionPane.ERROR_MESSAGE); + PassFailJFrame.forceFail("getTransferData() Failed"); + } + dtde.dropComplete(true); + } else { + dtde.rejectDrop(); + PassFailJFrame.log("stringFlavor is not supported by Transferable"); + JOptionPane.showMessageDialog(frame0, + "stringFlavor is not supported by Transferable", + "Test Failed", JOptionPane.ERROR_MESSAGE); + PassFailJFrame.forceFail("stringFlavor is not supported by Transferable"); + } + } + }; + new DropTarget(label1, dropTargetAdapter); + return List.of(frame0, frame1); + } + + private static void positionMultiTestUI(List windows, + PassFailJFrame.InstructionUI instructionUI) { + int x = instructionUI.getLocation().x + instructionUI.getSize().width + HGAP; + for (Window w : windows) { + w.setLocation(x, instructionUI.getLocation().y); + x += w.getWidth() + HGAP; + } + } +} diff --git a/test/jdk/java/awt/dnd/RejectDragTest.java b/test/jdk/java/awt/dnd/RejectDragTest.java new file mode 100644 index 0000000000000..c65612436bc38 --- /dev/null +++ b/test/jdk/java/awt/dnd/RejectDragTest.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.StringSelection; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.event.InputEvent; + +/* + * @test + * @key headful + * @bug 4407521 + * @summary Tests that DragSourceListener.dragEnter() and + DragSourceListener.dragOver() are not called after + drag rejecting, but DragSourceListener.dragExit() is. + */ + +public class RejectDragTest { + private static Frame frame; + private static Robot robot; + private static volatile boolean dragEnterCalled; + private static volatile boolean dragOverCalled; + private static volatile boolean dragExitCalledAtFirst; + private static volatile Point startPoint; + private static volatile Point endPoint; + + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + + EventQueue.invokeAndWait(RejectDragTest::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(RejectDragTest::addDnDListeners); + robot.waitForIdle(); + + testDnD(); + robot.waitForIdle(); + robot.delay(200); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void addDnDListeners() { + final DragSourceListener dragSourceListener = new DragSourceAdapter() { + private boolean first = true; + + public void dragEnter(DragSourceDragEvent dsde) { + first = false; + dragEnterCalled = true; + } + + public void dragExit(DragSourceEvent dse) { + if (first) { + dragExitCalledAtFirst = true; + first = false; + } + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + first = false; + } + + public void dragOver(DragSourceDragEvent dsde) { + first = false; + dragOverCalled = true; + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + first = false; + } + }; + + DragGestureListener dragGestureListener = + dge -> dge.startDrag(null, new StringSelection("OKAY"), + dragSourceListener); + new DragSource().createDefaultDragGestureRecognizer(frame, + DnDConstants.ACTION_COPY, + dragGestureListener); + + DropTargetAdapter dropTargetListener = new DropTargetAdapter() { + public void dragEnter(DropTargetDragEvent dtde) { + dtde.rejectDrag(); + } + + public void drop(DropTargetDropEvent dtde) { + dtde.rejectDrop(); + } + }; + + new DropTarget(frame, dropTargetListener); + } + + private static void createAndShowUI() { + frame = new Frame("RejectDragTest"); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void testDnD() throws Exception { + EventQueue.invokeAndWait(() -> { + Point start = frame.getLocationOnScreen(); + start.translate(50, 50); + startPoint = start; + + Point end = new Point(start); + end.translate(150, 150); + endPoint = end; + }); + + robot.mouseMove(startPoint.x, startPoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (Point p = new Point(startPoint); !p.equals(endPoint); + p.translate(sign(endPoint.x - p.x), + sign(endPoint.y - p.y))) { + robot.mouseMove(p.x, p.y); + robot.delay(30); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + if (dragEnterCalled || dragOverCalled) { + throw new RuntimeException("Test failed: " + + (dragEnterCalled ? "DragSourceListener.dragEnter() was called; " : "") + + (dragOverCalled ? "DragSourceListener.dragOver() was called; " : "") + + (!dragExitCalledAtFirst ? "DragSourceListener.dragExit() was not " + + "called immediately after rejectDrag() " : "")); + } + } + + public static int sign(int n) { + return Integer.compare(n, 0); + } +} From 04c9c5f0a7b49bbabfc2244411c6c995a3b464cf Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 4 Oct 2024 17:20:09 +0000 Subject: [PATCH 144/188] 8341111: open source several AWT tests including menu shortcut tests Reviewed-by: psadhukhan, jdv --- .../awt/MenuShortcut/ActionCommandTest.java | 111 ++++++++++++++ .../awt/MenuShortcut/CheckMenuShortcut.java | 139 +++++++++++++++++ .../awt/MenuShortcut/FunctionKeyShortcut.java | 140 +++++++++++++++++ .../MenuItemShortcutReplaceTest.java | 111 ++++++++++++++ test/jdk/java/awt/grab/CursorTest.java | 101 +++++++++++++ test/jdk/java/awt/grab/SystemMenuTest.java | 141 ++++++++++++++++++ 6 files changed, 743 insertions(+) create mode 100644 test/jdk/java/awt/MenuShortcut/ActionCommandTest.java create mode 100644 test/jdk/java/awt/MenuShortcut/CheckMenuShortcut.java create mode 100644 test/jdk/java/awt/MenuShortcut/FunctionKeyShortcut.java create mode 100644 test/jdk/java/awt/MenuShortcut/MenuItemShortcutReplaceTest.java create mode 100644 test/jdk/java/awt/grab/CursorTest.java create mode 100644 test/jdk/java/awt/grab/SystemMenuTest.java diff --git a/test/jdk/java/awt/MenuShortcut/ActionCommandTest.java b/test/jdk/java/awt/MenuShortcut/ActionCommandTest.java new file mode 100644 index 0000000000000..bd1648cdc2cd3 --- /dev/null +++ b/test/jdk/java/awt/MenuShortcut/ActionCommandTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4079449 + * @key headful + * @summary MenuItem objects return null if they are activated by shortcut + */ + +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Point; +import java.awt.Robot; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import static java.awt.event.KeyEvent.VK_CONTROL; +import static java.awt.event.KeyEvent.VK_META; + +public class ActionCommandTest implements ActionListener { + + static volatile Frame frame; + static volatile boolean event = false; + static volatile boolean failed = false; + static final String ITEMTEXT = "Testitem"; + + static void createUI() { + frame = new Frame("ActionCommand Menu Shortcut Test"); + MenuBar mb = new MenuBar(); + Menu m = new Menu("Test"); + MenuItem mi = new MenuItem(ITEMTEXT, new MenuShortcut(KeyEvent.VK_T)); + mi.addActionListener(new ActionCommandTest()); + m.add(mi); + mb.add(m); + frame.setMenuBar(mb); + frame.setBounds(50, 400, 200, 200); + frame.setVisible(true); + } + + public static void main(String[] args ) throws Exception { + + EventQueue.invokeAndWait(ActionCommandTest::createUI); + try { + Robot robot = new Robot(); + + robot.waitForIdle(); + robot.delay(2000); + + // Ensure window has focus + Point p = frame.getLocationOnScreen(); + robot.mouseMove(p.x + frame.getWidth() / 2, p.y + frame.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(2000); + + // invoke short cut. + robot.keyPress(KeyEvent.VK_T); + robot.delay(50); + robot.keyRelease(KeyEvent.VK_T); + robot.waitForIdle(); + robot.delay(2000); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + if (failed) { + throw new RuntimeException("No actioncommand"); + } + } + + // Since no ActionCommand is set, this should be the menuitem's label. + public void actionPerformed(ActionEvent e) { + event = true; + String s = e.getActionCommand(); + if (s == null || !s.equals(ITEMTEXT)) { + failed = true; + } + } + +} diff --git a/test/jdk/java/awt/MenuShortcut/CheckMenuShortcut.java b/test/jdk/java/awt/MenuShortcut/CheckMenuShortcut.java new file mode 100644 index 0000000000000..cebb42f1b55e3 --- /dev/null +++ b/test/jdk/java/awt/MenuShortcut/CheckMenuShortcut.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4167811 + * @summary tests that shortcuts work for Checkbox menu items + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckMenuShortcut +*/ + +import java.awt.CheckboxMenuItem; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; + +public class CheckMenuShortcut implements ActionListener, ItemListener { + + static final String INSTRUCTIONS = """ + A window that contains a text area will be displayed. + The window will have a menu labeled 'Window Menu'. Click on the menu to see its items. + + The two menu items should have shortcuts which in order are : Ctrl-A, Ctrl-I. + On macOS these will be Command-A, Command-I. + + If the second item only has the label 'checkbox item' and no shortcut + ie none of Ctrl-I or Ctrl-i, or Command-I or Command-i on macOS painted on it, the test FAILS. + + The same second item - labeled 'checkbox item' is in fact a Checkbox menu item. + The menu item should NOT be checked (eg no tick mark). + + Dismiss the menu by clicking inside the window, do not select any of menu items. + After that press Ctrl-i, (Command-i on macOS). + + After that click on the menu again. If the second menu item 'checkbox item' is now + checked, the test PASSES, if it is not checked, the test FAILS. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("CheckboxMenuItem Shortcut Test Instructions") + .instructions(INSTRUCTIONS) + .columns(60) + .logArea() + .testUI(CheckMenuShortcut::createUI) + .build() + .awaitAndCheck(); + } + + + static Frame createUI() { + + MenuBar mainMenu; + Menu menu; + MenuItem action; + CheckboxMenuItem item; + TextArea pane; + + boolean isMac = System.getProperty("os.name").startsWith("Mac"); + String ctrlA = (isMac) ? "Command-A" : "Ctrl-A"; + String ctrlI = (isMac) ? "Command-I" : "Ctrl-I"; + + CheckMenuShortcut cms = new CheckMenuShortcut(); + Frame frame = new Frame("CheckMenuShortcut"); + + mainMenu = new MenuBar(); + menu = new Menu("Window Menu"); + + action = new MenuItem("action"); + action.setShortcut(new MenuShortcut(KeyEvent.VK_A, false)); + action.addActionListener(cms); + action.setActionCommand("action"); + menu.add(action); + + item = new CheckboxMenuItem("checkbox item", false); + item.setShortcut(new MenuShortcut(KeyEvent.VK_I,false)); + item.addItemListener(cms); + item.addActionListener(cms); + menu.add(item); + + mainMenu.add(menu); + + frame.setMenuBar(mainMenu); + + pane = new TextArea(ctrlA + " -- action menu test\n", 10, 40, TextArea.SCROLLBARS_VERTICAL_ONLY); + Dimension mySize = frame.getSize(); + Insets myIns = frame.getInsets(); + pane.setBounds(new Rectangle(mySize.width - myIns.left - myIns.right, + mySize.height - myIns.top - myIns.bottom)); + pane.setLocation(myIns.left,myIns.top); + frame.add(pane); + + pane.append(ctrlI + " -- item menu test\n"); + + frame.pack(); + return frame; + } + + public void itemStateChanged(ItemEvent evt) { + PassFailJFrame.log("Got item: " + evt.getItem() + "\n"); + } + + public void actionPerformed(ActionEvent evt) { + PassFailJFrame.log("Got action: " + evt.getActionCommand() + "\n"); + } +} diff --git a/test/jdk/java/awt/MenuShortcut/FunctionKeyShortcut.java b/test/jdk/java/awt/MenuShortcut/FunctionKeyShortcut.java new file mode 100644 index 0000000000000..960de08bd2d5a --- /dev/null +++ b/test/jdk/java/awt/MenuShortcut/FunctionKeyShortcut.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4034665 + * @key headful + * @summary Function keys should work correctly as shortcuts + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import static java.awt.event.KeyEvent.VK_CONTROL; +import static java.awt.event.KeyEvent.VK_META; + +public class FunctionKeyShortcut implements ActionListener { + + static volatile Frame frame; + static volatile boolean event = false; + static volatile boolean failed = false; + + static final boolean isMac = System.getProperty("os.name").contains("OS X"); + + static void createUI() { + frame = new Frame("Function Key Menu Shortcut Test"); + MenuBar mb = new MenuBar(); + Menu m = new Menu("Test"); + MenuItem mi1 = new MenuItem("Function key 1", new MenuShortcut(KeyEvent.VK_F1)); + MenuItem mi2 = new MenuItem("Function key 2", new MenuShortcut(KeyEvent.VK_F2)); + MenuItem mi3 = new MenuItem("Function key 3", new MenuShortcut(KeyEvent.VK_F3)); + MenuItem mi4 = new MenuItem("Function key 4", new MenuShortcut(KeyEvent.VK_F4)); + MenuItem mi5 = new MenuItem("Function key 5", new MenuShortcut(KeyEvent.VK_F5)); + MenuItem mi6 = new MenuItem("Function key 6", new MenuShortcut(KeyEvent.VK_F6)); + MenuItem mi7 = new MenuItem("Function key 7", new MenuShortcut(KeyEvent.VK_F7)); + MenuItem mi8 = new MenuItem("Function key 8", new MenuShortcut(KeyEvent.VK_F8)); + MenuItem mi9 = new MenuItem("Function key 8", new MenuShortcut(KeyEvent.VK_F9)); + + FunctionKeyShortcut fks = new FunctionKeyShortcut(); + mi1.addActionListener(fks); + mi2.addActionListener(fks); + mi3.addActionListener(fks); + mi4.addActionListener(fks); + mi5.addActionListener(fks); + mi6.addActionListener(fks); + mi7.addActionListener(fks); + mi8.addActionListener(fks); + mi9.addActionListener(fks); + + m.add(mi1); + m.add(mi2); + m.add(mi3); + m.add(mi4); + m.add(mi5); + m.add(mi6); + m.add(mi7); + m.add(mi8); + m.add(mi9); + + mb.add(m); + frame.setMenuBar(mb); + frame.setBounds(50,400,200,200); + frame.setVisible(true); + } + + public static void main(String[] args ) throws Exception { + + EventQueue.invokeAndWait(FunctionKeyShortcut::createUI); + try { + Robot robot = new Robot(); + + robot.waitForIdle(); + robot.delay(2000); + + // Ensure window has focus + Point p = frame.getLocationOnScreen(); + robot.mouseMove(p.x + frame.getWidth() / 2, p.y + frame.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(2000); + + int mod = (isMac) ? KeyEvent.VK_META : KeyEvent.VK_CONTROL; + robot.keyPress(mod); + robot.keyPress(KeyEvent.VK_F1); + robot.delay(50); + robot.keyRelease(KeyEvent.VK_F1); + robot.keyRelease(mod); + robot.waitForIdle(); + robot.delay(2000); + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + if (!event || failed) { + throw new RuntimeException("No actioncommand"); + } + } + + public void actionPerformed(ActionEvent e) { + System.out.println("Got " + e); + String s = e.getActionCommand(); + event = true; + if (s == null || !s.equals("Function key 1")) { + failed = true; + } + } + +} diff --git a/test/jdk/java/awt/MenuShortcut/MenuItemShortcutReplaceTest.java b/test/jdk/java/awt/MenuShortcut/MenuItemShortcutReplaceTest.java new file mode 100644 index 0000000000000..fe59d1a02ef34 --- /dev/null +++ b/test/jdk/java/awt/MenuShortcut/MenuItemShortcutReplaceTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4080225 + * @summary A replaced menu shortcut does not draw in the menu. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuItemShortcutReplaceTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +/* + * Manual test because visual verification of the shortcut being painted is required. + */ + +public class MenuItemShortcutReplaceTest implements ActionListener { + + static boolean isMac = System.getProperty("os.name").startsWith("Mac"); + static String shortcut = (isMac) ? "Cmd" : "Ctrl"; + static String instructions = + "1. On the frame 'MenuItem Shortcut Replace Test' click on the Menu 'Click here'.\n" + + " You will see a MenuItem 'MenuItem1' with the shortcut key displayed as" + + " '" + shortcut + "+M'.\n" + + "2. Click the 'Change Shortcutkey' button.\n" + + "3. Now click on the Menu again to see the MenuItem.\n" + + "4. If the shortcut key displayed near the MenuItem is changed to " + + "'" + shortcut + "+C', press 'Pass' else press 'Fail'"; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("MenuItem Shortcut Replace Test Instructions") + .instructions(instructions) + .columns(60) + .logArea() + .testUI(MenuItemShortcutReplaceTest::createUI) + .build() + .awaitAndCheck(); + + } + + static volatile Button change; + static volatile MenuItem mi; + static volatile MenuShortcut ms; + + static Frame createUI() { + Frame frame = new Frame("MenuItem Shortcut Replace Test"); + MenuBar mb = new MenuBar(); + change = new Button("Change ShortcutKey"); + Panel p = new Panel(); + p.add(change); + MenuItemShortcutReplaceTest misrt = new MenuItemShortcutReplaceTest(); + change.addActionListener(misrt); + Menu m = new Menu("Click here"); + mb.add(m); + mi = new MenuItem("MenuItem1"); + m.add(mi); + mi.addActionListener(misrt); + frame.setMenuBar(mb); + //Set the shortcut key for the menuitem + ms = new MenuShortcut(KeyEvent.VK_M); + mi.setShortcut(ms); + frame.add(p, BorderLayout.SOUTH); + frame.setSize(300, 300); + return frame; + } + + public void actionPerformed(ActionEvent e) { + //change the shortcut key + if (e.getSource() == change) { + ms = new MenuShortcut(KeyEvent.VK_C); + mi.setShortcut(ms); + PassFailJFrame.log("Shortcut key set to "+shortcut+"C"); + } + if (e.getSource() == mi) { + PassFailJFrame.log("MenuItem Selected"); + } + } +} diff --git a/test/jdk/java/awt/grab/CursorTest.java b/test/jdk/java/awt/grab/CursorTest.java new file mode 100644 index 0000000000000..f08008cbd8f76 --- /dev/null +++ b/test/jdk/java/awt/grab/CursorTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6364746 6400007 + * @summary Cursor should be changed correctly while Swing menu is open (input is grabbed). + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CursorTest +*/ + +import java.awt.FlowLayout; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; + +public class CursorTest { + + static final String INSTRUCTIONS = """ + After the test starts you will see a frame titled "Cursor Test Window", + with two menus in the menubar (menu1 and menu2), and a textfield and + a button, labeled "JButton". + 1. Open menu1 (it should be small and fit within the border of the frame), + 2. Verify that the pointer image (cursor) is the default desktop cursor. + 3. Move the mouse over the text field - the cursor should change its shape to caret, + 4. Move the mouse over the button - the cursor should be default one, + 5. Move the mouse to the border of the frame - cursor should be a resize one + (exact shape is dependent on the border you move over), + 6. Move the mouse out of the frame - cursor should be default one, + 7. Perform steps 2-6 in reverse order (after this the mouse should be over the open menu1), + 8. Open menu2, it should be big enough to not fit within the frame, + 9. Repeat steps 2-7 (you should end up with mouse over opened menu2 :), + 10. Close the menu. + 11. If on every step the cursor was as described, press Pass, press Fail otherwise. + """; + + static JFrame createUI() { + + JButton but = new JButton("JButton"); + JPanel panel = new JPanel(); + JTextField jtf = new JTextField("JTextField", 20); + + JFrame.setDefaultLookAndFeelDecorated(true); + JFrame frame = new JFrame("Cursor Test Window"); + frame.setLayout(new FlowLayout()); + panel.add(but); + + frame.getContentPane().add(jtf); + frame.getContentPane().add(panel); + + JMenu menu1 = new JMenu("menu1"); + menu1.add(new JMenuItem("menu1,item1")); + JMenuBar mb = new JMenuBar(); + mb.add(menu1); + JMenu menu2 = new JMenu("menu2"); + for (int i = 0; i < 10; i++) { + menu2.add(new JMenuItem("menu2,item"+i)); + } + mb.add(menu2); + frame.setJMenuBar(mb); + frame.pack(); + return frame; + } + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Cursor Test") + .instructions(INSTRUCTIONS) + .columns(60) + .testUI(CursorTest::createUI) + .build() + .awaitAndCheck(); + + } +} diff --git a/test/jdk/java/awt/grab/SystemMenuTest.java b/test/jdk/java/awt/grab/SystemMenuTest.java new file mode 100644 index 0000000000000..07676b3191124 --- /dev/null +++ b/test/jdk/java/awt/grab/SystemMenuTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6364741 + * @key headful + * @requires (os.family == "windows") + * @summary REG: Using frame's menu actions does not make swing menu disappear on WinXP, + * since Mustang-b53 + */ + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.Point; +import java.awt.Robot; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; + +public class SystemMenuTest implements MenuListener { + + static volatile JMenu menu; + static volatile JMenu sub_menu; + static volatile JFrame frame; + + static volatile int selectCount = 0; + static volatile int deselectCount = 0; + static volatile boolean failed = false; + static volatile String reason = "none"; + + static void createUI() { + SystemMenuTest smt = new SystemMenuTest(); + sub_menu = new JMenu("SubMenu"); + sub_menu.addMenuListener(smt); + sub_menu.add(new JMenuItem("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); + sub_menu.add(new JMenuItem("BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB")); + menu = new JMenu("Menu"); + menu.addMenuListener(smt); + menu.add(sub_menu); + JMenuBar mb = new JMenuBar(); + mb.add(menu); + + frame = new JFrame("JFrame"); + frame.setJMenuBar(mb); + frame.pack(); + frame.setVisible(true); + } + + public static void main(String[] args) throws Exception { + + Robot robot = new Robot(); + + SwingUtilities.invokeAndWait(SystemMenuTest::createUI); + + try { + robot.waitForIdle(); + robot.delay(2000); + + Point p = menu.getLocationOnScreen(); + robot.mouseMove(p.x + menu.getWidth() / 2, p.y + menu.getHeight() / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(2000); + + p = sub_menu.getLocationOnScreen(); + robot.mouseMove(p.x + sub_menu.getWidth() / 2, p.y + sub_menu.getHeight() /2 ); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); + robot.delay(2000); + + // Alt-Space to invoke System Menu, should close Swing menus. + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_SPACE); + robot.delay(50); + robot.keyRelease(KeyEvent.VK_SPACE); + robot.keyRelease(KeyEvent.VK_ALT); + robot.waitForIdle(); + robot.delay(2000); + + if (selectCount != 2 || deselectCount != 2) { + throw new RuntimeException("unexpected selection count " + selectCount + ", " + deselectCount); + } + if (failed) { + throw new RuntimeException("Failed because " + reason); + } + } finally { + if (frame != null) { + SwingUtilities.invokeAndWait(frame::dispose); + } + } + } + + public void menuCanceled(MenuEvent e) { + System.out.println("cancelled"+e.getSource()); + } + + public void menuDeselected(MenuEvent e) { + deselectCount++; + if (selectCount != 2) { + failed = true; + reason = "deselect without two selects"; + } + System.out.println("deselected"+e.getSource()); + } + + public void menuSelected(MenuEvent e) { + if (deselectCount != 0) { + failed = true; + reason = "select without non-zero deselects"; + } + selectCount++; + System.out.println("selected"+e.getSource()); + } +} From f5f0852f51d3dc1001bf3d68b89f4aab31e05e61 Mon Sep 17 00:00:00 2001 From: Kelvin Nilsen Date: Fri, 4 Oct 2024 17:29:31 +0000 Subject: [PATCH 145/188] 8341379: Shenandoah: Improve lock contention during cleanup Reviewed-by: xpeng, phh, wkemper --- .../share/gc/shenandoah/shenandoahFreeSet.cpp | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp index 03e19a3af5e30..310cd5b8061eb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -910,7 +910,6 @@ void ShenandoahFreeSet::try_recycle_trashed(ShenandoahHeapRegion* r) { void ShenandoahFreeSet::recycle_trash() { // lock is not reentrable, check we don't have it shenandoah_assert_not_heaplocked(); - size_t count = 0; for (size_t i = 0; i < _heap->num_regions(); i++) { ShenandoahHeapRegion* r = _heap->get_region(i); @@ -919,16 +918,45 @@ void ShenandoahFreeSet::recycle_trash() { } } - // Relinquish the lock after this much time passed. - static constexpr jlong deadline_ns = 30000; // 30 us + size_t total_batches = 0; + jlong batch_start_time = 0; + jlong recycle_trash_start_time = os::javaTimeNanos(); // This value will be treated as the initial batch_start_time + jlong batch_end_time = recycle_trash_start_time; + // Process as many batches as can be processed within 10 us. + static constexpr jlong deadline_ns = 10000; // 10 us size_t idx = 0; + jlong predicted_next_batch_end_time; + jlong batch_process_time_estimate = 0; while (idx < count) { - os::naked_yield(); // Yield to allow allocators to take the lock - ShenandoahHeapLocker locker(_heap->lock()); - const jlong deadline = os::javaTimeNanos() + deadline_ns; - while (idx < count && os::javaTimeNanos() < deadline) { - try_recycle_trashed(_trash_regions[idx++]); + if (idx > 0) { + os::naked_yield(); // Yield to allow allocators to take the lock, except on the first iteration } + // Avoid another call to javaTimeNanos() if we already know time at which last batch ended + batch_start_time = batch_end_time; + const jlong deadline = batch_start_time + deadline_ns; + + ShenandoahHeapLocker locker(_heap->lock()); + do { + // Measurements on typical 2024 hardware suggest it typically requires between 1400 and 2000 ns to process a batch of + // 32 regions, assuming low contention with other threads. Sometimes this goes higher, when mutator threads + // are contending for CPU cores and/or the heap lock. On this hardware with a 10 us deadline, we expect 3-6 batches + // to be processed between yields most of the time. + // + // Note that deadline is enforced since the end of previous batch. In the case that yield() or acquisition of heap lock + // takes a "long time", we will have less time to process regions, but we will always process at least one batch between + // yields. Yielding more frequently when there is heavy contention for the heap lock or for CPU cores is considered the + // right thing to do. + const size_t REGIONS_PER_BATCH = 32; + size_t max_idx = MIN2(count, idx + REGIONS_PER_BATCH); + while (idx < max_idx) { + try_recycle_trashed(_trash_regions[idx++]); + } + total_batches++; + batch_end_time = os::javaTimeNanos(); + // Estimate includes historic combination of yield times and heap lock acquisition times. + batch_process_time_estimate = (batch_end_time - recycle_trash_start_time) / total_batches; + predicted_next_batch_end_time = batch_end_time + batch_process_time_estimate; + } while ((idx < count) && (predicted_next_batch_end_time < deadline)); } } From 2e5b420f81cf714fe66871c4b426a460b4714b28 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Fri, 4 Oct 2024 17:34:08 +0000 Subject: [PATCH 146/188] 8340326: Remove references to Applet in core-libs/security tests Reviewed-by: prr, naoto, dfuchs --- test/jdk/java/net/Socket/SocketImplTest.java | 186 ------------------ .../util/TimeZone/DefaultTimeZoneTest.html | 74 ------- .../util/TimeZone/DefaultTimeZoneTest.java | 153 +++++++------- .../java/util/logging/TestMainAppContext.java | 6 +- .../URLClassPath/ClassnameCharTest.java | 6 +- test/jdk/sun/net/www/ParseUtil_6380332.java | 5 +- .../sun/net/www/protocol/http/B6296310.java | 5 +- .../protocol/http/ResponseCacheStream.java | 4 +- .../DisableMultiplexing.java | 4 +- test/jdk/tools/launcher/HelpFlagsTest.java | 3 +- test/jdk/tools/launcher/VersionCheck.java | 3 +- 11 files changed, 99 insertions(+), 350 deletions(-) delete mode 100644 test/jdk/java/net/Socket/SocketImplTest.java delete mode 100644 test/jdk/java/util/TimeZone/DefaultTimeZoneTest.html diff --git a/test/jdk/java/net/Socket/SocketImplTest.java b/test/jdk/java/net/Socket/SocketImplTest.java deleted file mode 100644 index 28f49b2618363..0000000000000 --- a/test/jdk/java/net/Socket/SocketImplTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -import java.applet.Applet; -import java.io.*; -import java.net.*; - -/** - * Simple Applet for exposing the Socket constructor - * bug. - */ -public class SocketImplTest extends Applet { - - static public void main(String[] args) { - System.setSecurityManager(new SecurityManager()); - SocketImplTest s = new SocketImplTest(); - s.init(); - s.start(); - } - - - /** - * A no-op SocketImpl descendant. - */ - class MySocketImpl extends SocketImpl { - protected void accept(SocketImpl impl) throws IOException { - } - - protected int available(){ - return 0; - } - - protected void bind(InetAddress host, int port){ - } - - protected void close(){ - } - - protected void connect(InetAddress address, int port){ - } - - protected void connect(String host, int port){ - } - - protected void connect(SocketAddress a, int t) throws IOException { - } - - - protected void create(boolean stream){ - } - - protected InputStream getInputStream(){ - return null; - } - - protected OutputStream getOutputStream(){ - return null; - } - - protected void listen(int backlog){ - } - - public Object getOption(int optID){ - return null; - } - - public void setOption(int optID, Object value){ - } - - protected void sendUrgentData(int i){ - } - } - - class MyDatagramSocketImpl extends DatagramSocketImpl { - protected void create() throws SocketException { - } - - protected void bind(int lport, InetAddress laddr) throws SocketException { - } - - protected void send(DatagramPacket p) throws IOException { - } - - protected int peek(InetAddress i) throws IOException { - return 0; - } - - protected int peekData(DatagramPacket p) throws IOException { - return 0; - } - - protected void receive(DatagramPacket p) throws IOException { - } - - protected void setTTL(byte ttl) throws IOException { - } - - protected byte getTTL() throws IOException { - return 0; - } - - protected void setTimeToLive(int ttl) throws IOException { - } - - protected int getTimeToLive() throws IOException { - return 0; - } - - protected void join(InetAddress inetaddr) throws IOException { - } - - protected void leave(InetAddress inetaddr) throws IOException { - } - - protected void joinGroup(SocketAddress mcastaddr, NetworkInterface netIf) - throws IOException { - } - - protected void leaveGroup(SocketAddress mcastaddr, NetworkInterface netIf) - throws IOException { - } - - protected void close() { - } - - public Object getOption(int optID){ - return null; - } - - public void setOption(int optID, Object value){ - } - - } - - /** - * A no-op Socket descendant. - */ - class MySocket extends Socket { - public MySocket(SocketImpl impl) throws IOException { - super(impl); - } - } - - class MyDatagramSocket extends DatagramSocket { - public MyDatagramSocket(DatagramSocketImpl impl) { - super(impl); - } - } - - /** - * Our test case entrypoint. Generates - * a SecurityException. - */ - public void init(){ - MySocketImpl socketImpl = new MySocketImpl(); - MyDatagramSocketImpl dgramSocketImpl = new MyDatagramSocketImpl(); - - try{ - MySocket socko = new MySocket(socketImpl); - MyDatagramSocket dsock = new MyDatagramSocket(dgramSocketImpl); - } catch(IOException ioex){ - System.err.println(ioex); - } catch(SecurityException sec) { - throw new RuntimeException("Failed. Creation of socket throwing SecurityException: "); - } - } -} diff --git a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.html b/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.html deleted file mode 100644 index 1fa0659ed6392..0000000000000 --- a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.html +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - Disable Auto-adjust Daylight Saving Time Test - - - -This applet tests the platform time zone detection on all platforms (Part I) -and on/off of DST adjustment on Windows (Part II). - -Part I: - -Observe the displayed Time zone ID and the local time. If you can change -the platform time zone setting, try several time zones. If both the ID and -the local time, including the time zone name and its time zone offset, are -always correct, Part I passes. Note that some time zone IDs have their -aliases that may be displayed. For example, "US/Pacific" is an alias of -"America/Los_Angeles". - -If you are running this applet in non-English locale, the time zone names -can be displayed in the local language and English by pushing the -English/Local button. - -If platform time zones are NOT detected correctly, press the Fail button -to finish this applet. - -If this platform is Windows, proceed to Part II. Otherwise, press the Pass -button to finish this applet. - -Part II: - -Note that Part II may require the Administrator privilege to change -Windows setting. - - 1. Open the Date and Time control panel. - 2. Select any time zone where daylight saving time is *currently* in effect, - such as "(GMT-08:00) Pacific Time (US & Canada); Tijuana", - "(GMT+10:00) Canberra, Melbourne, Sydney", and Apply. - 3. Observe the local time on the control panel (Date&Time pane) and - the applet local time should be the same (daylight time). - 4. Clear "Automatically adjust clock for daylight saving changes" and Apply. - 5. Observe the two local times should be the same (standard time). - 6. Select "Automatically adjust clock for daylight saving changes" and Apply. - -If the local time in the control panel and applet are always the same, -then this test passes. Press the Pass or Fail button based on the Part II -result and finish this applet. - - - - diff --git a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java b/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java index a6d3ac50866c0..4dd644d58b529 100644 --- a/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java +++ b/test/jdk/java/util/TimeZone/DefaultTimeZoneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,85 +24,94 @@ /* * @test * @bug 4296930 5033603 7092679 - * @summary Make sure that Java runtime detects the platform time zone - * correctly. Also make sure that the system time zone detection code - * detects the "Automatically adjust clock for daylight saving - * changes" setting correctly on Windows. - * @run applet/manual=yesno DefaultTimeZoneTest.html + * @summary Ensure that Java detects the platform time zone correctly, even + * if changed during runtime. Also ensure that the system time zone detection code + * detects the "Automatically adjust clock for daylight saving changes" setting + * correctly on Windows. This is a manual test dependent on making changes to + * the platform setting of the machine and thus cannot be automated. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DefaultTimeZoneTest */ -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; -import java.text.*; -import java.util.*; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import java.awt.BorderLayout; +import java.awt.Window; +import java.lang.reflect.InvocationTargetException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; -public class DefaultTimeZoneTest extends JApplet implements Runnable { - static final String FORMAT = "yyyy-MM-dd HH:mm:ss zzzz (XXX)"; - JLabel tzid; - JLabel label; - SimpleDateFormat sdf = new SimpleDateFormat(FORMAT); - JButton button = new JButton("English"); - Thread clock; - boolean english = false; +public class DefaultTimeZoneTest { - @Override - public void init() { - tzid = new JLabel("Time zone ID: " + sdf.getTimeZone().getID(), SwingConstants.CENTER); - tzid.setAlignmentX(Component.CENTER_ALIGNMENT); - label = new JLabel(sdf.format(new Date()), SwingConstants.CENTER); - label.setAlignmentX(Component.CENTER_ALIGNMENT); - button.addActionListener(new ActionListener() { - @Override - @SuppressWarnings("deprecation") - public void actionPerformed(ActionEvent e) { - english = (english == false); - Locale loc = english ? Locale.US : Locale.getDefault(); - sdf = new SimpleDateFormat(FORMAT, loc); - button.setLabel(!english ? "English" : "Local"); - } - }); - button.setAlignmentX(Component.CENTER_ALIGNMENT); - JPanel panel = new JPanel(); - panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS)); - panel.add(Box.createRigidArea(new Dimension(0, 10))); - panel.add(tzid); - panel.add(Box.createRigidArea(new Dimension(0, 5))); - panel.add(label); - panel.add(Box.createRigidArea(new Dimension(0, 10))); - panel.add(button); - getContentPane().add(panel); - } + private static final SimpleDateFormat SDF = + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzzz (XXX)"); + private static final String INSTRUCTIONS = + """ + Tests the platform time zone detection on all platforms. + (Part I) and on/off of DST adjustment on Windows (Part II). - @Override - public void start() { - clock = new Thread(this); - clock.start(); - } + Part I: + Observe the displayed Time zone ID and the local time. + Change the platform time zone setting, then click the + "Update Time Zone" button. If the ID and local time + update correctly, part I passes, otherwise press fail. Note that + some time zone IDs have their aliases that may be displayed. + For example, "US/Pacific" is an alias of "America/Los_Angeles". + If this platform is Windows, proceed to Part II. Otherwise, press + the Pass button to complete this test. - @Override - public void stop() { - clock = null; - } + Part II: + Note that Part II may require the Administrator privilege to change + Windows setting. - @Override - public void run() { - Thread me = Thread.currentThread(); + 1. Open the Settings app and navigate to Time & Language > Date & Time + 2. Select any time zone where daylight saving time is *currently* + in effect, such as "(GMT-08:00) Pacific Time (US & Canada); + Tijuana", "(GMT+10:00) Canberra, Melbourne, Sydney", and Apply. + 3. After pressing "Update Time Zone" button, observe that the local + time on the Settings app and the test local time are the same (daylight time). + 4. Turn off "Adjust for daylight saving time automatically" + 5. Observe the two local times should be the same (standard time). + 6. Turn on "Adjust for daylight saving time automatically" - while (clock == me) { - // Reset the default time zone so that - // TimeZone.getDefault will detect the platform time zone - TimeZone.setDefault(null); - System.setProperty("user.timezone", ""); + If the local time in the Settings app and test window are always the same, + then this test passes. Press the Pass or Fail button based on the Part II + result and complete the test. + """; + + public static void main(String[] args) + throws InterruptedException, InvocationTargetException { + // Force platform time zone as default time zone + TimeZone.setDefault(null); + System.setProperty("user.timezone", ""); + // Construct test window + PassFailJFrame.builder() + .title("DefaultTimeZoneTest Instructions") + .testUI(createTest()) + .instructions(INSTRUCTIONS) + .build().awaitAndCheck(); + } + + private static Window createTest() { + var contents = new JFrame("DefaultTimeZoneTest"); + var label = new JLabel(SDF.format(new Date())); + var panel = new JPanel(); + var button = new JButton("Update Time Zone"); + panel.add(button); + contents.setSize(350, 250); + contents.add(label, BorderLayout.NORTH); + contents.add(panel, BorderLayout.CENTER); + // Update default time zone on button click + button.addActionListener(e -> { TimeZone tz = TimeZone.getDefault(); - sdf.setTimeZone(tz); - tzid.setText("Time zone ID: " + tz.getID()); - label.setText(sdf.format(new Date())); - repaint(); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - } - } + SDF.setTimeZone(tz); + label.setText(SDF.format(new Date())); + contents.repaint(); + }); + return contents; } } diff --git a/test/jdk/java/util/logging/TestMainAppContext.java b/test/jdk/java/util/logging/TestMainAppContext.java index 49f371aa32160..0bfcbbad9d85b 100644 --- a/test/jdk/java/util/logging/TestMainAppContext.java +++ b/test/jdk/java/util/logging/TestMainAppContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,8 +46,8 @@ public static void main(String... args) throws Exception { rootTG = rootTG.getParent(); } - ThreadGroup tg = new ThreadGroup(rootTG, "FakeApplet"); - final Thread t1 = new Thread(tg, "createNewAppContext") { + ThreadGroup tg = new ThreadGroup(rootTG, "main"); + final Thread t1 = new Thread(tg, "child") { @Override public void run() { try { diff --git a/test/jdk/jdk/internal/loader/URLClassPath/ClassnameCharTest.java b/test/jdk/jdk/internal/loader/URLClassPath/ClassnameCharTest.java index 9e14957ef6229..85987ef6f5e1c 100644 --- a/test/jdk/jdk/internal/loader/URLClassPath/ClassnameCharTest.java +++ b/test/jdk/jdk/internal/loader/URLClassPath/ClassnameCharTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,9 +95,9 @@ public void handle(HttpExchange exchange) { server.stop(0); } } - // the class loader code was copied from the now deleted AppletClassLoader + static class MyURLClassLoader extends URLClassLoader { - private URL base; /* applet code base URL */ + private URL base; /* code base URL */ private CodeSource codesource; /* codesource for the base URL */ private AccessControlContext acc; MyURLClassLoader(URL base) { diff --git a/test/jdk/sun/net/www/ParseUtil_6380332.java b/test/jdk/sun/net/www/ParseUtil_6380332.java index a517742f2c4bf..bd0331d52bd53 100644 --- a/test/jdk/sun/net/www/ParseUtil_6380332.java +++ b/test/jdk/sun/net/www/ParseUtil_6380332.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,12 +22,13 @@ */ /* @test - * @summary SunTea applet fails to load under Mustang + * @summary Ensure ParseUtil.toURI does not fail when port number is -1 * @bug 6380332 * @modules java.base/sun.net.www */ import sun.net.www.ParseUtil; + import java.net.URI; import java.net.URL; diff --git a/test/jdk/sun/net/www/protocol/http/B6296310.java b/test/jdk/sun/net/www/protocol/http/B6296310.java index dbb3ead18c556..867b4edaf3280 100644 --- a/test/jdk/sun/net/www/protocol/http/B6296310.java +++ b/test/jdk/sun/net/www/protocol/http/B6296310.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,8 @@ * @library /test/lib * @run main/othervm B6296310 * @run main/othervm -Djava.net.preferIPv6Addresses=true B6296310 - * @summary REGRESSION: AppletClassLoader.getResourceAsStream() behaviour is wrong in some cases + * @summary Prevent NPE in HttpURLConnection.getInputStream0() when + * content length is 0 */ import java.io.IOException; diff --git a/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java b/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java index 841279fa76d5e..2fba6d8ab7548 100644 --- a/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java +++ b/test/jdk/sun/net/www/protocol/http/ResponseCacheStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ * @bug 6262486 * @library /test/lib * @run main/othervm -Dhttp.keepAlive=false ResponseCacheStream - * @summary COMPATIBILITY: jagex_com - Monkey Puzzle applet fails to load + * @summary Ensure HttpInputStream resets properly when cache is in use */ import java.io.ByteArrayOutputStream; diff --git a/test/jdk/sun/rmi/transport/tcp/disableMultiplexing/DisableMultiplexing.java b/test/jdk/sun/rmi/transport/tcp/disableMultiplexing/DisableMultiplexing.java index 4a8748ab25320..253f166cae4dd 100644 --- a/test/jdk/sun/rmi/transport/tcp/disableMultiplexing/DisableMultiplexing.java +++ b/test/jdk/sun/rmi/transport/tcp/disableMultiplexing/DisableMultiplexing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* @test * @bug 4183204 * @summary The RMI runtime should fail to export a remote object on a TCP - * port for an applet or application that does not have permission to listen + * port for an application that does not have permission to listen * on that port, rather than engage in the deprecated "multiplexing protocol". * @author Peter Jones * diff --git a/test/jdk/tools/launcher/HelpFlagsTest.java b/test/jdk/tools/launcher/HelpFlagsTest.java index 15c6c101dd0c1..0e8bc345ddc77 100644 --- a/test/jdk/tools/launcher/HelpFlagsTest.java +++ b/test/jdk/tools/launcher/HelpFlagsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -45,7 +45,6 @@ public class HelpFlagsTest extends TestHelper { // Tools that should not be tested because a usage message is pointless. static final String[] TOOLS_NOT_TO_TEST = { - "appletviewer", // deprecated, don't test "jaccessinspector", // gui, don't test, win only "jaccessinspector-32", // gui, don't test, win-32 only "jaccesswalker", // gui, don't test, win only diff --git a/test/jdk/tools/launcher/VersionCheck.java b/test/jdk/tools/launcher/VersionCheck.java index 8ce636c4af7cf..539af8698d473 100644 --- a/test/jdk/tools/launcher/VersionCheck.java +++ b/test/jdk/tools/launcher/VersionCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,7 +67,6 @@ public class VersionCheck extends TestHelper { // tools that do not accept -version static final String[] BLACKLIST_VERSION = { - "appletviewer", "controlpanel", "jaccessinspector", "jaccessinspector-32", From c8e70df37ebc90faaffae469244cefa10e8274c1 Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Fri, 4 Oct 2024 18:08:37 +0000 Subject: [PATCH 147/188] 8341162: Open source some of the AWT window test Reviewed-by: aivanov --- .../TestLocationByPlatform.java | 105 ++++++++++++++++++ .../OwnedWindowShowTest.java | 54 +++++++++ .../awt/Window/ResizeTest/ResizeTest.java | 80 +++++++++++++ .../Window/ShowWindowTest/ShowWindowTest.java | 88 +++++++++++++++ 4 files changed, 327 insertions(+) create mode 100644 test/jdk/java/awt/Window/LocationByPlatform/TestLocationByPlatform.java create mode 100644 test/jdk/java/awt/Window/OwnedWindowShowTest/OwnedWindowShowTest.java create mode 100644 test/jdk/java/awt/Window/ResizeTest/ResizeTest.java create mode 100644 test/jdk/java/awt/Window/ShowWindowTest/ShowWindowTest.java diff --git a/test/jdk/java/awt/Window/LocationByPlatform/TestLocationByPlatform.java b/test/jdk/java/awt/Window/LocationByPlatform/TestLocationByPlatform.java new file mode 100644 index 0000000000000..33b9d048ef2a9 --- /dev/null +++ b/test/jdk/java/awt/Window/LocationByPlatform/TestLocationByPlatform.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6318630 + * @summary Test that location by platform works + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestLocationByPlatform + */ + +import java.awt.BorderLayout; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; + +public class TestLocationByPlatform { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + You should see two frames. One has locationByPlatform set, it + should be displayed somewhere on the screen most probably without + intersecting other Frames or stacked over normal frame with some + offset. Another has its location explicitly set to (0, 450). + Please verify that the frames are located correctly on the screen. + + Also verify that the picture inside of frames looks the same + and consists of red descending triangle occupying exactly the bottom + half of the frame. Make sure that there is a blue rectangle exactly + surrounding the client area of frame with no pixels between it and + the frame's decorations. Press Pass if this all is true, + otherwise press Fail. + """; + + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows(13) + .columns(40) + .build(); + EventQueue.invokeAndWait(TestLocationByPlatform::createUI); + passFailJFrame.awaitAndCheck(); + } + private static void createUI() { + Frame frame = new Frame("Normal"); + frame.setLocation(0, 450); + Canvas c = new MyCanvas(); + frame.add(c, BorderLayout.CENTER); + frame.pack(); + PassFailJFrame.addTestWindow(frame); + frame.setVisible(true); + + frame = new Frame("Location by platform"); + frame.setLocationByPlatform(true); + c = new MyCanvas(); + frame.add(c, BorderLayout.CENTER); + frame.pack(); + PassFailJFrame.addTestWindow(frame); + frame.setVisible(true); + } + + static class MyCanvas extends Canvas { + @Override + public Dimension getPreferredSize() { + return new Dimension(400, 400); + } + + @Override + public void paint(Graphics g) { + g.setColor(Color.red); + for (int i = 399; i >= 0; i--) { + g.drawLine(400 - i - 1, 400 - i - 1, + 400 - i - 1, 399); + } + g.setColor(Color.blue); + g.drawLine(0, 0, 399, 0); + g.drawLine(0, 0, 0, 399); + g.drawLine(0, 399, 399, 399); + g.drawLine(399, 0, 399, 399); + } + } +} diff --git a/test/jdk/java/awt/Window/OwnedWindowShowTest/OwnedWindowShowTest.java b/test/jdk/java/awt/Window/OwnedWindowShowTest/OwnedWindowShowTest.java new file mode 100644 index 0000000000000..c8b5ad4a619d0 --- /dev/null +++ b/test/jdk/java/awt/Window/OwnedWindowShowTest/OwnedWindowShowTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4177156 + * @key headful + * @summary Tests that multiple level of window ownership doesn't cause + * NullPointerException when showing a Window + * @run main OwnedWindowShowTest + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Window; + +public class OwnedWindowShowTest { + public static void main(String[] args) throws Exception { + EventQueue.invokeAndWait(OwnedWindowShowTest::runTest); + } + + static void runTest() { + Frame parent = new Frame("OwnedWindowShowTest"); + try { + Window owner = new Window(parent); + Window window = new Window(owner); + // Showing a window with multiple levels of ownership + // should not throw NullPointerException + window.setVisible(true); + } finally { + parent.dispose(); + } + } +} diff --git a/test/jdk/java/awt/Window/ResizeTest/ResizeTest.java b/test/jdk/java/awt/Window/ResizeTest/ResizeTest.java new file mode 100644 index 0000000000000..a9191f8bd0536 --- /dev/null +++ b/test/jdk/java/awt/Window/ResizeTest/ResizeTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4225955 + * @summary Tests that focus lost is delivered to a lightweight component + * in a disposed window + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ResizeTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; + +public class ResizeTest +{ + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1) Push button A to create modal dialog 2. + 2) Resize dialog 2, then click button B to hide it. + 3) Push button A again. Dialog B should be packed to its original + size. + 4) Push button B again to hide, and A to reshow. + Dialog B should still be the same size, then test is passed, + otherwise failed. + 5) Push button B to hide the modal dialog and then select pass/fail. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(ResizeTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("1"); + Dialog d = new Dialog(f, "2", true); + d.setLocationRelativeTo(null); + Button b2 = new Button("B"); + b2.addActionListener(e -> d.setVisible(false)); + d.setLayout(new BorderLayout()); + d.add(b2, BorderLayout.CENTER); + + Button b = new Button("A"); + f.add(b, BorderLayout.CENTER); + b.addActionListener(e -> { + d.pack(); + d.setVisible(true); + }); + f.pack(); + return f; + } +} diff --git a/test/jdk/java/awt/Window/ShowWindowTest/ShowWindowTest.java b/test/jdk/java/awt/Window/ShowWindowTest/ShowWindowTest.java new file mode 100644 index 0000000000000..4857929c94ebc --- /dev/null +++ b/test/jdk/java/awt/Window/ShowWindowTest/ShowWindowTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4084997 + * @summary See if Window can be created without its size explicitly set + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ShowWindowTest + */ + +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class ShowWindowTest implements ActionListener +{ + private static Window window; + private static Button showButton; + private static Button hideButton; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. You should see a Frame with a "Show" and a "Hide" button in it. + 2. Click on the "Show" button. A window with a "Hello World" Label + should appear + 3. If the window does not appear, the test failed, otherwise passed. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(ShowWindowTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame("ShowWindowTest"); + frame.setLayout(new FlowLayout()); + frame.setSize(100,100); + frame.add(showButton = new Button("Show")); + frame.add(hideButton = new Button("Hide")); + + ActionListener handler = new ShowWindowTest(); + showButton.addActionListener(handler); + hideButton.addActionListener(handler); + + window = new Window(frame); + window.add("Center", new Label("Hello World")); + window.setLocationRelativeTo(null); + return frame; + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == showButton) { + window.pack(); + window.setVisible(true); + } else if (e.getSource() == hideButton) + window.setVisible(false); + } +} From 7e3978eab22f040995f5794b97417022532d375d Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Fri, 4 Oct 2024 18:35:08 +0000 Subject: [PATCH 148/188] 8340164: Open source few Component tests - Set1 Reviewed-by: psadhukhan, prr --- .../LWParentMovedTest/LWParentMovedTest.java | 99 ++++++++++ .../LightWeightTabFocus.java | 154 +++++++++++++++ .../LightweightFontTest.java | 182 ++++++++++++++++++ 3 files changed, 435 insertions(+) create mode 100644 test/jdk/java/awt/LightweightComponent/LWParentMovedTest/LWParentMovedTest.java create mode 100644 test/jdk/java/awt/LightweightComponent/LightWeightTabFocus/LightWeightTabFocus.java create mode 100644 test/jdk/java/awt/LightweightComponent/LightweightFontTest/LightweightFontTest.java diff --git a/test/jdk/java/awt/LightweightComponent/LWParentMovedTest/LWParentMovedTest.java b/test/jdk/java/awt/LightweightComponent/LWParentMovedTest/LWParentMovedTest.java new file mode 100644 index 0000000000000..d46af3a0d5e51 --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/LWParentMovedTest/LWParentMovedTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4147246 + * @summary Simple check for peer != null in Component.componentMoved + * @key headful + * @run main LWParentMovedTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Container; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; + +public class LWParentMovedTest { + static CMTFrame f; + + // test will throw an exception and fail if lwc is null + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(() -> f = new CMTFrame()); + } finally { + if (f != null) { + EventQueue.invokeAndWait(() -> f.dispose()); + } + } + } +} + +class CMTFrame extends Frame { + Container lwc; + Button button; + + public CMTFrame() { + super("Moving LWC Test"); + setLayout(new FlowLayout()); + lwc = new LWSquare(Color.blue, 100, 100); + button = new Button(); + lwc.add(button); + add(lwc); + + setSize(400, 300); + setVisible(true); + + // queue up a bunch of COMPONENT_MOVED events + for (int i = 0; i < 1000; i++) { + lwc.setLocation(i, i); + } + + // remove heavyweight from lightweight container + lwc.remove(button); + } +} + +// +// Lightweight container +// +class LWSquare extends Container { + int width; + int height; + + public LWSquare(Color color, int w, int h) { + setBackground(color); + setLayout(new FlowLayout()); + width = w; + height = h; + setName("LWSquare-" + color.toString()); + } + + public void paint(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, 1000, 1000); + } +} diff --git a/test/jdk/java/awt/LightweightComponent/LightWeightTabFocus/LightWeightTabFocus.java b/test/jdk/java/awt/LightweightComponent/LightWeightTabFocus/LightWeightTabFocus.java new file mode 100644 index 0000000000000..05889580fd423 --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/LightWeightTabFocus/LightWeightTabFocus.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4095214 + * @summary Test change of focus on lightweights using the tab key + * @key headful + * @run main LightWeightTabFocus + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +public class LightWeightTabFocus { + private static Frame f; + private static LightweightButton btn1; + private static Button btn2; + private static Robot robot; + private static volatile Point point; + private static Point loc; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> createUI()); + robot.delay(1000); + EventQueue.invokeAndWait(() -> { + loc = f.getLocation(); + point = btn2.getLocation(); + }); + robot.mouseMove(loc.x + point.x, loc.y + point.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + // First TAB + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + if (!btn1.hasFocus()) { + new RuntimeException("First tab failed"); + } + // Second TAB + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + if (!btn2.hasFocus()) { + new RuntimeException("Second tab failed"); + } + // First SHIFT+TAB + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_TAB); + robot.delay(100); + robot.keyRelease(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_SHIFT); + if (!btn1.hasFocus()) { + new RuntimeException("First shift+tab failed"); + } + // Second SHIFT+TAB + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_TAB); + robot.delay(100); + robot.keyRelease(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_SHIFT); + if (!btn2.hasFocus()) { + new RuntimeException("Second shift+tab failed"); + } + + } catch (Exception e) { + e.printStackTrace(); + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static Frame createUI() { + f = new Frame("TAB Focus Change on LW Test"); + f.setLayout(new FlowLayout()); + btn1 = new LightweightButton(); + f.add(btn1); + btn2 = new Button("Click Me To start"); + f.add(btn2); + f.pack(); + f.setVisible(true); + return f; + } +} + +class LightweightButton extends Component implements FocusListener { + boolean focus; + LightweightButton() { + focus = false; + addFocusListener(this); + } + + public Dimension getPreferredSize() + { + return new Dimension(100, 100); + } + + public void focusGained(FocusEvent e) { + focus = true; + repaint(); + } + + public void focusLost(FocusEvent e) { + focus = false; + repaint(); + } + + public void paint(Graphics g) { + if (focus) { + g.drawString("Has Focus", 10, 20); + } else { + g.drawString("Not Focused", 10, 20); + } + } + + public boolean isFocusable() { + return true; + } +} diff --git a/test/jdk/java/awt/LightweightComponent/LightweightFontTest/LightweightFontTest.java b/test/jdk/java/awt/LightweightComponent/LightweightFontTest/LightweightFontTest.java new file mode 100644 index 0000000000000..4fd90656d6124 --- /dev/null +++ b/test/jdk/java/awt/LightweightComponent/LightweightFontTest/LightweightFontTest.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 4077709 4153989 + * @summary Lightweight component font settable test + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual LightweightFontTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; + + +public class LightweightFontTest { + static Font desiredFont = null; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + [ There are 7 steps to this test ] + 1. The 2 bordered labels (Emacs vs. vi) should be in a LARGE font + (approximately 1/2 inch tall) + 2. The labels should not overlap. + 3. Each button should be large enough to contain the entire label. + 4. The labels should have red backgrounds + 5. The text in the left label should be blue and the right yellow + 6. Resize the window to make it much smaller and larger + 7. The buttons should never overlap, and they should be large + enough to contain the entire label. + (although the button may disappear if there is not enough + room in the window)" + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(LightweightFontTest::createUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("Lightweight Font Test"); + f.setLayout(new FlowLayout()); + + desiredFont = new Font(Font.DIALOG, Font.PLAIN, 36); + Component component; + component = new BorderedLabel("Emacs or vi?"); + component.setFont(desiredFont); + component.setBackground(Color.red); + component.setForeground(Color.blue); + f.add(component); + component = new BorderedLabel("Vi or Emacs???"); + component.setFont(desiredFont); + component.setBackground(Color.red); + component.setForeground(Color.yellow); + f.add(component); + f.pack(); + return f; + } +} + +/** + * Lightweight component + */ +class BorderedLabel extends Component { + boolean superIsButton; + String labelString; + + BorderedLabel(String labelString) { + this.labelString = labelString; + + Component thisComponent = this; + superIsButton = (thisComponent instanceof Button); + if(superIsButton) { + ((Button)thisComponent).setLabel(labelString); + } + } + + public Dimension getMinimumSize() { + Dimension minSize = new Dimension(); + + if (superIsButton) { + minSize = super.getMinimumSize(); + } else { + + Graphics g = getGraphics(); + verifyFont(g); + FontMetrics metrics = g.getFontMetrics(); + + minSize.width = metrics.stringWidth(labelString) + 14; + minSize.height = metrics.getMaxAscent() + metrics.getMaxDescent() + 9; + + g.dispose(); + } + return minSize; + } + + public Dimension getPreferredSize() { + Dimension prefSize = new Dimension(); + if (superIsButton) { + prefSize = super.getPreferredSize(); + } else { + prefSize = getMinimumSize(); + } + return prefSize; + } + + public void paint(Graphics g) { + verifyFont(g); + super.paint(g); + if (superIsButton) { + return; + } + Dimension size = getSize(); + Color oldColor = g.getColor(); + + // draw border + g.setColor(getBackground()); + g.fill3DRect(0, 0, size.width, size.height, false); + g.fill3DRect(3, 3, size.width - 6, size.height - 6, true); + + // draw text + FontMetrics metrics = g.getFontMetrics(); + int centerX = size.width / 2; + int centerY = size.height / 2; + int textX = centerX - (metrics.stringWidth(labelString) / 2); + int textY = centerY + ((metrics.getMaxAscent() + + metrics.getMaxDescent()) / 2); + g.setColor(getForeground()); + g.drawString(labelString, textX, textY); + + g.setColor(oldColor); + } + + /** + * Verifies that the font is correct and prints a warning + * message and/or throws a RuntimeException if it is not. + */ + private void verifyFont(Graphics g) { + Font desiredFont = LightweightFontTest.desiredFont; + Font actualFont = g.getFont(); + if (!actualFont.equals(desiredFont)) { + PassFailJFrame.log("AWT BUG: FONT INFORMATION LOST!"); + PassFailJFrame.log(" Desired font: " + desiredFont); + PassFailJFrame.log(" Actual font: " + actualFont); + PassFailJFrame.forceFail(); + } + } +} From 3d38cd97eff2228e2172bfdbf5cc21cf2060f871 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Fri, 4 Oct 2024 18:36:26 +0000 Subject: [PATCH 149/188] 8340966: Open source few Checkbox and Cursor tests - Set1 Reviewed-by: psadhukhan, jdv --- .../DynamicChangeTest/DynamicChangeTest.java | 72 ++++++++ .../Cursor/CursorDragTest/ListDragCursor.java | 84 ++++++++++ .../HiddenDialogParentTest.java | 72 ++++++++ .../InvalidImageCustomCursorTest.java | 95 +++++++++++ .../Cursor/NullCursorTest/NullCursorTest.java | 154 ++++++++++++++++++ 5 files changed, 477 insertions(+) create mode 100644 test/jdk/java/awt/Checkbox/DynamicChangeTest/DynamicChangeTest.java create mode 100644 test/jdk/java/awt/Cursor/CursorDragTest/ListDragCursor.java create mode 100644 test/jdk/java/awt/Cursor/HiddenDialogParentTest/HiddenDialogParentTest.java create mode 100644 test/jdk/java/awt/Cursor/InvalidImageCustomCursorTest/InvalidImageCustomCursorTest.java create mode 100644 test/jdk/java/awt/Cursor/NullCursorTest/NullCursorTest.java diff --git a/test/jdk/java/awt/Checkbox/DynamicChangeTest/DynamicChangeTest.java b/test/jdk/java/awt/Checkbox/DynamicChangeTest/DynamicChangeTest.java new file mode 100644 index 0000000000000..b62255efa4589 --- /dev/null +++ b/test/jdk/java/awt/Checkbox/DynamicChangeTest/DynamicChangeTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6225679 + * @summary Tests that checkbox changes into radiobutton dynamically + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DynamicChangeTest + */ + +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Frame; +import java.awt.GridLayout; + +public class DynamicChangeTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test is primarily for Windows platform, but should pass + on other platforms as well. Ensure that 'This is checkbox' is + checkbox, and 'This is radiobutton' is radiobutton. + If it is so, press pass else fail. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(DynamicChangeTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Dynamic Change Checkbox Test"); + f.setSize(200, 200); + + f.setLayout(new GridLayout(2, 1)); + Checkbox ch1 = new Checkbox("This is checkbox", + new CheckboxGroup(), true); + f.add(ch1); + Checkbox ch2 = new Checkbox("This is radiobutton", null, true); + f.add(ch2); + + ch1.setCheckboxGroup(null); + ch2.setCheckboxGroup(new CheckboxGroup()); + return f; + } +} diff --git a/test/jdk/java/awt/Cursor/CursorDragTest/ListDragCursor.java b/test/jdk/java/awt/Cursor/CursorDragTest/ListDragCursor.java new file mode 100644 index 0000000000000..32923f1d78b0a --- /dev/null +++ b/test/jdk/java/awt/Cursor/CursorDragTest/ListDragCursor.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4313052 + * @summary Test cursor changes after mouse dragging ends + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ListDragCursor + */ + +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.List; +import java.awt.Panel; +import java.awt.TextArea; + +public class ListDragCursor { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Move mouse to the TextArea. + 2. Press the left mouse button. + 3. Drag mouse to the list. + 4. Release the left mouse button. + + If the mouse cursor starts as a Text Line Cursor and changes + to a regular Pointer Cursor, then Hand Cursor when hovering + the list, pass the test. This test fails if the cursor does + not update at all when pointing over the different components. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ListDragCursor::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame frame = new Frame("Cursor change after drag"); + Panel panel = new Panel(); + + List list = new List(2); + list.add("List1"); + list.add("List2"); + list.add("List3"); + list.add("List4"); + list.setCursor(new Cursor(Cursor.HAND_CURSOR)); + + TextArea textArea = new TextArea(3, 5); + textArea.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + + panel.add(textArea); + panel.add(list); + + frame.add(panel); + frame.setBounds(300, 100, 300, 150); + return frame; + } +} diff --git a/test/jdk/java/awt/Cursor/HiddenDialogParentTest/HiddenDialogParentTest.java b/test/jdk/java/awt/Cursor/HiddenDialogParentTest/HiddenDialogParentTest.java new file mode 100644 index 0000000000000..7450f4ec3bb77 --- /dev/null +++ b/test/jdk/java/awt/Cursor/HiddenDialogParentTest/HiddenDialogParentTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 5079694 + * @summary Test if JDialog respects setCursor + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HiddenDialogParentTest + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Cursor; + +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.border.LineBorder; + +public class HiddenDialogParentTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + You can see a label area in the center of JDialog. + Verify that the cursor is a hand cursor in this area. + If so, press pass, else press fail. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(HiddenDialogParentTest::createUI) + .build() + .awaitAndCheck(); + } + + public static JDialog createUI() { + JDialog dialog = new JDialog(); + dialog.setTitle("JDialog Cursor Test"); + dialog.setLayout(new BorderLayout()); + JLabel centerLabel = new JLabel("Cursor should be a hand in this " + + "label area"); + centerLabel.setBorder(new LineBorder(Color.BLACK)); + centerLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + dialog.add(centerLabel, BorderLayout.CENTER); + dialog.setSize(300, 200); + + return dialog; + } +} diff --git a/test/jdk/java/awt/Cursor/InvalidImageCustomCursorTest/InvalidImageCustomCursorTest.java b/test/jdk/java/awt/Cursor/InvalidImageCustomCursorTest/InvalidImageCustomCursorTest.java new file mode 100644 index 0000000000000..9877df342ec60 --- /dev/null +++ b/test/jdk/java/awt/Cursor/InvalidImageCustomCursorTest/InvalidImageCustomCursorTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4212593 + * @summary The Toolkit.createCustomCursor does not check absence of the + * image of cursor + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual InvalidImageCustomCursorTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Toolkit; + +public class InvalidImageCustomCursorTest { + static Cursor cursor; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Press 'Hide' button to hide (set transparent) cursor for the + green panel. Move the pointer over the green panel - pointer + should disappear. Press 'Default' button to set default cursor + for the green panel. + + If you see any exceptions or cursor is not transparent, + test failed, otherwise it passed. + """; + + Toolkit tk = Toolkit.getDefaultToolkit(); + Image image = tk.getImage("NON_EXISTING_FILE.gif"); + Point p = new Point(0, 0); + + cursor = tk.createCustomCursor(image, p, "Test"); + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(InvalidImageCustomCursorTest::createUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Invalid Cursor Image Test"); + f.setLayout(new BorderLayout()); + f.setSize(200, 200); + + Button def = new Button("Default"); + Button hide = new Button("Hide"); + Panel panel = new Panel(); + + def.addActionListener(e -> panel.setCursor(Cursor.getDefaultCursor())); + hide.addActionListener(e -> panel.setCursor(cursor)); + + panel.setBackground(Color.green); + panel.setSize(100, 100); + f.add("Center", panel); + f.add("North", hide); + f.add("South", def); + + return f; + } +} diff --git a/test/jdk/java/awt/Cursor/NullCursorTest/NullCursorTest.java b/test/jdk/java/awt/Cursor/NullCursorTest/NullCursorTest.java new file mode 100644 index 0000000000000..c2398a80eb2b2 --- /dev/null +++ b/test/jdk/java/awt/Cursor/NullCursorTest/NullCursorTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4111379 + * @summary Test for setting cursor to null for lightweight components + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual NullCursorTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class NullCursorTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Hover over each colored area as described: + Green area shows a CrossCursor. + Red area shows a TextCursor. + Yellow area shows a HandCursor. + 2. Click once in red area, then: + Green area shows a HandCursor. + Red area shows a BusyCursor. + Yellow area shows a HandCursor. + 3. Click again in red area, then: + Green area shows a CrossCursor. + Red area shows a HandCursor. + Yellow area shows a HandCursor. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(NullCursorTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Null Cursor Test Frame"); + f.setSize(200, 200); + final Container p = f; + p.setName("parent"); + p.setLayout(null); + + final Component green = p.add(new Component() { + public void paint(Graphics g) { + Rectangle r = getBounds(); + g.setColor(Color.green); + g.fillRect(0, 0, r.width, r.height); + } + }); + green.setName("green"); + green.setBackground(Color.red); + green.setBounds(50, 50, 75, 75); + green.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); + + Container h = new Container() { + public void paint(Graphics g) { + Rectangle r = getBounds(); + g.setColor(Color.yellow); + g.fillRect(0, 0, r.width, r.height); + super.paint(g); + } + }; + h.setBounds(15, 25, 150, 150); + h.setName("container"); + h.setBackground(Color.yellow); + h.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + final Component red = new Component() { + public void paint(Graphics g) { + Rectangle r = getBounds(); + Color c = getBackground(); + g.setColor(c); + g.fillRect(0, 0, r.width, r.height); + super.paint(g); + } + }; + red.setName("red"); + red.setBackground(Color.red); + red.setBounds(10, 10, 120, 120); + red.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); + + final Button b = (Button)h.add(new Button("Test")); + b.setBounds(10, 10, 40, 20); + h.add(red); + p.add(h); + + b.addActionListener(new ActionListener() { + boolean f = false; + public void actionPerformed(ActionEvent e) { + if (f) { + b.setCursor(null); + } else { + b.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } + f = !f; + } + }); + red.addMouseListener(new MouseAdapter() { + boolean f = true; + + public void mouseClicked(MouseEvent e) { + Component c = (Component)e.getSource(); + if (f) { + c.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + p.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); + green.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + f = false; + } else { + c.setCursor(null); + p.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + green.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); + f = true; + } + } + }); + return f; + } +} From 92cb6331085bb6f4db091ce80d9951413541d74a Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Fri, 4 Oct 2024 18:39:30 +0000 Subject: [PATCH 150/188] 8340967: Open source few Cursor tests - Set2 Reviewed-by: psadhukhan --- .../BlockedWindowTest/BlockedWindowTest.java | 105 ++++++++++++++ .../CursorUpdateTest/CursorUpdateTest.java | 118 +++++++++++++++ .../CustomCursorTest/CustomCursorTest.java | 137 ++++++++++++++++++ .../JPanelCursorTest/JPanelCursorTest.java | 122 ++++++++++++++++ .../Cursor/SetCursorTest/SetCursorTest.java | 82 +++++++++++ 5 files changed, 564 insertions(+) create mode 100644 test/jdk/java/awt/Cursor/BlockedWindowTest/BlockedWindowTest.java create mode 100644 test/jdk/java/awt/Cursor/CursorUpdateTest/CursorUpdateTest.java create mode 100644 test/jdk/java/awt/Cursor/CustomCursorTest/CustomCursorTest.java create mode 100644 test/jdk/java/awt/Cursor/JPanelCursorTest/JPanelCursorTest.java create mode 100644 test/jdk/java/awt/Cursor/SetCursorTest/SetCursorTest.java diff --git a/test/jdk/java/awt/Cursor/BlockedWindowTest/BlockedWindowTest.java b/test/jdk/java/awt/Cursor/BlockedWindowTest/BlockedWindowTest.java new file mode 100644 index 0000000000000..f1313dbb74246 --- /dev/null +++ b/test/jdk/java/awt/Cursor/BlockedWindowTest/BlockedWindowTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6391547 + * @summary Test if the JTextField's cursor is changed when there is a modal dialog + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual BlockedWindowTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Cursor; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +class MyDialog extends Dialog implements ActionListener { + MyDialog(Frame owner) { + super(owner, "Modal dialog", true); + setBounds(owner.getX() + 150, owner.getY() + 150, 100, 100); + setLayout(new BorderLayout()); + Button b = new Button("Close"); + add(b, "South"); + b.addActionListener(this); + setVisible(true); + } + + public void actionPerformed(ActionEvent ae) { + setVisible(false); + this.dispose(); + } +} + +class MyFrame extends Frame implements ActionListener { + Dialog d; + + public MyFrame() { + super("ManualYesNoTest"); + Button b = new Button("Click here"); + TextField tf = new TextField("A text field"); + b.addActionListener(this); + setLayout(new BorderLayout()); + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + add(b, "South"); + add(tf, "North"); + setSize(300, 300); + } + + public void actionPerformed(ActionEvent ae) { + d = new MyDialog(this); + } +} + +public class BlockedWindowTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Verify that the hand cursor is displayed over the window and + text cursor over TextField. + Click the button in the window to display a modal dialog. + Verify that default cursor is displayed over the window + and over TextField now. + Then close modal dialog and verify that hand cursor is + displayed over window and text cursor over TextField. + If so, press PASS, else press FAIL. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(BlockedWindowTest::createUI) + .build() + .awaitAndCheck(); + } + + public static MyFrame createUI() { + MyFrame f = new MyFrame(); + return f; + } +} diff --git a/test/jdk/java/awt/Cursor/CursorUpdateTest/CursorUpdateTest.java b/test/jdk/java/awt/Cursor/CursorUpdateTest/CursorUpdateTest.java new file mode 100644 index 0000000000000..33e2a3cb166a1 --- /dev/null +++ b/test/jdk/java/awt/Cursor/CursorUpdateTest/CursorUpdateTest.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5097531 + * @summary Make sure the cursor updates correctly under certain + * circumstances even when the EDT is busy + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CursorUpdateTest + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; + +public class CursorUpdateTest { + final static String progress = "|/-\\"; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Check the following: + 1. Cursor must be crosshair when hovering the mouse over the + blue square. + 2. Crosshair cursor must not flicker. + 3. The cursor must be "I-beam" when hovering the mouse over the + button. + 4. Click the button - it will display "Busy" message and a + rotating bar for 5 seconds. The cursor must change to + hourglass. + 5. (Windows only) While the cursor is on the button, press Alt. + The cursor must change to normal shape. Pressing Alt again + must revert it back to I-beam. + 6. Move the mouse out of the button and back onto it. The cursor + must update correctly (hourglass over the button, normal + over the frame) even when the button displays "busy". + Do not try to check (1) or (5) when the button displays + "Busy" - this is not required. + Pass if all the steps are as behave as described. Otherwise, + fail this test. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(CursorUpdateTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame(); + f.setLayout(new FlowLayout()); + Button b = new Button("Button"); + f.add(b); + b.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + Component c = new MyComponent(); + f.add(c); + c.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); + b.addActionListener(e -> { + String oldLabel = b.getLabel(); + Cursor oldCursor = b.getCursor(); + b.setCursor(new Cursor(Cursor.WAIT_CURSOR)); + try { + for (int i = 0; i < 50; i++) { + b.setLabel("Busy " + progress.charAt(i % 4)); + Thread.sleep(100); + } + } catch (InterruptedException ex) { + } + b.setCursor(oldCursor); + b.setLabel(oldLabel); + }); + return f; + } +} + +class MyComponent extends Component { + public void paint(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, getSize().width, getSize().height); + } + + public MyComponent() { + setBackground(Color.blue); + } + + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } +} diff --git a/test/jdk/java/awt/Cursor/CustomCursorTest/CustomCursorTest.java b/test/jdk/java/awt/Cursor/CustomCursorTest/CustomCursorTest.java new file mode 100644 index 0000000000000..32c1fdc150622 --- /dev/null +++ b/test/jdk/java/awt/Cursor/CustomCursorTest/CustomCursorTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4174035 4106384 4205805 + * @summary Test for functionality of Custom Cursor + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CustomCursorTest + */ + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Frame; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Toolkit; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JLabel; + +import static java.awt.image.BufferedImage.TYPE_INT_ARGB; + +public class CustomCursorTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test is for switching between a custom cursor and the + system cursor. + + 1. Click on the test window panel to change from the default + system cursor to the custom red square cursor + 2. Verify that the square cursor shows when the panel is clicked + 3. Verify that the square cursor is colored red + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(CustomCursorTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + JFrame f = new JFrame("Custom Cursor Test"); + CustomCursorPanel c = null; + try { + c = new CustomCursorPanel(); + } catch (IOException e) { + e.printStackTrace(); + } + + f.setIconImage(c.getImage()); + f.getContentPane().add(c); + f.setSize(400, 400); + return f; + } +} + +class CustomCursorPanel extends Panel { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + Image image; + Cursor cursor; + boolean flip = false; + + public CustomCursorPanel() throws IOException { + generateRedSquareCursor(); + + image = toolkit.getImage(System.getProperty("test.classes", ".") + + java.io.File.separator + "square_cursor.gif"); + + setBackground(Color.green); + cursor = toolkit.createCustomCursor(image, new Point(0, 0), "custom"); + + JLabel c = (JLabel) add(new JLabel("click to switch between " + + "red square and default cursors")); + c.setBackground(Color.white); + c.setForeground(Color.red); + + addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent me) { + if (!flip) { + setCursor(cursor); + flip = true; + } else { + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + flip = false; + } + } + }); + } + + public Image getImage() { + return image; + } + + private static void generateRedSquareCursor() throws IOException { + Path p = Path.of(System.getProperty("test.classes", ".")); + BufferedImage bImg = new BufferedImage(35, 34, TYPE_INT_ARGB); + Graphics2D cg = bImg.createGraphics(); + cg.setColor(Color.RED); + cg.fillRect(0, 0, 35, 34); + ImageIO.write(bImg, "png", new File(p + java.io.File.separator + + "square_cursor.gif")); + } +} diff --git a/test/jdk/java/awt/Cursor/JPanelCursorTest/JPanelCursorTest.java b/test/jdk/java/awt/Cursor/JPanelCursorTest/JPanelCursorTest.java new file mode 100644 index 0000000000000..8acd622e59212 --- /dev/null +++ b/test/jdk/java/awt/Cursor/JPanelCursorTest/JPanelCursorTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4114073 + * @summary Test for setCursor in a JPanel when added to a JFrame's contentPane + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual JPanelCursorTest + */ + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.border.BevelBorder; + +public class JPanelCursorTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test checks for setCursor in a JPanel when added to a + JFrame's contentPane. + + 1. Verify that the cursor in the left side of the test window + is a default cursor. + 2. Verify that the cursor changes to the crosshair cursor when + pointing over the button. + 3. Verify that the cursor changes to the hand cursor when in + the right side of the splitpane (and not on the button). + + If true, then pass the test. Otherwise, fail this test. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(JPanelCursorTest::createUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createUI() { + JFrame frame = new JFrame(); + + JSplitPane j = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); + ExtJComponent pane = new ExtJComponent(); + + CursorBugPanel panel = new CursorBugPanel(); + + j.setLeftComponent(pane); + j.setRightComponent(panel); + j.setContinuousLayout(true); + + frame.getContentPane().add("Center", j); + pane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR)); + frame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + frame.pack(); + return frame; + } +} + +class ExtJComponent extends JComponent { + public ExtJComponent() { + super(); + setOpaque(true); + setBackground(Color.green); + setForeground(Color.red); + setBorder(new BevelBorder(BevelBorder.RAISED)); + } + public void paintComponent(Graphics g) { + g.drawString("Default", 20, 30); + } + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } +} + +class CursorBugPanel extends JPanel { + public CursorBugPanel () { + // BUG: fails to set cursor for panel + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + + // Create a button + JButton button = new JButton("Crosshair"); + + // Sets cursor for button, no problem + button.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); + add(button); + } + + public void paintComponent(Graphics g) { + g.drawString("Hand", 20, 60); + } +} diff --git a/test/jdk/java/awt/Cursor/SetCursorTest/SetCursorTest.java b/test/jdk/java/awt/Cursor/SetCursorTest/SetCursorTest.java new file mode 100644 index 0000000000000..87f028eb4f617 --- /dev/null +++ b/test/jdk/java/awt/Cursor/SetCursorTest/SetCursorTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4160080 + * @summary Test setCursor() on lightweight components when event is generated + * by a button + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetCursorTest + */ + +import java.awt.Cursor; + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; + + +public class SetCursorTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test checks for the behavior of setCursor() when called in + a JFrame's JButton action event. + + 1. Click the "OK" button in the test window. + 2. Verify that the cursor changes to the waiting cursor instead + of the default system cursor. + + If true, then pass the test. Otherwise, fail this test. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(SetCursorTest::createUI) + .build() + .awaitAndCheck(); + } + + public static myFrame createUI() { + myFrame f = new myFrame(); + return f; + } +} + +class myFrame extends JFrame { + public myFrame() { + super("SetCursor With Button Test"); + setSize(200, 200); + + final JPanel p = new JPanel(); + final JButton okButton = new JButton("OK"); + okButton.addActionListener(e -> + setCursor(new Cursor(Cursor.WAIT_CURSOR))); + + p.add(okButton); + getContentPane().add(p); + } +} From 86e3d52c70a611975da3abdebd2e1f14c7a1d019 Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Fri, 4 Oct 2024 18:42:45 +0000 Subject: [PATCH 151/188] 8341258: Open source few various AWT tests - Set1 Reviewed-by: psadhukhan --- .../RemoveComponentTest.java | 166 ++++++++++++++++++ .../java/awt/GradientPaint/JerkyGradient.java | 125 +++++++++++++ .../jdk/java/awt/GradientPaint/ShearTest.java | 137 +++++++++++++++ 3 files changed, 428 insertions(+) create mode 100644 test/jdk/java/awt/CardLayout/RemoveComponentTest/RemoveComponentTest.java create mode 100644 test/jdk/java/awt/GradientPaint/JerkyGradient.java create mode 100644 test/jdk/java/awt/GradientPaint/ShearTest.java diff --git a/test/jdk/java/awt/CardLayout/RemoveComponentTest/RemoveComponentTest.java b/test/jdk/java/awt/CardLayout/RemoveComponentTest/RemoveComponentTest.java new file mode 100644 index 0000000000000..0a23a98953302 --- /dev/null +++ b/test/jdk/java/awt/CardLayout/RemoveComponentTest/RemoveComponentTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4546123 + * @summary CardLayout becomes unusable after deleting an element + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RemoveComponentTest + */ + +import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +public class RemoveComponentTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + You should see a frame titled "Test Frame For + RemoveComponentTest". Try to select a few different panels from + the second menu. Make sure your last choice is the red panel. + Then click close (in first menu). After that you should be able + to select any panels except red one. + If that is the case, the test passes. Otherwise, the test failed. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(RemoveComponentTest::createUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + TestFrame frame = new TestFrame(); + frame.setSize(200, 200); + return frame; + } +} + +class TestFrame extends Frame implements ActionListener { + public Panel aPanel; + public TestPanel pageRed; + public TestPanel pageGreen; + public TestPanel pageBlue; + public String currentSelection = ""; + + public MenuItem mi; + public CardLayout theCardLayout; + + + public TestFrame() { + super("Test Frame For RemoveComponentTest"); + + setBackground(Color.black); + setLayout(new BorderLayout(5, 5)); + + MenuBar mb = new MenuBar(); + + Menu fileMenu = new Menu("File"); + Menu pageMenu = new Menu("Pages"); + + mi = new MenuItem("Close"); + mi.addActionListener(this); + fileMenu.add(mi); + + mi = new MenuItem("Red"); + mi.addActionListener(this); + pageMenu.add(mi); + + mi = new MenuItem("Green"); + mi.addActionListener(this); + pageMenu.add(mi); + + mi = new MenuItem("Blue"); + mi.addActionListener(this); + pageMenu.add(mi); + + mb.add(fileMenu); + mb.add(pageMenu); + + setMenuBar(mb); + + aPanel = new Panel(); + theCardLayout = new CardLayout(); + + aPanel.setLayout(theCardLayout); + + pageRed = new TestPanel("PageRed", Color.red); + pageGreen = new TestPanel("PageGreen", Color.green); + pageBlue = new TestPanel("PageBlue", Color.blue); + + aPanel.add("PageRed", pageRed); + aPanel.add("PageGreen", pageGreen); + aPanel.add("PageBlue", pageBlue); + + add("Center", aPanel); + setSize(getPreferredSize()); + } + + public Insets getInsets() { + return new Insets(47, 9, 9, 9); + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Red")) { + theCardLayout.show(aPanel, "PageRed"); + currentSelection = "PageRed"; + } else if (e.getActionCommand().equals("Green")) { + theCardLayout.show(aPanel, "PageGreen"); + } else if (e.getActionCommand().equals("Blue")) { + theCardLayout.show(aPanel, "PageBlue"); + } else if (e.getActionCommand().equals("Close")) { + PassFailJFrame.log("Closing"); + + if (currentSelection.equals("PageRed")) { + PassFailJFrame.log("Remove page red"); + theCardLayout.removeLayoutComponent(pageRed); + } + } + } +} + +class TestPanel extends JPanel { + private String pageName; + + TestPanel(String pageName, Color color) { + setBackground(color); + add(new JLabel(pageName)); + } +} diff --git a/test/jdk/java/awt/GradientPaint/JerkyGradient.java b/test/jdk/java/awt/GradientPaint/JerkyGradient.java new file mode 100644 index 0000000000000..dc33b9c185af8 --- /dev/null +++ b/test/jdk/java/awt/GradientPaint/JerkyGradient.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4221201 + * @summary Test where the gradient drawn should remain in sync with the + * rotating rectangle. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual JerkyGradient + */ + +import java.awt.Color; +import java.awt.Frame; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Panel; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; + +public class JerkyGradient extends Panel implements Runnable { + protected static Shape mShape; + protected static Paint mPaint; + protected static double mTheta; + static Thread animatorThread; + static BufferedImage mImg; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Watch at least one full rotation of the rectangle. Check that + the gradient drawn remains in sync with the rotating + rectangle. If so, pass this test. Otherwise, fail this test. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(JerkyGradient::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Rotating Gradient Test"); + JerkyGradient jg = new JerkyGradient(); + f.add(jg); + f.setSize(200, 200); + return f; + } + + public JerkyGradient() { + mShape = new Rectangle2D.Double(60, 50, 80, 100); + mPaint = new GradientPaint(0, 0, Color.red, + 25, 25, Color.yellow, + true); + mImg = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB); + + animatorThread = new Thread(this); + animatorThread.setPriority(Thread.MIN_PRIORITY); + animatorThread.start(); + } + + public synchronized void run() { + Thread me = Thread.currentThread(); + double increment = Math.PI / 36; + double twoPI = Math.PI * 2; + + while (animatorThread == me) { + mTheta = (mTheta + increment) % twoPI; + repaint(); + try { + wait(50); + } catch (InterruptedException ie) { + break; + } + } + } + + public void update(Graphics g) { + Graphics2D g2 = mImg.createGraphics(); + g2.setColor(getBackground()); + g2.fillRect(0, 0, 200, 200); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2.rotate(mTheta, 100, 100); + g2.setPaint(Color.black); + g2.drawLine(100, 30, 100, 55); + g2.setPaint(mPaint); + g2.fill(mShape); + g2.setPaint(Color.black); + g2.draw(mShape); + paint(g); + g2.dispose(); + } + + public void paint(Graphics g) { + g.drawImage(mImg, 0, 0, null); + } +} diff --git a/test/jdk/java/awt/GradientPaint/ShearTest.java b/test/jdk/java/awt/GradientPaint/ShearTest.java new file mode 100644 index 0000000000000..95a4e4a6dcd3e --- /dev/null +++ b/test/jdk/java/awt/GradientPaint/ShearTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4171820 + * @summary Checks that GradientPaint responds to shearing transforms correctly + * The gradients drawn should be parallel to the sides of the + * indicated anchor rectangle. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ShearTest + */ + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; + +public class ShearTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This test displays 2 rows each containing 4 gradient fills. Each + gradient fill is labeled depending on whether the line or lines + of the gradient should be truly vertical, truly horizontal, or + some slanted diagonal direction. The test passes if the direction + of each gradient matches its label. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(35) + .testUI(ShearTest::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame f = new Frame("Shear Gradient Test"); + f.setLayout(new GridLayout(0, 1)); + f.add(getPanelSet(false), "North"); + f.add(getPanelSet(true), "Center"); + f.setSize(500, 300); + return f; + } + + public static Panel getPanelSet(boolean horizontal) { + String direven = horizontal ? "Slanted" : "Vertical"; + String dirodd = horizontal ? "Horizontal" : "Slanted"; + + Panel p = new Panel(); + p.setLayout(new GridLayout(0, 4)); + p.add(new ShearCanvas(direven, false, horizontal, false, true)); + p.add(new ShearCanvas(dirodd, false, horizontal, true, false)); + p.add(new ShearCanvas(direven, true, horizontal, false, true)); + p.add(new ShearCanvas(dirodd, true, horizontal, true, false)); + + return p; + } + + public static class ShearCanvas extends Canvas { + public static final int GRADW = 30; + + public static final Rectangle anchor = + new Rectangle(-GRADW / 2, -GRADW / 2, GRADW, GRADW); + + public static final Color faintblue = new Color(0f, 0f, 1.0f, 0.35f); + + private AffineTransform txform; + private GradientPaint grad; + private String label; + + public ShearCanvas(String label, + boolean cyclic, boolean horizontal, + boolean shearx, boolean sheary) { + txform = new AffineTransform(); + if (shearx) { + txform.shear(-.5, 0); + } + if (sheary) { + txform.shear(0, -.5); + } + int relx = horizontal ? 0 : GRADW / 2; + int rely = horizontal ? GRADW / 2 : 0; + grad = new GradientPaint(-relx, -rely, Color.green, + relx, rely, Color.yellow, cyclic); + this.label = label; + } + + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D) g; + + AffineTransform at = g2d.getTransform(); + g2d.translate(75, 75); + g2d.transform(txform); + g2d.setPaint(grad); + g2d.fill(g.getClip()); + g2d.setColor(faintblue); + g2d.fill(anchor); + g2d.setTransform(at); + + Dimension d = getSize(); + g2d.setColor(Color.black); + g2d.drawRect(0, 0, d.width - 1, d.height - 1); + g2d.drawString(label, 5, d.height - 5); + g2d.dispose(); + } + } +} From e70cbcfd0c07c0334bf3d5fe20da806129d7565e Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 4 Oct 2024 19:25:31 +0000 Subject: [PATCH 152/188] 8341541: Wrong anchor in wrapper classes links Reviewed-by: hannesw, liach --- src/java.base/share/classes/java/lang/package-info.java | 4 ++-- .../share/classes/javax/lang/model/util/Types.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/package-info.java b/src/java.base/share/classes/java/lang/package-info.java index 0484ecb29527d..9ca4482c8191f 100644 --- a/src/java.base/share/classes/java/lang/package-info.java +++ b/src/java.base/share/classes/java/lang/package-info.java @@ -29,8 +29,8 @@ * Object}, which is the root of the class hierarchy, and {@link * Class}, instances of which represent classes at run time. * - *

              Frequently it is necessary to represent a value of primitive - * type as if it were an object.The {@index + *

              Frequently it is necessary to represent a + * value of primitive type as if it were an object.The {@index * "wrapper classes"} {@link Boolean}, {@link Byte}, {@link * Character}, {@link Short}, {@link Integer}, {@link Long}, {@link * Float}, and {@link Double} serve this purpose. An object of type diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java index ce83cda405862..8be31c26f77c1 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java @@ -206,7 +206,7 @@ public interface Types { * * @throws IllegalArgumentException if the given type has no * unboxing conversion. Only types for the {@linkplain - * java.lang##wrapperClasses wrapper classes} have an + * java.lang##wrapperClass wrapper classes} have an * unboxing conversion. * @jls 5.1.8 Unboxing Conversion */ From a3e23572d5e879bd1c3b1755cf7be4601d03b62e Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 4 Oct 2024 20:31:28 +0000 Subject: [PATCH 153/188] 8341483: Clarify special case handling of Types.getArrayType Reviewed-by: liach, prappo, dlsmith --- .../classes/javax/lang/model/util/Types.java | 5 +- .../com/sun/tools/javac/model/JavacTypes.java | 4 ++ .../model/util/types/TestInvalidInputs.java | 68 ++++++++++++++++--- 3 files changed, 65 insertions(+), 12 deletions(-) diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java index 8be31c26f77c1..951b56ed2149a 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java @@ -263,7 +263,10 @@ public interface Types { * * @param componentType the component type * @throws IllegalArgumentException if the component type is not valid for - * an array, including executable, package, module, and wildcard types + * an array. All valid types are {@linkplain ReferenceType + * reference types} or {@linkplain PrimitiveType primitive types}. + * Invalid types include {@linkplain NullType null}, executable, package, + * module, and wildcard types. * @jls 10.1 Array Types */ ArrayType getArrayType(TypeMirror componentType); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java index 1bc5de7f73a80..71e39a6a4080f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacTypes.java @@ -193,10 +193,14 @@ public NoType getNoType(TypeKind kind) { public ArrayType getArrayType(TypeMirror componentType) { switch (componentType.getKind()) { case VOID: + case NONE: + case NULL: case EXECUTABLE: case WILDCARD: // heh! case PACKAGE: case MODULE: + case UNION: + case INTERSECTION: throw new IllegalArgumentException(componentType.toString()); } return new Type.ArrayType((Type) componentType, syms.arrayClass); diff --git a/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java b/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java index 3cc1e246e41d9..47b11bbbba84e 100644 --- a/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java +++ b/test/langtools/tools/javac/processing/model/util/types/TestInvalidInputs.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8340721 + * @bug 8340721 8341483 * @summary Test invalid inputs to javax.lang.model.util.Types methods * @library /tools/javac/lib * @modules java.compiler @@ -68,8 +68,20 @@ public boolean process(Set annotations, RoundEnvironment roundEnv) { if (!roundEnv.processingOver()) { initializeTypes(); + + // isSubType + // isAssignable + // contains + // directSupertypes testUnboxedType(); + // capture + // getPrimitiveType + // getNoType + testGetArrayType(); testGetWildcardType(); + // getDeclaredType + // getDeclaredType (overload) + // asMemberOf } return true; } @@ -136,15 +148,18 @@ void testUnboxedType() { // Reference types are ArrayType, DeclaredType, ErrorType, NullType, TypeVariable // non-reference: ExecutableType, IntersectionType, NoType, PrimitiveType, UnionType, WildcardType - var invalidInputs = List.of(objectType, stringType, arrayType, - executableType, intersectionType, - noTypeVoid, noTypeNone, noTypePackage, noTypeModule, nullType, - primitiveType, /*unionType, */ wildcardType); + var invalidInputs = + List.of(primitiveType, executableType, + objectType, stringType, arrayType, + intersectionType, /*unionType, */ + noTypeVoid, noTypeNone, noTypePackage, noTypeModule, + nullType, + wildcardType); for (TypeMirror tm : invalidInputs) { try { PrimitiveType pt = types.unboxedType(tm); - throw new RuntimeException("Should not reach " + tm); + shouldNotReach(tm); } catch(IllegalArgumentException iae) { ; // Expected } @@ -152,6 +167,11 @@ void testUnboxedType() { return; } + private void shouldNotReach(TypeMirror tm) { + throw new RuntimeException("Should not reach " + tm + + " " + tm.getKind()); + } + /** * @throws IllegalArgumentException if bounds are not valid, * including for types that are not {@linkplain ReferenceType @@ -160,25 +180,51 @@ void testUnboxedType() { void testGetWildcardType() { // Reference types are ArrayType, DeclaredType, ErrorType, NullType, TypeVariable // non-reference: ExecutableType, IntersectionType, NoType, PrimitiveType, UnionType, WildcardType - var invalidInputs = List.of(executableType, intersectionType, - noTypeVoid, noTypeNone, noTypePackage, noTypeModule, nullType, - primitiveType, /*unionType, */ wildcardType); + var invalidInputs = + List.of(primitiveType, executableType, + intersectionType, /*unionType, */ + noTypeVoid, noTypeNone, noTypePackage, noTypeModule, + nullType, + wildcardType); for (TypeMirror tm : invalidInputs) { try { WildcardType wc1 = types.getWildcardType(tm, null); - throw new RuntimeException("Should not reach " + tm); + shouldNotReach(tm); } catch(IllegalArgumentException iae) { ; // Expected } try { WildcardType wc2 = types.getWildcardType(null, tm); - throw new RuntimeException("Should not reach " + tm); + shouldNotReach(tm); } catch(IllegalArgumentException iae) { ; // Expected } } return; } + + /** + * @throws IllegalArgumentException if the component type is not valid for + * an array. All valid types are {@linkplain ReferenceType + * reference types} or {@linkplain PrimitiveType primitive types}. + * Invalid types include null, executable, package, module, and wildcard types. + */ + void testGetArrayType() { + var invalidInputs = + List.of(executableType, + noTypeVoid, noTypeNone, noTypePackage, noTypeModule, + nullType, + /*unionType, */ wildcardType); + + for (TypeMirror tm : invalidInputs) { + try { + ArrayType arrayType = types.getArrayType(tm); + shouldNotReach(tm); + } catch(IllegalArgumentException iae) { + ; // Expected + } + } + } } From 33e4bfdf919c44bebcf122818ab92deeb1f1cdce Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Fri, 4 Oct 2024 21:17:21 +0000 Subject: [PATCH 154/188] 8341295: Add some useful debugging APIs to the debug agent Reviewed-by: amenkov, sspitsyn --- .../share/native/libjdwp/util.c | 179 ++++++++++++++++++ .../share/native/libjdwp/util.h | 9 + 2 files changed, 188 insertions(+) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c index 7e198be9a4637..335acc62dcf4f 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c @@ -1652,6 +1652,185 @@ setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue) } } +#ifdef DEBUG +// APIs that can be called when debugging the debug agent + +#define check_jvmti_status(err, msg) \ + if (err != JVMTI_ERROR_NONE) { \ + EXIT_ERROR(err, msg); \ + } + +char* +translateThreadState(jint flags) { + char str[15 * 20]; + str[0] = '\0'; + + if (flags & JVMTI_THREAD_STATE_ALIVE) { + strcat(str, " ALIVE"); + } + if (flags & JVMTI_THREAD_STATE_TERMINATED) { + strcat(str, " TERMINATED"); + } + if (flags & JVMTI_THREAD_STATE_RUNNABLE) { + strcat(str, " RUNNABLE"); + } + if (flags & JVMTI_THREAD_STATE_WAITING) { + strcat(str, " WAITING"); + } + if (flags & JVMTI_THREAD_STATE_WAITING_INDEFINITELY) { + strcat(str, " WAITING_INDEFINITELY"); + } + if (flags & JVMTI_THREAD_STATE_WAITING_WITH_TIMEOUT) { + strcat(str, " WAITING_WITH_TIMEOUT"); + } + if (flags & JVMTI_THREAD_STATE_SLEEPING) { + strcat(str, " SLEEPING"); + } + if (flags & JVMTI_THREAD_STATE_IN_OBJECT_WAIT) { + strcat(str, " IN_OBJECT_WAIT"); + } + if (flags & JVMTI_THREAD_STATE_PARKED) { + strcat(str, " PARKED"); + } + if (flags & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER) { + strcat(str, " BLOCKED_ON_MONITOR_ENTER"); + } + if (flags & JVMTI_THREAD_STATE_SUSPENDED) { + strcat(str, " SUSPENDED"); + } + if (flags & JVMTI_THREAD_STATE_INTERRUPTED) { + strcat(str, " INTERRUPTED"); + } + if (flags & JVMTI_THREAD_STATE_IN_NATIVE) { + strcat(str, " IN_NATIVE"); + } + + if (strlen(str) == 0) { + strcpy(str, ""); + } + + char* tstate = (char*)jvmtiAllocate((int)strlen(str) + 1); + strcpy(tstate, str); + + return tstate; +} + +char* +getThreadName(jthread thread) { + jvmtiThreadInfo thr_info; + jvmtiError err; + + memset(&thr_info, 0, sizeof(thr_info)); + err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) + (gdata->jvmti, thread, &thr_info); + if (err == JVMTI_ERROR_WRONG_PHASE || err == JVMTI_ERROR_THREAD_NOT_ALIVE) { + return NULL; // VM or target thread completed its work + } + check_jvmti_status(err, "getThreadName: error in JVMTI GetThreadInfo call"); + + char* tname = thr_info.name; + if (tname == NULL) { + const char* UNNAMED_STR = ""; + size_t UNNAMED_LEN = strlen(UNNAMED_STR); + tname = (char*)jvmtiAllocate((int)UNNAMED_LEN + 1); + strcpy(tname, UNNAMED_STR); + } + return tname; +} + +char* +getMethodName(jmethodID method) { + char* mname = NULL; + jvmtiError err; + + err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName) + (gdata->jvmti, method, &mname, NULL, NULL); + check_jvmti_status(err, "getMethodName: error in JVMTI GetMethodName call"); + + return mname; +} + +static char* +get_method_class_name(jmethodID method) { + jclass klass = NULL; + char* cname = NULL; + char* result = NULL; + jvmtiError err; + + err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass) + (gdata->jvmti, method, &klass); + check_jvmti_status(err, "get_method_class_name: error in JVMTI GetMethodDeclaringClass"); + + err = JVMTI_FUNC_PTR(gdata->jvmti,GetClassSignature) + (gdata->jvmti, klass, &cname, NULL); + check_jvmti_status(err, "get_method_class_name: error in JVMTI GetClassSignature"); + + size_t len = strlen(cname) - 2; // get rid of leading 'L' and trailing ';' + result = (char*)jvmtiAllocate((int)len + 1); + strncpy(result, cname + 1, len); // skip leading 'L' + result[len] = '\0'; + jvmtiDeallocate((void*)cname); + return result; +} + +static void +print_method(jmethodID method, jint depth) { + char* cname = NULL; + char* mname = NULL; + char* msign = NULL; + jvmtiError err; + + cname = get_method_class_name(method); + + err = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName) + (gdata->jvmti, method, &mname, &msign, NULL); + check_jvmti_status(err, "print_method: error in JVMTI GetMethodName"); + + tty_message("%2d: %s: %s%s", depth, cname, mname, msign); + jvmtiDeallocate((void*)cname); + jvmtiDeallocate((void*)mname); + jvmtiDeallocate((void*)msign); +} + +#define MAX_FRAME_COUNT_PRINT_STACK_TRACE 200 + +void +printStackTrace(jthread thread) { + jvmtiFrameInfo frames[MAX_FRAME_COUNT_PRINT_STACK_TRACE]; + char* tname = getThreadName(thread); + jint count = 0; + + jvmtiError err = JVMTI_FUNC_PTR(gdata->jvmti,GetStackTrace) + (gdata->jvmti, thread, 0, MAX_FRAME_COUNT_PRINT_STACK_TRACE, frames, &count); + check_jvmti_status(err, "printStackTrace: error in JVMTI GetStackTrace"); + + tty_message("JVMTI Stack Trace for thread %s: frame count: %d", tname, count); + for (int depth = 0; depth < count; depth++) { + print_method(frames[depth].method, depth); + } + jvmtiDeallocate((void*)tname); +} + +void +printThreadInfo(jthread thread) { + jvmtiThreadInfo thread_info; + jint thread_state; + jvmtiError err; + err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) + (gdata->jvmti, thread, &thread_info); + check_jvmti_status(err, "Error in GetThreadInfo"); + err = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadState) + (gdata->jvmti, thread, &thread_state); + check_jvmti_status(err, "Error in GetThreadState"); + const char* state = translateThreadState(thread_state); + tty_message("Thread: %p, name: %s, state(%x): %s, attrs: %s %s", + thread, thread_info.name, thread_state, state, + (isVThread(thread) ? "virtual": "platform"), + (thread_info.is_daemon ? "daemon": "")); +} + +#endif /* DEBUG*/ + /** * Return property value as JDWP allocated string in UTF8 encoding */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.h b/src/jdk.jdwp.agent/share/native/libjdwp/util.h index 75281813709e0..3d499d7d56985 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.h @@ -386,6 +386,15 @@ jvmtiError allNestedClasses(jclass clazz, jclass **ppnested, jint *pcount); void setAgentPropertyValue(JNIEnv *env, char *propertyName, char* propertyValue); +#ifdef DEBUG +// APIs that can be called when debugging the debug agent +char* translateThreadState(jint flags); +char* getThreadName(jthread thread); +char* getMethodName(jmethodID method); +void printStackTrace(jthread thread); +void printThreadInfo(jthread thread); +#endif + void *jvmtiAllocate(jint numBytes); void jvmtiDeallocate(void *buffer); From 85e0e6452d167db2fadd60543f875a6375339604 Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Fri, 4 Oct 2024 21:21:47 +0000 Subject: [PATCH 155/188] 8341443: [macos] AppContentTest and SigningOptionsTest failed due to "codesign" does not fails with "--app-content" on macOS 15 Reviewed-by: asemenyuk --- .../jpackage/macosx/SigningOptionsTest.java | 11 ++++++++++- .../tools/jpackage/share/AppContentTest.java | 19 +++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java index 9db836af99238..fee874da2e8bc 100644 --- a/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java @@ -91,8 +91,17 @@ public static Collection input() { new String[]{"--type"}, "Option [--mac-installer-sign-identity] is not valid with type"}, // --app-content and --type app-image + // JDK-8340802: "codesign" may or may not fail if additional + // content is specified based on macOS version. For example on + // macOS 15 aarch64 "codesign" will not fail with additional content. + // Since we only need to check that warning is displayed when + // "codesign" fails and "--app-content" is provided, lets fail + // "codesign" for some better reason like identity which does not + // exists. {"Hello", - new String[]{"--app-content", TEST_DUKE}, + new String[]{"--app-content", TEST_DUKE, + "--mac-sign", + "--mac-app-image-sign-identity", "test-identity"}, null, "\"codesign\" failed and additional application content" + " was supplied via the \"--app-content\" parameter."}, diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index b31a6e637b292..a343e20d8a748 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ import java.util.Collection; import java.util.List; +import jdk.internal.util.OSVersion; /** * Tests generation of packages with input folder containing empty folders. @@ -48,6 +49,7 @@ * @build jdk.jpackage.test.* * @build AppContentTest * @modules jdk.jpackage/jdk.jpackage.internal + * @modules java.base/jdk.internal.util * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=AppContentTest */ @@ -81,6 +83,17 @@ public AppContentTest(String... testPathArgs) { @Test public void test() throws Exception { + // On macOS signing may or may not work for modified app bundles. + // It works on macOS 15 and up, but fails on macOS below 15. + final int expectedJPackageExitCode; + final boolean isMacOS15 = (OSVersion.current().compareTo( + new OSVersion(15, 0, 0)) > 0); + if (testPathArgs.contains(TEST_BAD) || (TKit.isOSX() && !isMacOS15)) { + expectedJPackageExitCode = 1; + } else { + expectedJPackageExitCode = 0; + } + new PackageTest().configureHelloApp() .addInitializer(cmd -> { for (String arg : testPathArgs) { @@ -99,9 +112,7 @@ public void test() throws Exception { } }) - // On macOS we always signing app image and signing will fail, since - // test produces invalid app bundle. - .setExpectedExitCode(testPathArgs.contains(TEST_BAD) || TKit.isOSX() ? 1 : 0) + .setExpectedExitCode(expectedJPackageExitCode) .run(); } } From bade041db82a09cf33d4dbcc849f5784b3851f3d Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 4 Oct 2024 21:56:06 +0000 Subject: [PATCH 156/188] 8341554: Shenandoah: Missing heap lock when updating usage for soft ref policy Reviewed-by: kdnilsen, ysr --- .../share/gc/shenandoah/shenandoahControlThread.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 8a4ef63b8e38b..df2d6d092e630 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -177,10 +177,13 @@ void ShenandoahControlThread::run_service() { // it is a normal completion, or the abort. heap->free_set()->log_status_under_lock(); - // Notify Universe about new heap usage. This has implications for - // global soft refs policy, and we better report it every time heap - // usage goes down. - heap->update_capacity_and_used_at_gc(); + { + // Notify Universe about new heap usage. This has implications for + // global soft refs policy, and we better report it every time heap + // usage goes down. + ShenandoahHeapLocker locker(heap->lock()); + heap->update_capacity_and_used_at_gc(); + } // Signal that we have completed a visit to all live objects. heap->record_whole_heap_examined_timestamp(); From 559289487d97230760cff6f3349be4dc55c3a2ef Mon Sep 17 00:00:00 2001 From: Damon Nguyen Date: Fri, 4 Oct 2024 22:08:37 +0000 Subject: [PATCH 157/188] 8340417: Open source some MenuBar tests - Set1 Reviewed-by: psadhukhan --- test/jdk/java/awt/MenuBar/CellsResize.java | 159 ++++++++++++++++++ .../MenuBarRemoveMenuTest.java | 93 ++++++++++ .../jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java | 63 +++++++ .../SetMBarWhenHidden/SetMBarWhenHidden.java | 92 ++++++++++ 4 files changed, 407 insertions(+) create mode 100644 test/jdk/java/awt/MenuBar/CellsResize.java create mode 100644 test/jdk/java/awt/MenuBar/MenuBarRemoveMenu/MenuBarRemoveMenuTest.java create mode 100644 test/jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java create mode 100644 test/jdk/java/awt/MenuBar/SetMBarWhenHidden/SetMBarWhenHidden.java diff --git a/test/jdk/java/awt/MenuBar/CellsResize.java b/test/jdk/java/awt/MenuBar/CellsResize.java new file mode 100644 index 0000000000000..64777095fa8d5 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/CellsResize.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 6502052 + * @summary Menu cells must resize if font changes (XToolkit) + * @requires os.family == "linux" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CellsResize + */ + +import java.awt.Button; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuComponent; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.Toolkit; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class CellsResize { + private static Frame frame; + private static MenuBar menuBar; + private static PopupMenu popupMenu; + private static Menu barSubMenu; + private static Menu popupSubMenu; + private static boolean fontMultiplied = false; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Open all nested menus in menu bar. + 2. Click on "popup-menu" button to show popup-menus. + 3. Open all nested menus in popup-menu. + 4. Click on "big-font" button (to make all menus have a + bigger font). + 5. Open all nested menus again (as described in 1, 2, 3). + 6. If all menu items use a bigger font now and their labels fit + into menu-item size, press "pass", otherwise press "fail". + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(CellsResize::createUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + public static Frame createUI () { + if (!checkToolkit()) { + new RuntimeException("Toolkit check failed."); + } + frame = new Frame("MenuBar Cell Resize Test"); + + popupMenu = new PopupMenu(); + popupMenu.add(createMenu(false)); + + frame.add(popupMenu); + + menuBar = new MenuBar(); + menuBar.add(createMenu(true)); + + frame.setMenuBar(menuBar); + + Button bp = new Button("popup-menu"); + bp.addMouseListener(new MouseAdapter() { + public void mouseReleased(MouseEvent e) { + popupMenu.show(e.getComponent(), e.getX(), e.getY()); + } + }); + + Button bf = new Button("big-font"); + bf.addMouseListener(new MouseAdapter() { + public void mouseReleased(MouseEvent e) { + bigFont(); + } + }); + + Panel panel = new Panel(); + panel.setLayout(new GridLayout(2, 1)); + panel.add(bp); + panel.add(bf); + + frame.add(panel); + frame.setSize(300, 300); + return frame; + } + + static boolean checkToolkit() { + String toolkitName = Toolkit.getDefaultToolkit().getClass().getName(); + return toolkitName.equals("sun.awt.X11.XToolkit"); + } + + static Menu createMenu(boolean bar) { + Menu menu1 = new Menu("Menu-1"); + Menu menu11 = new Menu("Menu-11"); + menu1.add(menu11); + if (bar) { + barSubMenu = menu11; + } else { + popupSubMenu = menu11; + } + menu11.add(new MenuItem("MenuItem")); + return menu1; + } + + static void bigFont() { + if (fontMultiplied) { + return; + } else { + fontMultiplied = true; + } + + multiplyFont(barSubMenu, 7); + multiplyFont(popupSubMenu, 7); + + // NOTE: if previous two are moved below following + // two, they get their font multiplied twice. + + multiplyFont(menuBar, 5); + multiplyFont(popupMenu, 5); + } + + static void multiplyFont(MenuComponent comp, int times) { + Font font = comp.getFont(); + float size = font.getSize() * times; + comp.setFont(font.deriveFont(size)); + } +} diff --git a/test/jdk/java/awt/MenuBar/MenuBarRemoveMenu/MenuBarRemoveMenuTest.java b/test/jdk/java/awt/MenuBar/MenuBarRemoveMenu/MenuBarRemoveMenuTest.java new file mode 100644 index 0000000000000..098065d1361f6 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/MenuBarRemoveMenu/MenuBarRemoveMenuTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4275848 + * @summary Tests that MenuBar is painted correctly after its submenu is removed + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarRemoveMenuTest + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public class MenuBarRemoveMenuTest implements ActionListener { + private static MenuBar menubar; + private static Button removeButton; + private static Button addButton; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Press "Remove menu" button. If you see that both menus + disappeared, the test failed. Otherwise try to add and remove + menu several times to verify that the test passed. Every time + you press "Remove menu" button only one menu should go away. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MenuBarRemoveMenuTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame(); + menubar = new MenuBar(); + removeButton = new Button("Remove menu"); + addButton = new Button("Add menu"); + removeButton.addActionListener(new MenuBarRemoveMenuTest()); + addButton.addActionListener(new MenuBarRemoveMenuTest()); + addButton.setEnabled(false); + menubar.add(new Menu("menu")); + menubar.add(new Menu("menu")); + frame.setMenuBar(menubar); + frame.setLayout(new GridLayout(1, 2)); + frame.add(removeButton); + frame.add(addButton); + frame.pack(); + return frame; + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == removeButton) { + menubar.remove(0); + removeButton.setEnabled(false); + addButton.setEnabled(true); + } else { + menubar.add(new Menu("menu")); + removeButton.setEnabled(true); + addButton.setEnabled(false); + } + } +} diff --git a/test/jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java b/test/jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java new file mode 100644 index 0000000000000..a7a3a3480118e --- /dev/null +++ b/test/jdk/java/awt/MenuBar/MenuNPE/MenuNPE.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 5005194 + * @summary Frame.remove(getMenuBar()) throws NPE if the frame doesn't + * have a menu bar + * @key headful + * @run main MenuNPE + */ + +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +public class MenuNPE { + private static Frame frame; + public static void main(String[] args) throws Exception { + try { + frame = new Frame("Menu NPE"); + MenuBar menuBar = new MenuBar(); + Menu menu1 = new Menu("Menu 01"); + MenuItem menuLabel = new MenuItem("Item 01"); + menu1.add(menuLabel); + menuBar.add(menu1); + frame.setMenuBar(menuBar); + frame.setSize(200, 200); + frame.setVisible(true); + frame.validate(); + frame.remove(frame.getMenuBar()); + frame.remove(frame.getMenuBar()); + System.out.println("Test passed."); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (frame != null) { + frame.dispose(); + } + } + } +} diff --git a/test/jdk/java/awt/MenuBar/SetMBarWhenHidden/SetMBarWhenHidden.java b/test/jdk/java/awt/MenuBar/SetMBarWhenHidden/SetMBarWhenHidden.java new file mode 100644 index 0000000000000..67eefe4894248 --- /dev/null +++ b/test/jdk/java/awt/MenuBar/SetMBarWhenHidden/SetMBarWhenHidden.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4105881 + * @summary Sets the menu bar while frame window is hidden, then shows + frame again + * @key headful + * @run main SetMBarWhenHidden + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Rectangle; + +// test case for 4105881: FRAME.SETSIZE() DOESN'T WORK FOR SOME SOLARIS WITH +// JDK115+CASES ON +public class SetMBarWhenHidden { + private static Frame f; + private static Rectangle startBounds; + private static Rectangle endBounds; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(() -> { + f = new Frame("Set MenuBar When Hidden Test"); + Menu file; + Menu edit; + MenuBar menubar = new MenuBar(); + file = new Menu("File"); + menubar.add(file); + edit = new Menu("Edit"); + menubar.add(edit); + edit.setEnabled(false); + f.setMenuBar(menubar); + f.setSize(200, 200); + startBounds = f.getBounds(); + System.out.println("About to call setVisible(false)"); + f.setVisible(false); + System.out.println("About to call setSize(500, 500)"); + f.setSize(500, 500); + // create a new menubar and add + MenuBar menubar1 = new MenuBar(); + menubar1.add(file); + menubar1.add(edit); + System.out.println("About to call setMenuBar"); + f.setMenuBar(menubar1); + System.out.println("About to call setVisible(true)"); + f.setVisible(true); + endBounds = f.getBounds(); + }); + if (startBounds.getHeight() > endBounds.getHeight() && + startBounds.getWidth() > endBounds.getWidth()) { + throw new RuntimeException("Test failed. Frame size didn't " + + "change.\nStart: " + startBounds + "\n" + + "End: " + endBounds); + } else { + System.out.println("Test passed.\nStart: " + startBounds + + "\nEnd: " + endBounds); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} From b42fbf43dfd62ae64973ff0e406b6609cd8e1aa6 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 4 Oct 2024 22:35:03 +0000 Subject: [PATCH 158/188] 8339699: Optimize DataOutputStream writeUTF Reviewed-by: liach, bpb --- .../classes/java/io/DataOutputStream.java | 42 ++-- .../classes/java/io/ObjectOutputStream.java | 202 ++++++------------ .../classfile/impl/BufWriterImpl.java | 28 +-- .../jdk/internal/util/ModifiedUtf.java | 71 ++++++ .../bench/java/io/DataOutputStreamBench.java | 91 ++++++++ 5 files changed, 252 insertions(+), 182 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java create mode 100644 test/micro/org/openjdk/bench/java/io/DataOutputStreamBench.java diff --git a/src/java.base/share/classes/java/io/DataOutputStream.java b/src/java.base/share/classes/java/io/DataOutputStream.java index d16ae73f913bf..4b22d65bd39fa 100644 --- a/src/java.base/share/classes/java/io/DataOutputStream.java +++ b/src/java.base/share/classes/java/io/DataOutputStream.java @@ -1,5 +1,6 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -25,8 +26,13 @@ package java.io; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.util.ByteArray; +import static jdk.internal.util.ModifiedUtf.putChar; +import static jdk.internal.util.ModifiedUtf.utfLen; + /** * A data output stream lets an application write primitive Java data * types to an output stream in a portable way. An application can @@ -44,6 +50,8 @@ * @since 1.0 */ public class DataOutputStream extends FilterOutputStream implements DataOutput { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + /** * The number of bytes written to the data output stream so far. * If this counter overflows, it will be wrapped to Integer.MAX_VALUE. @@ -352,15 +360,11 @@ public final void writeUTF(String str) throws IOException { * {@code str} would exceed 65535 bytes in length * @throws IOException if some other I/O error occurs. */ + @SuppressWarnings("deprecation") static int writeUTF(String str, DataOutput out) throws IOException { final int strlen = str.length(); - int utflen = strlen; // optimized for ASCII - - for (int i = 0; i < strlen; i++) { - int c = str.charAt(i); - if (c >= 0x80 || c == 0) - utflen += (c >= 0x800) ? 2 : 1; - } + int countNonZeroAscii = JLA.countNonZeroAscii(str); + int utflen = utfLen(str, countNonZeroAscii); if (utflen > 65535 || /* overflow */ utflen < strlen) throw new UTFDataFormatException(tooLongMsg(str, utflen)); @@ -377,25 +381,11 @@ static int writeUTF(String str, DataOutput out) throws IOException { int count = 0; ByteArray.setUnsignedShort(bytearr, count, utflen); count += 2; - int i = 0; - for (i = 0; i < strlen; i++) { // optimized for initial run of ASCII - int c = str.charAt(i); - if (c >= 0x80 || c == 0) break; - bytearr[count++] = (byte) c; - } + str.getBytes(0, countNonZeroAscii, bytearr, count); + count += countNonZeroAscii; - for (; i < strlen; i++) { - int c = str.charAt(i); - if (c < 0x80 && c != 0) { - bytearr[count++] = (byte) c; - } else if (c >= 0x800) { - bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F)); - bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F)); - bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F)); - } else { - bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F)); - bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F)); - } + for (int i = countNonZeroAscii; i < strlen;) { + count = putChar(bytearr, count, str.charAt(i++)); } out.write(bytearr, 0, utflen + 2); return utflen + 2; diff --git a/src/java.base/share/classes/java/io/ObjectOutputStream.java b/src/java.base/share/classes/java/io/ObjectOutputStream.java index 3650b10135356..bde069a1774d1 100644 --- a/src/java.base/share/classes/java/io/ObjectOutputStream.java +++ b/src/java.base/share/classes/java/io/ObjectOutputStream.java @@ -1,5 +1,6 @@ /* * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -34,8 +35,13 @@ import java.util.StringJoiner; import jdk.internal.util.ByteArray; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import sun.reflect.misc.ReflectUtil; +import static jdk.internal.util.ModifiedUtf.putChar; +import static jdk.internal.util.ModifiedUtf.utfLen; + /** * An ObjectOutputStream writes primitive data types and graphs of Java objects * to an OutputStream. The objects can be read (reconstituted) using an @@ -169,6 +175,7 @@ public class ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private static class Caches { /** cache of subclass security audit results */ @@ -885,7 +892,7 @@ public void writeChars(String str) throws IOException { * stream */ public void writeUTF(String str) throws IOException { - bout.writeUTF(str); + bout.writeUTFInternal(str, false); } /** @@ -1317,14 +1324,7 @@ private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared) */ private void writeString(String str, boolean unshared) throws IOException { handles.assign(unshared ? null : str); - long utflen = bout.getUTFLength(str); - if (utflen <= 0xFFFF) { - bout.writeByte(TC_STRING); - bout.writeUTF(str, utflen); - } else { - bout.writeByte(TC_LONGSTRING); - bout.writeLongUTF(str, utflen); - } + bout.writeUTFInternal(str, true); } /** @@ -1994,26 +1994,27 @@ public void writeDouble(double v) throws IOException { } } - public void writeBytes(String s) throws IOException { - int endoff = s.length(); - int cpos = 0; - int csize = 0; - for (int off = 0; off < endoff; ) { - if (cpos >= csize) { - cpos = 0; - csize = Math.min(endoff - off, CHAR_BUF_SIZE); - s.getChars(off, off + csize, cbuf, 0); - } - if (pos >= MAX_BLOCK_SIZE) { + @SuppressWarnings("deprecation") + void writeBytes(String s, int len) throws IOException { + int pos = this.pos; + for (int strpos = 0; strpos < len;) { + int rem = MAX_BLOCK_SIZE - pos; + int csize = Math.min(len - strpos, rem); + s.getBytes(strpos, strpos + csize, buf, pos); + pos += csize; + strpos += csize; + + if (pos == MAX_BLOCK_SIZE) { + this.pos = pos; drain(); + pos = 0; } - int n = Math.min(csize - cpos, MAX_BLOCK_SIZE - pos); - int stop = pos + n; - while (pos < stop) { - buf[pos++] = (byte) cbuf[cpos++]; - } - off += n; } + this.pos = pos; + } + + public void writeBytes(String s) throws IOException { + writeBytes(s, s.length()); } public void writeChars(String s) throws IOException { @@ -2026,8 +2027,47 @@ public void writeChars(String s) throws IOException { } } - public void writeUTF(String s) throws IOException { - writeUTF(s, getUTFLength(s)); + public void writeUTF(String str) throws IOException { + writeUTFInternal(str, false); + } + + private void writeUTFInternal(String str, boolean writeHeader) throws IOException { + int strlen = str.length(); + int countNonZeroAscii = JLA.countNonZeroAscii(str); + int utflen = utfLen(str, countNonZeroAscii); + if (utflen <= 0xFFFF) { + if(writeHeader) { + writeByte(TC_STRING); + } + writeShort(utflen); + } else { + if(writeHeader) { + writeByte(TC_LONGSTRING); + } + writeLong(utflen); + } + + if (countNonZeroAscii != 0) { + writeBytes(str, countNonZeroAscii); + } + if (countNonZeroAscii != strlen) { + writeMoreUTF(str, countNonZeroAscii); + } + } + + private void writeMoreUTF(String str, int stroff) throws IOException { + int pos = this.pos; + for (int strlen = str.length(); stroff < strlen;) { + char c = str.charAt(stroff++); + int csize = c != 0 && c < 0x80 ? 1 : c >= 0x800 ? 3 : 2; + if (pos + csize >= MAX_BLOCK_SIZE) { + this.pos = pos; + drain(); + pos = 0; + } + pos = putChar(buf, pos, c); + } + this.pos = pos; } @@ -2153,112 +2193,6 @@ void writeDoubles(double[] v, int off, int len) throws IOException { } } } - - /** - * Returns the length in bytes of the UTF encoding of the given string. - */ - long getUTFLength(String s) { - int len = s.length(); - long utflen = 0; - for (int off = 0; off < len; ) { - int csize = Math.min(len - off, CHAR_BUF_SIZE); - s.getChars(off, off + csize, cbuf, 0); - for (int cpos = 0; cpos < csize; cpos++) { - char c = cbuf[cpos]; - if (c >= 0x0001 && c <= 0x007F) { - utflen++; - } else if (c > 0x07FF) { - utflen += 3; - } else { - utflen += 2; - } - } - off += csize; - } - return utflen; - } - - /** - * Writes the given string in UTF format. This method is used in - * situations where the UTF encoding length of the string is already - * known; specifying it explicitly avoids a prescan of the string to - * determine its UTF length. - */ - void writeUTF(String s, long utflen) throws IOException { - if (utflen > 0xFFFFL) { - throw new UTFDataFormatException(); - } - writeShort((int) utflen); - if (utflen == (long) s.length()) { - writeBytes(s); - } else { - writeUTFBody(s); - } - } - - /** - * Writes given string in "long" UTF format. "Long" UTF format is - * identical to standard UTF, except that it uses an 8 byte header - * (instead of the standard 2 bytes) to convey the UTF encoding length. - */ - void writeLongUTF(String s) throws IOException { - writeLongUTF(s, getUTFLength(s)); - } - - /** - * Writes given string in "long" UTF format, where the UTF encoding - * length of the string is already known. - */ - void writeLongUTF(String s, long utflen) throws IOException { - writeLong(utflen); - if (utflen == (long) s.length()) { - writeBytes(s); - } else { - writeUTFBody(s); - } - } - - /** - * Writes the "body" (i.e., the UTF representation minus the 2-byte or - * 8-byte length header) of the UTF encoding for the given string. - */ - private void writeUTFBody(String s) throws IOException { - int limit = MAX_BLOCK_SIZE - 3; - int len = s.length(); - for (int off = 0; off < len; ) { - int csize = Math.min(len - off, CHAR_BUF_SIZE); - s.getChars(off, off + csize, cbuf, 0); - for (int cpos = 0; cpos < csize; cpos++) { - char c = cbuf[cpos]; - if (pos <= limit) { - if (c <= 0x007F && c != 0) { - buf[pos++] = (byte) c; - } else if (c > 0x07FF) { - buf[pos + 2] = (byte) (0x80 | ((c >> 0) & 0x3F)); - buf[pos + 1] = (byte) (0x80 | ((c >> 6) & 0x3F)); - buf[pos + 0] = (byte) (0xE0 | ((c >> 12) & 0x0F)); - pos += 3; - } else { - buf[pos + 1] = (byte) (0x80 | ((c >> 0) & 0x3F)); - buf[pos + 0] = (byte) (0xC0 | ((c >> 6) & 0x1F)); - pos += 2; - } - } else { // write one byte at a time to normalize block - if (c <= 0x007F && c != 0) { - write(c); - } else if (c > 0x07FF) { - write(0xE0 | ((c >> 12) & 0x0F)); - write(0x80 | ((c >> 6) & 0x3F)); - write(0x80 | ((c >> 0) & 0x3F)); - } else { - write(0xC0 | ((c >> 6) & 0x1F)); - write(0x80 | ((c >> 0) & 0x3F)); - } - } - } - off += csize; - } - } } /** diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java index 4cc6c205fe4ff..1a7c9a36c44a6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java @@ -38,6 +38,9 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.vm.annotation.ForceInline; +import static jdk.internal.util.ModifiedUtf.putChar; +import static jdk.internal.util.ModifiedUtf.utfLen; + public final class BufWriterImpl implements BufWriter { private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); @@ -162,14 +165,7 @@ public void writeBytes(BufWriterImpl other) { void writeUTF(String str) { int strlen = str.length(); int countNonZeroAscii = JLA.countNonZeroAscii(str); - int utflen = strlen; - if (countNonZeroAscii != strlen) { - for (int i = countNonZeroAscii; i < strlen; i++) { - int c = str.charAt(i); - if (c >= 0x80 || c == 0) - utflen += (c >= 0x800) ? 2 : 1; - } - } + int utflen = utfLen(str, countNonZeroAscii); if (utflen > 65535) { throw new IllegalArgumentException("string too long"); } @@ -185,20 +181,8 @@ void writeUTF(String str) { str.getBytes(0, countNonZeroAscii, elems, offset); offset += countNonZeroAscii; - for (int i = countNonZeroAscii; i < strlen; ++i) { - char c = str.charAt(i); - if (c >= '\001' && c <= '\177') { - elems[offset++] = (byte) c; - } else if (c > '\u07FF') { - elems[offset ] = (byte) (0xE0 | c >> 12 & 0xF); - elems[offset + 1] = (byte) (0x80 | c >> 6 & 0x3F); - elems[offset + 2] = (byte) (0x80 | c & 0x3F); - offset += 3; - } else { - elems[offset ] = (byte) (0xC0 | c >> 6 & 0x1F); - elems[offset + 1] = (byte) (0x80 | c & 0x3F); - offset += 2; - } + for (int i = countNonZeroAscii; i < strlen; i++) { + offset = putChar(elems, offset, str.charAt(i)); } this.offset = offset; diff --git a/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java b/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java new file mode 100644 index 0000000000000..a8d2fe8bb74b4 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/util/ModifiedUtf.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.util; + +import jdk.internal.vm.annotation.ForceInline; + +/** + * Helper to JDK UTF putChar and Calculate length + * + * @since 24 + */ +public abstract class ModifiedUtf { + private ModifiedUtf() { + } + + @ForceInline + public static int putChar(byte[] buf, int offset, char c) { + if (c != 0 && c < 0x80) { + buf[offset++] = (byte) c; + } else if (c >= 0x800) { + buf[offset ] = (byte) (0xE0 | c >> 12 & 0x0F); + buf[offset + 1] = (byte) (0x80 | c >> 6 & 0x3F); + buf[offset + 2] = (byte) (0x80 | c & 0x3F); + offset += 3; + } else { + buf[offset ] = (byte) (0xC0 | c >> 6 & 0x1F); + buf[offset + 1] = (byte) (0x80 | c & 0x3F); + offset += 2; + } + return offset; + } + + /** + * Calculate the utf length of a string + * @param str input string + * @param countNonZeroAscii the number of non-zero ascii characters in the prefix calculated by JLA.countNonZeroAscii(str) + */ + @ForceInline + public static int utfLen(String str, int countNonZeroAscii) { + int utflen = str.length(); + for (int i = utflen - 1; i >= countNonZeroAscii; i--) { + int c = str.charAt(i); + if (c >= 0x80 || c == 0) + utflen += (c >= 0x800) ? 2 : 1; + } + return utflen; + } +} diff --git a/test/micro/org/openjdk/bench/java/io/DataOutputStreamBench.java b/test/micro/org/openjdk/bench/java/io/DataOutputStreamBench.java new file mode 100644 index 0000000000000..34568110dde53 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/io/DataOutputStreamBench.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024, 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.java.io; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.HexFormat; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Fork(2) +@Measurement(iterations = 6, time = 1) +@Warmup(iterations = 4, time = 2) +@State(Scope.Thread) +public class DataOutputStreamBench { + + @Param({"ascii", "utf8_2_bytes", "utf8_3_bytes", "emoji"}) + public String charType; + + ByteArrayOutputStream bytesOutput; + DataOutputStream dataOutput; + ObjectOutputStream objectOutput; + String[] strings; + + @Setup(Level.Trial) + public void setup() throws Exception { + byte[] bytes = HexFormat.of().parseHex( + switch (charType) { + case "ascii" -> "78"; + case "utf8_2_bytes" -> "c2a9"; + case "utf8_3_bytes" -> "e6b8a9"; + case "emoji" -> "e29da3efb88f"; + default -> throw new IllegalArgumentException("bad charType: " + charType); + } + ); + String s = new String(bytes, 0, bytes.length, StandardCharsets.UTF_8); + strings = new String[128]; + for (int i = 0; i < strings.length; i++) { + strings[i] = "A".repeat(i).concat(s.repeat(i)); + } + + bytesOutput = new ByteArrayOutputStream(1024 * 64); + dataOutput = new DataOutputStream(bytesOutput); + objectOutput = new ObjectOutputStream(bytesOutput); + } + + @Benchmark + public void dataOutwriteUTF(Blackhole bh) throws Exception { + bytesOutput.reset(); + for (var s : strings) { + dataOutput.writeUTF(s); + } + dataOutput.flush(); + bh.consume(bytesOutput.size()); + } + + @Benchmark + public void objectWriteUTF(Blackhole bh) throws Exception { + bytesOutput.reset(); + for (var s : strings) { + objectOutput.writeUTF(s); + } + objectOutput.flush(); + bh.consume(bytesOutput.size()); + } +} From f8db3a831b61bb585c5494a7a8657e37000892b4 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 5 Oct 2024 01:21:25 +0000 Subject: [PATCH 159/188] 8341510: Optimize StackMapGenerator::processFieldInstructions Reviewed-by: liach --- .../classfile/constantpool/ConstantDynamicEntry.java | 2 +- .../lang/classfile/constantpool/FieldRefEntry.java | 2 +- .../internal/classfile/impl/StackMapGenerator.java | 12 +++++------- .../classes/jdk/internal/classfile/impl/Util.java | 4 ---- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java index 144c8a539d72c..507ff906274cb 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantDynamicEntry.java @@ -50,7 +50,7 @@ public sealed interface ConstantDynamicEntry * {@return a symbolic descriptor for the dynamic constant's type} */ default ClassDesc typeSymbol() { - return Util.fieldTypeSymbol(nameAndType()); + return Util.fieldTypeSymbol(type()); } @Override diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java index 628abdac6fe43..75533770b3524 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/FieldRefEntry.java @@ -44,6 +44,6 @@ public sealed interface FieldRefEntry extends MemberRefEntry * {@return a symbolic descriptor for the field's type} */ default ClassDesc typeSymbol() { - return Util.fieldTypeSymbol(nameAndType()); + return Util.fieldTypeSymbol(type()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 0eae3c357196a..7c4871fb12afe 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -756,22 +756,20 @@ private void processSwitch(RawBytecodeHelper bcs) { } private void processFieldInstructions(RawBytecodeHelper bcs) { - var desc = Util.fieldTypeSymbol(cp.entryByIndex(bcs.getIndexU2(), MemberRefEntry.class).nameAndType()); + var desc = Util.fieldTypeSymbol(cp.entryByIndex(bcs.getIndexU2(), MemberRefEntry.class).type()); + var currentFrame = this.currentFrame; switch (bcs.opcode()) { case GETSTATIC -> currentFrame.pushStack(desc); case PUTSTATIC -> { - currentFrame.popStack(); - if (Util.isDoubleSlot(desc)) currentFrame.popStack(); + currentFrame.decStack(Util.isDoubleSlot(desc) ? 2 : 1); } case GETFIELD -> { - currentFrame.popStack(); + currentFrame.decStack(1); currentFrame.pushStack(desc); } case PUTFIELD -> { - currentFrame.popStack(); - currentFrame.popStack(); - if (Util.isDoubleSlot(desc)) currentFrame.popStack(); + currentFrame.decStack(Util.isDoubleSlot(desc) ? 3 : 2); } default -> throw new AssertionError("Should not reach here"); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index e1e3f6fb3d2b4..0b9d4950cbda7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -231,10 +231,6 @@ public static MethodTypeDesc methodTypeSymbol(Utf8Entry utf8) { return ((AbstractPoolEntry.Utf8EntryImpl) utf8).methodTypeSymbol(); } - public static ClassDesc fieldTypeSymbol(NameAndTypeEntry nat) { - return fieldTypeSymbol(nat.type()); - } - public static MethodTypeDesc methodTypeSymbol(NameAndTypeEntry nat) { return methodTypeSymbol(nat.type()); } From 1c3e56c3e45be3626afec0461d4ae8059b0b577f Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 5 Oct 2024 15:37:18 +0000 Subject: [PATCH 160/188] 8341512: Optimize StackMapGenerator::processInvokeInstructions Reviewed-by: liach --- .../attribute/EnclosingMethodAttribute.java | 2 +- .../constantpool/InterfaceMethodRefEntry.java | 2 +- .../classfile/constantpool/InvokeDynamicEntry.java | 2 +- .../lang/classfile/constantpool/MethodRefEntry.java | 2 +- .../classfile/instruction/InvokeInstruction.java | 2 +- .../internal/classfile/impl/AbstractInstruction.java | 2 +- .../internal/classfile/impl/DirectCodeBuilder.java | 2 +- .../jdk/internal/classfile/impl/StackCounter.java | 2 +- .../internal/classfile/impl/StackMapGenerator.java | 12 +++++------- .../classes/jdk/internal/classfile/impl/Util.java | 4 ---- 10 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java b/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java index 768019fa1d301..2c91900850120 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/EnclosingMethodAttribute.java @@ -92,7 +92,7 @@ default Optional enclosingMethodType() { * immediately enclosed by a method or constructor} */ default Optional enclosingMethodTypeSymbol() { - return enclosingMethod().map(Util::methodTypeSymbol); + return enclosingMethodType().map(Util::methodTypeSymbol); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java index 43faa488bb915..b97defdc1e148 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/InterfaceMethodRefEntry.java @@ -45,6 +45,6 @@ public sealed interface InterfaceMethodRefEntry * {@return a symbolic descriptor for the interface method's type} */ default MethodTypeDesc typeSymbol() { - return Util.methodTypeSymbol(nameAndType()); + return Util.methodTypeSymbol(type()); } } diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/InvokeDynamicEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/InvokeDynamicEntry.java index d9a1c29997299..f06c3d4c7828c 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/InvokeDynamicEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/InvokeDynamicEntry.java @@ -47,7 +47,7 @@ public sealed interface InvokeDynamicEntry * {@return a symbolic descriptor for the call site's invocation type} */ default MethodTypeDesc typeSymbol() { - return Util.methodTypeSymbol(nameAndType()); + return Util.methodTypeSymbol(type()); } /** diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java index 39684db462134..3ff8dfdc0f462 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/MethodRefEntry.java @@ -44,6 +44,6 @@ public sealed interface MethodRefEntry extends MemberRefEntry * {@return a symbolic descriptor for the method's type} */ default MethodTypeDesc typeSymbol() { - return Util.methodTypeSymbol(nameAndType()); + return Util.methodTypeSymbol(type()); } } diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java index ff68abce3d21e..74b8dc942a271 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/InvokeInstruction.java @@ -94,7 +94,7 @@ default Utf8Entry type() { * {@return a symbolic descriptor for the method type} */ default MethodTypeDesc typeSymbol() { - return Util.methodTypeSymbol(method().nameAndType()); + return Util.methodTypeSymbol(method().type()); } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index d325842793705..b5d6ea240593e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java @@ -1061,7 +1061,7 @@ public boolean isInterface() { @Override public int count() { return op == Opcode.INVOKEINTERFACE - ? Util.parameterSlots(Util.methodTypeSymbol(methodEntry.nameAndType())) + 1 + ? Util.parameterSlots(Util.methodTypeSymbol(methodEntry.type())) + 1 : 0; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index ee312a97dad80..b986efde1a512 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -809,7 +809,7 @@ public CodeBuilder loadLocal(TypeKind tk, int slot) { @Override public CodeBuilder invoke(Opcode opcode, MemberRefEntry ref) { if (opcode == INVOKEINTERFACE) { - int slots = Util.parameterSlots(Util.methodTypeSymbol(ref.nameAndType())) + 1; + int slots = Util.parameterSlots(Util.methodTypeSymbol(ref.type())) + 1; writeInvokeInterface(opcode, (InterfaceMethodRefEntry) ref, slots); } else { writeInvokeNormal(opcode, ref); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java index 49a06b3acc6e7..843528df84bb0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java @@ -326,7 +326,7 @@ public StackCounter(LabelContext labelContext, case INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE, INVOKEDYNAMIC -> { var cpe = cp.entryByIndex(bcs.getIndexU2()); var nameAndType = opcode == INVOKEDYNAMIC ? ((DynamicConstantPoolEntry)cpe).nameAndType() : ((MemberRefEntry)cpe).nameAndType(); - var mtd = Util.methodTypeSymbol(nameAndType); + var mtd = Util.methodTypeSymbol(nameAndType.type()); var delta = Util.slotSize(mtd.returnType()) - Util.parameterSlots(mtd); if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) { delta--; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index 7c4871fb12afe..2f31615a4e00e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -781,12 +781,12 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl var nameAndType = opcode == INVOKEDYNAMIC ? cp.entryByIndex(index, InvokeDynamicEntry.class).nameAndType() : cp.entryByIndex(index, MemberRefEntry.class).nameAndType(); - String invokeMethodName = nameAndType.name().stringValue(); - var mDesc = Util.methodTypeSymbol(nameAndType); + var mDesc = Util.methodTypeSymbol(nameAndType.type()); int bci = bcs.bci(); + var currentFrame = this.currentFrame; currentFrame.decStack(Util.parameterSlots(mDesc)); if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) { - if (OBJECT_INITIALIZER_NAME.equals(invokeMethodName)) { + if (nameAndType.name().equalsString(OBJECT_INITIALIZER_NAME)) { Type type = currentFrame.popStack(); if (type == Type.UNITIALIZED_THIS_TYPE) { if (inTryBlock) { @@ -795,9 +795,7 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl currentFrame.initializeObject(type, thisType); thisUninit = true; } else if (type.tag == ITEM_UNINITIALIZED) { - int new_offset = type.bci; - int new_class_index = bcs.getU2(new_offset + 1); - Type new_class_type = cpIndexToType(new_class_index, cp); + Type new_class_type = cpIndexToType(bcs.getU2(type.bci + 1), cp); if (inTryBlock) { processExceptionHandlerTargets(bci, thisUninit); } @@ -806,7 +804,7 @@ private boolean processInvokeInstructions(RawBytecodeHelper bcs, boolean inTryBl throw generatorError("Bad operand type when invoking "); } } else { - currentFrame.popStack(); + currentFrame.decStack(1); } } currentFrame.pushStack(mDesc.returnType()); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 0b9d4950cbda7..84786164d578e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -231,10 +231,6 @@ public static MethodTypeDesc methodTypeSymbol(Utf8Entry utf8) { return ((AbstractPoolEntry.Utf8EntryImpl) utf8).methodTypeSymbol(); } - public static MethodTypeDesc methodTypeSymbol(NameAndTypeEntry nat) { - return methodTypeSymbol(nat.type()); - } - @SuppressWarnings("unchecked") private static > void writeAttribute(BufWriterImpl writer, Attribute attr) { if (attr instanceof CustomAttribute ca) { From df763cd2c27070d96a40c9ec00f921107767edb9 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Sat, 5 Oct 2024 18:34:31 +0000 Subject: [PATCH 161/188] 8341558: [AIX] build broken after 8341413 Reviewed-by: kbarrett --- src/hotspot/os/aix/osThread_aix.cpp | 1 - src/hotspot/os/aix/osThread_aix.hpp | 7 ------- 2 files changed, 8 deletions(-) diff --git a/src/hotspot/os/aix/osThread_aix.cpp b/src/hotspot/os/aix/osThread_aix.cpp index b9c5f16a62251..ab08a766156fe 100644 --- a/src/hotspot/os/aix/osThread_aix.cpp +++ b/src/hotspot/os/aix/osThread_aix.cpp @@ -40,7 +40,6 @@ OSThread::OSThread() _ucontext(nullptr), _expanding_stack(0), _alt_sig_stack(nullptr), - _last_cpu_times(), _startThread_lock(new Monitor(Mutex::event, "startThread_lock")) { sigemptyset(&_caller_sigmask); } diff --git a/src/hotspot/os/aix/osThread_aix.hpp b/src/hotspot/os/aix/osThread_aix.hpp index acbe1d37684cf..8f3799d070142 100644 --- a/src/hotspot/os/aix/osThread_aix.hpp +++ b/src/hotspot/os/aix/osThread_aix.hpp @@ -131,13 +131,6 @@ class OSThread : public OSThreadBase { return _startThread_lock; } - // The last measured values of cpu timing to prevent the "stale - // value return" bug in thread_cpu_time. - volatile struct { - jlong sys; - jlong user; - } _last_cpu_times; - // Printing uintx thread_id_for_printing() const override { return (uintx)_thread_id; From 9a25f822fb2529c1cae3ae909761381789d7b7b1 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Sat, 5 Oct 2024 18:42:37 +0000 Subject: [PATCH 162/188] 8339386: Assertion on AIX - original PC must be in the main code section of the compiled method Reviewed-by: rrich, lucy --- src/hotspot/cpu/ppc/frame_ppc.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index 4c1ffeb0d768e..eb16af5e9db1b 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -117,9 +117,9 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - common_abi* sender_abi = (common_abi*) fp; + volatile common_abi* sender_abi = (common_abi*) fp; // May get updated concurrently by deoptimization! intptr_t* sender_sp = (intptr_t*) fp; - address sender_pc = (address) sender_abi->lr;; + address sender_pc = (address) sender_abi->lr; if (Continuation::is_return_barrier_entry(sender_pc)) { // If our sender_pc is the return barrier, then our "real" sender is the continuation entry @@ -134,9 +134,18 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } + intptr_t* unextended_sender_sp = is_interpreted_frame() ? interpreter_frame_sender_sp() : sender_sp; + + // If the sender is a deoptimized nmethod we need to check if the original pc is valid. + nmethod* sender_nm = sender_blob->as_nmethod_or_null(); + if (sender_nm != nullptr && sender_nm->is_deopt_pc(sender_pc)) { + address orig_pc = *(address*)((address)unextended_sender_sp + sender_nm->orig_pc_offset()); + if (!sender_nm->insts_contains_inclusive(orig_pc)) return false; + } + // It should be safe to construct the sender though it might not be valid. - frame sender(sender_sp, sender_pc, nullptr /* unextended_sp */, nullptr /* fp */, sender_blob); + frame sender(sender_sp, sender_pc, unextended_sender_sp, nullptr /* fp */, sender_blob); // Do we have a valid fp? address sender_fp = (address) sender.fp(); From 260d4658aefe370d8994574c20057de07fd6f197 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Sat, 5 Oct 2024 21:15:18 +0000 Subject: [PATCH 163/188] 8340572: ConcurrentModificationException when sorting ArrayList sublists Reviewed-by: smarks --- .../share/classes/java/util/ArrayList.java | 2 +- .../java/util/ArrayList/SortingModCount.java | 59 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/util/ArrayList/SortingModCount.java diff --git a/src/java.base/share/classes/java/util/ArrayList.java b/src/java.base/share/classes/java/util/ArrayList.java index bcf7b79e78024..c00b130a553a2 100644 --- a/src/java.base/share/classes/java/util/ArrayList.java +++ b/src/java.base/share/classes/java/util/ArrayList.java @@ -1808,6 +1808,7 @@ private void replaceAllRange(UnaryOperator operator, int i, int end) { @Override public void sort(Comparator c) { sortRange(c, 0, size); + modCount++; } @SuppressWarnings("unchecked") @@ -1816,7 +1817,6 @@ private void sortRange(Comparator c, int fromIndex, int toIndex) { Arrays.sort((E[]) elementData, fromIndex, toIndex, c); if (modCount != expectedModCount) throw new ConcurrentModificationException(); - modCount++; } void checkInvariants() { diff --git a/test/jdk/java/util/ArrayList/SortingModCount.java b/test/jdk/java/util/ArrayList/SortingModCount.java new file mode 100644 index 0000000000000..394c74cf4448c --- /dev/null +++ b/test/jdk/java/util/ArrayList/SortingModCount.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.ArrayList; +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.List; + +/** + * @test + * @bug 8340572 + * @summary ConcurrentModificationException when sorting ArrayList sublists + */ + +public class SortingModCount { + public static void main(String[] args) { + testSortingSubListsDoesNotIncrementModCount(); + testSortingListDoesIncrementModCount(); + } + + private static void testSortingSubListsDoesNotIncrementModCount() { + List l = new ArrayList<>(List.of(1, 2, 3, 4)); + var a = l.subList(0, 2); + var b = l.subList(2, 4); + Collections.sort(a); + Collections.sort(b); + } + + private static void testSortingListDoesIncrementModCount() { + List l = new ArrayList<>(List.of(1, 2, 3, 4)); + var b = l.subList(2, 4); + Collections.sort(l); + try { + Collections.sort(b); + throw new Error("expected ConcurrentModificationException not thrown"); + } catch (ConcurrentModificationException expected) { + } + } +} From 50426b3841240c5fda0df11439e52fa1ae9e7e07 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Sun, 6 Oct 2024 12:21:17 +0000 Subject: [PATCH 164/188] 8337713: RISC-V: fix typos in macroAssembler_riscv.cpp Reviewed-by: jwaters, fyang --- src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 6 +++--- src/hotspot/cpu/riscv/methodHandles_riscv.cpp | 1 - .../cert/CertPathValidator/certification/CAInterop.java | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b99ba542423a1..b327fb0480cf5 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -2947,7 +2947,7 @@ int MacroAssembler::corrected_idivq(Register result, Register rs1, Register rs2, return idivq_offset; } -// Look up the method for a megamorpic invkkeinterface call. +// Look up the method for a megamorphic invokeinterface call. // The target method is determined by . // The receiver klass is in recv_klass. // On success, the result will be in method_result, and execution falls through. @@ -2962,9 +2962,9 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, assert_different_registers(recv_klass, intf_klass, scan_tmp); assert_different_registers(method_result, intf_klass, scan_tmp); assert(recv_klass != method_result || !return_method, - "recv_klass can be destroyed when mehtid isn't needed"); + "recv_klass can be destroyed when method isn't needed"); assert(itable_index.is_constant() || itable_index.as_register() == method_result, - "caller must be same register for non-constant itable index as for method"); + "caller must use same register for non-constant itable index as for method"); // Compute start of first itableOffsetEntry (which is at the end of the vtable). int vtable_base = in_bytes(Klass::vtable_start_offset()); diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp index deeb771d83bb8..280ae6062a946 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp @@ -444,7 +444,6 @@ void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, __ far_jump(RuntimeAddress(SharedRuntime::throw_IncompatibleClassChangeError_entry())); } } - } #ifndef PRODUCT diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java index 924f58cc80f25..2bfd3ea760320 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java @@ -26,7 +26,7 @@ * @bug 8189131 * @summary Interoperability tests with Actalis CA * Before this test set to manual, the original timeout - * value if 180 + * value is 180 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop * @run main/othervm/manual -Djava.security.debug=certpath,ocsp From 20f36c666c30e50c446d09cca4ea52395317a7eb Mon Sep 17 00:00:00 2001 From: "David M. Lloyd" Date: Sun, 6 Oct 2024 16:26:45 +0000 Subject: [PATCH 165/188] 8339329: ConstantPoolBuilder#constantValueEntry method doc typo and clarifications Reviewed-by: liach --- .../lang/classfile/constantpool/ConstantPoolBuilder.java | 3 ++- .../lang/classfile/constantpool/ConstantValueEntry.java | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java index 1c0d6e55e3143..12c9789133bb4 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantPoolBuilder.java @@ -470,10 +470,11 @@ default StringEntry stringEntry(String value) { } /** - * {@return A {@link ConstantValueEntry} descripbing the provided + * {@return A {@link ConstantValueEntry} describing the provided * Integer, Long, Float, Double, or String constant} * * @param c the constant + * @see ConstantValueEntry#constantValue() */ default ConstantValueEntry constantValueEntry(ConstantDesc c) { if (c instanceof Integer i) return intEntry(i); diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java index 340baeb905fd6..720e3fd5d5cc4 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/ConstantValueEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,13 +24,14 @@ */ package java.lang.classfile.constantpool; +import java.lang.classfile.Attributes; import java.lang.constant.ConstantDesc; import jdk.internal.javac.PreviewFeature; /** * Models a constant pool entry that can be used as the constant in a - * {@code ConstantValue} attribute; this includes the four primitive constant - * types and {@linkplain String} constants. + * {@link Attributes#constantValue() ConstantValue} attribute; this includes the four + * primitive constant types and {@linkplain String} constants. * * @sealedGraph * @since 22 @@ -42,6 +43,8 @@ public sealed interface ConstantValueEntry extends LoadableConstantEntry /** * {@return the constant value} The constant value will be an {@link Integer}, * {@link Long}, {@link Float}, {@link Double}, or {@link String}. + * + * @see ConstantPoolBuilder#constantValueEntry(ConstantDesc) */ @Override ConstantDesc constantValue(); From 6600161ad46fe5b1e742409481bf225cd87f07c9 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 7 Oct 2024 07:05:31 +0000 Subject: [PATCH 166/188] 8338379: Accesses to class init state should be properly synchronized Reviewed-by: mdoerr, dholmes, coleenp, fyang, amitkumar --- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 4 ++-- src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp | 3 ++- src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp | 1 + src/hotspot/cpu/arm/templateTable_arm.cpp | 1 + src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 1 + src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 8 ++++++-- src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp | 1 + src/hotspot/cpu/riscv/macroAssembler_riscv.cpp | 1 + src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp | 1 + src/hotspot/cpu/s390/macroAssembler_s390.cpp | 3 ++- src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 1 + src/hotspot/cpu/x86/macroAssembler_x86.cpp | 3 ++- src/hotspot/cpu/x86/templateTable_x86.cpp | 1 + src/hotspot/share/oops/instanceKlass.cpp | 2 +- src/hotspot/share/oops/instanceKlass.hpp | 14 +++++++------- src/hotspot/share/opto/graphKit.cpp | 2 +- src/hotspot/share/opto/library_call.cpp | 2 +- 17 files changed, 32 insertions(+), 17 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 5e116d82761ac..1385366d8793b 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -1168,8 +1168,8 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { if (op->init_check()) { - __ ldrb(rscratch1, Address(op->klass()->as_register(), - InstanceKlass::init_state_offset())); + __ lea(rscratch1, Address(op->klass()->as_register(), InstanceKlass::init_state_offset())); + __ ldarb(rscratch1, rscratch1); __ cmpw(rscratch1, InstanceKlass::fully_initialized); add_debug_info_for_null_check_here(op->stub()->info()); __ br(Assembler::NE, *op->stub()->entry()); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index c5c02619d446e..16473b09fff42 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -1838,7 +1838,8 @@ void MacroAssembler::clinit_barrier(Register klass, Register scratch, Label* L_f L_slow_path = &L_fallthrough; } // Fast path check: class is fully initialized - ldrb(scratch, Address(klass, InstanceKlass::init_state_offset())); + lea(scratch, Address(klass, InstanceKlass::init_state_offset())); + ldarb(scratch, scratch); subs(zr, scratch, InstanceKlass::fully_initialized); br(Assembler::EQ, *L_fast_path); diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index bb6a93e6f8da7..b14e6f0b4ca0c 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -948,6 +948,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { if (op->init_check()) { Register tmp = op->tmp1()->as_register(); __ ldrb(tmp, Address(op->klass()->as_register(), InstanceKlass::init_state_offset())); + __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp); add_debug_info_for_null_check_here(op->stub()->info()); __ cmp(tmp, InstanceKlass::fully_initialized); __ b(*op->stub()->entry(), ne); diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp index 80519fd89f426..0974ff1f9a9c3 100644 --- a/src/hotspot/cpu/arm/templateTable_arm.cpp +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp @@ -3974,6 +3974,7 @@ void TemplateTable::_new() { // make sure klass is initialized // make sure klass is fully initialized __ ldrb(Rtemp, Address(Rklass, InstanceKlass::init_state_offset())); + __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp); __ cmp(Rtemp, InstanceKlass::fully_initialized); __ b(slow_case, ne); diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 42934dc7c3179..684c06614a97a 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -2274,6 +2274,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { } __ lbz(op->tmp1()->as_register(), in_bytes(InstanceKlass::init_state_offset()), op->klass()->as_register()); + // acquire barrier included in membar_storestore() which follows the allocation immediately. __ cmpwi(CCR0, op->tmp1()->as_register(), InstanceKlass::fully_initialized); __ bc_far_optimized(Assembler::bcondCRbiIs0, __ bi0(CCR0, Assembler::equal), *op->stub()->entry()); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 8d8e39b8bbc00..a194c030a6124 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2410,7 +2410,7 @@ void MacroAssembler::verify_secondary_supers_table(Register r_sub_klass, void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fast_path, Label* L_slow_path) { assert(L_fast_path != nullptr || L_slow_path != nullptr, "at least one is required"); - Label L_fallthrough; + Label L_check_thread, L_fallthrough; if (L_fast_path == nullptr) { L_fast_path = &L_fallthrough; } else if (L_slow_path == nullptr) { @@ -2419,10 +2419,14 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa // Fast path check: class is fully initialized lbz(R0, in_bytes(InstanceKlass::init_state_offset()), klass); + // acquire by cmp-branch-isync if fully_initialized cmpwi(CCR0, R0, InstanceKlass::fully_initialized); - beq(CCR0, *L_fast_path); + bne(CCR0, L_check_thread); + isync(); + b(*L_fast_path); // Fast path check: current thread is initializer thread + bind(L_check_thread); ld(R0, in_bytes(InstanceKlass::init_thread_offset()), klass); cmpd(CCR0, thread, R0); if (L_slow_path == &L_fallthrough) { diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index 940706b0a7376..828f70e4decee 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -980,6 +980,7 @@ void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { if (op->init_check()) { __ lbu(t0, Address(op->klass()->as_register(), InstanceKlass::init_state_offset())); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); __ mv(t1, (u1)InstanceKlass::fully_initialized); add_debug_info_for_null_check_here(op->stub()->info()); __ bne(t0, t1, *op->stub()->entry(), /* is_far */ true); diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index b327fb0480cf5..46701b6ede387 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -493,6 +493,7 @@ void MacroAssembler::clinit_barrier(Register klass, Register tmp, Label* L_fast_ // Fast path check: class is fully initialized lbu(tmp, Address(klass, InstanceKlass::init_state_offset())); + membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); sub(tmp, tmp, InstanceKlass::fully_initialized); beqz(tmp, *L_fast_path); diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index d288f4a893d0a..8990cf1663dd5 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -2350,6 +2350,7 @@ void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr de void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { if (op->init_check()) { // Make sure klass is initialized & doesn't have finalizer. + // init_state needs acquire, but S390 is TSO, and so we are already good. const int state_offset = in_bytes(InstanceKlass::init_state_offset()); Register iklass = op->klass()->as_register(); add_debug_info_for_null_check_here(op->stub()->info()); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index e192bbab0deb8..6bfe5125959ad 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -3459,7 +3459,8 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa L_slow_path = &L_fallthrough; } - // Fast path check: class is fully initialized + // Fast path check: class is fully initialized. + // init_state needs acquire, but S390 is TSO, and so we are already good. z_cli(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); z_bre(*L_fast_path); diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index c3444d5a5abce..6d9812c11ae6e 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -1578,6 +1578,7 @@ void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { if (op->init_check()) { add_debug_info_for_null_check_here(op->stub()->info()); + // init_state needs acquire, but x86 is TSO, and so we are already good. __ cmpb(Address(op->klass()->as_register(), InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 893ae4e844ba4..018258a012e57 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -5084,7 +5084,8 @@ void MacroAssembler::clinit_barrier(Register klass, Register thread, Label* L_fa L_slow_path = &L_fallthrough; } - // Fast path check: class is fully initialized + // Fast path check: class is fully initialized. + // init_state needs acquire, but x86 is TSO, and so we are already good. cmpb(Address(klass, InstanceKlass::init_state_offset()), InstanceKlass::fully_initialized); jcc(Assembler::equal, *L_fast_path); diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 5e783225fcbfc..527d961259ecc 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -4048,6 +4048,7 @@ void TemplateTable::_new() { __ push(rcx); // save the contexts of klass for initializing the header // make sure klass is initialized + // init_state needs acquire, but x86 is TSO, and so we are already good. #ifdef _LP64 assert(VM_Version::supports_fast_class_init_checks(), "must support fast class initialization checks"); __ clinit_barrier(rcx, r15_thread, nullptr /*L_fast_path*/, &slow_case); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 5e226a90764ee..6b6d35ee026de 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -4103,7 +4103,7 @@ void InstanceKlass::set_init_state(ClassState state) { assert(good_state || state == allocated, "illegal state transition"); #endif assert(_init_thread == nullptr, "should be cleared before state change"); - _init_state = state; + Atomic::release_store(&_init_state, state); } #if INCLUDE_JVMTI diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index eaffa0250d133..45d65f273c866 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -507,14 +507,14 @@ class InstanceKlass: public Klass { public: // initialization state - bool is_loaded() const { return _init_state >= loaded; } - bool is_linked() const { return _init_state >= linked; } - bool is_initialized() const { return _init_state == fully_initialized; } - bool is_not_initialized() const { return _init_state < being_initialized; } - bool is_being_initialized() const { return _init_state == being_initialized; } - bool is_in_error_state() const { return _init_state == initialization_error; } + bool is_loaded() const { return init_state() >= loaded; } + bool is_linked() const { return init_state() >= linked; } + bool is_initialized() const { return init_state() == fully_initialized; } + bool is_not_initialized() const { return init_state() < being_initialized; } + bool is_being_initialized() const { return init_state() == being_initialized; } + bool is_in_error_state() const { return init_state() == initialization_error; } bool is_reentrant_initialization(Thread *thread) { return thread == _init_thread; } - ClassState init_state() const { return _init_state; } + ClassState init_state() const { return Atomic::load_acquire(&_init_state); } const char* init_state_name() const; bool is_rewritten() const { return _misc_flags.rewritten(); } diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 3bc5b9a8b2a7d..1a0d0bd037515 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -3008,7 +3008,7 @@ void GraphKit::guard_klass_being_initialized(Node* klass) { Node* adr = basic_plus_adr(top(), klass, init_state_off); Node* init_state = LoadNode::make(_gvn, nullptr, immutable_memory(), adr, adr->bottom_type()->is_ptr(), TypeInt::BYTE, - T_BYTE, MemNode::unordered); + T_BYTE, MemNode::acquire); init_state = _gvn.transform(init_state); Node* being_initialized_state = makecon(TypeInt::make(InstanceKlass::being_initialized)); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 4d182e06a5657..386dd41f2e956 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -2904,7 +2904,7 @@ bool LibraryCallKit::inline_unsafe_allocate() { Node* insp = basic_plus_adr(kls, in_bytes(InstanceKlass::init_state_offset())); // Use T_BOOLEAN for InstanceKlass::_init_state so the compiler // can generate code to load it as unsigned byte. - Node* inst = make_load(nullptr, insp, TypeInt::UBYTE, T_BOOLEAN, MemNode::unordered); + Node* inst = make_load(nullptr, insp, TypeInt::UBYTE, T_BOOLEAN, MemNode::acquire); Node* bits = intcon(InstanceKlass::fully_initialized); test = _gvn.transform(new SubINode(inst, bits)); // The 'test' is non-zero if we need to take a slow path. From 92186a27743732964b5cf3be339fd568da2aa4ba Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 7 Oct 2024 07:58:01 +0000 Subject: [PATCH 167/188] 8341612: [BACKOUT] 8338442: AArch64: Clean up IndOffXX type and let legitimize_address() fix out-of-range operands Reviewed-by: chagedorn --- src/hotspot/cpu/aarch64/aarch64.ad | 393 ++++++++++++++---- src/hotspot/cpu/aarch64/aarch64_vector.ad | 16 +- src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 | 2 +- src/hotspot/cpu/aarch64/ad_encode.m4 | 8 +- src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad | 2 +- src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad | 2 +- .../compiler/c2/TestUnalignedAccess.java | 61 +-- 7 files changed, 361 insertions(+), 123 deletions(-) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 7d2a35cefd86a..c7cae54d14c0a 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -2721,7 +2721,7 @@ typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt, { Address addr = mem2address(opcode, base, index, scale, disp); if (addr.getMode() == Address::base_plus_offset) { - // Fix up any out-of-range offsets. + /* Fix up any out-of-range offsets. */ assert_different_registers(rscratch1, base); assert_different_registers(rscratch1, reg); addr = __ legitimize_address(addr, size_in_memory, rscratch1); @@ -2762,11 +2762,7 @@ typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt, int opcode, Register base, int index, int size, int disp) { if (index == -1) { - // Fix up any out-of-range offsets. - assert_different_registers(rscratch1, base); - Address addr = Address(base, disp); - addr = __ legitimize_address(addr, (1 << T), rscratch1); - (masm->*insn)(reg, T, addr); + (masm->*insn)(reg, T, Address(base, disp)); } else { assert(disp == 0, "unsupported address mode"); (masm->*insn)(reg, T, Address(base, as_Register(index), Address::lsl(size))); @@ -2821,7 +2817,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsbw(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrsbw(iRegI dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsbw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2829,7 +2825,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsb(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrsb(iRegI dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2837,7 +2833,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrb(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrb(iRegI dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2845,7 +2841,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrb(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldrb(iRegL dst, memory1 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrb, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2853,7 +2849,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrshw(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrshw(iRegI dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrshw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2861,7 +2857,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsh(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrsh(iRegI dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2869,7 +2865,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrh(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrh(iRegI dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2877,7 +2873,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrh(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldrh(iRegL dst, memory2 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrh, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2885,7 +2881,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrw(iRegI dst, memory mem) %{ + enc_class aarch64_enc_ldrw(iRegI dst, memory4 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2893,7 +2889,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrw(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldrw(iRegL dst, memory4 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2901,7 +2897,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrsw(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldrsw(iRegL dst, memory4 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldrsw, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2909,7 +2905,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldr(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldr(iRegL dst, memory8 mem) %{ Register dst_reg = as_Register($dst$$reg); loadStore(masm, &MacroAssembler::ldr, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -2917,7 +2913,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrs(vRegF dst, memory mem) %{ + enc_class aarch64_enc_ldrs(vRegF dst, memory4 mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(masm, &MacroAssembler::ldrs, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2925,7 +2921,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_ldrd(vRegD dst, memory mem) %{ + enc_class aarch64_enc_ldrd(vRegD dst, memory8 mem) %{ FloatRegister dst_reg = as_FloatRegister($dst$$reg); loadStore(masm, &MacroAssembler::ldrd, dst_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -2933,7 +2929,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb(iRegI src, memory mem) %{ + enc_class aarch64_enc_strb(iRegI src, memory1 mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strb, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -2941,14 +2937,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0(memory mem) %{ + enc_class aarch64_enc_strb0(memory1 mem) %{ loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strh(iRegI src, memory mem) %{ + enc_class aarch64_enc_strh(iRegI src, memory2 mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strh, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); @@ -2956,14 +2952,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strh0(memory mem) %{ + enc_class aarch64_enc_strh0(memory2 mem) %{ loadStore(masm, &MacroAssembler::strh, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 2); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strw(iRegI src, memory mem) %{ + enc_class aarch64_enc_strw(iRegI src, memory4 mem) %{ Register src_reg = as_Register($src$$reg); loadStore(masm, &MacroAssembler::strw, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -2971,14 +2967,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strw0(memory mem) %{ + enc_class aarch64_enc_strw0(memory4 mem) %{ loadStore(masm, &MacroAssembler::strw, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_str(iRegL src, memory mem) %{ + enc_class aarch64_enc_str(iRegL src, memory8 mem) %{ Register src_reg = as_Register($src$$reg); // we sometimes get asked to store the stack pointer into the // current thread -- we cannot do that directly on AArch64 @@ -2993,14 +2989,14 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_str0(memory mem) %{ + enc_class aarch64_enc_str0(memory8 mem) %{ loadStore(masm, &MacroAssembler::str, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); %} // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strs(vRegF src, memory mem) %{ + enc_class aarch64_enc_strs(vRegF src, memory4 mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(masm, &MacroAssembler::strs, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 4); @@ -3008,7 +3004,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strd(vRegD src, memory mem) %{ + enc_class aarch64_enc_strd(vRegD src, memory8 mem) %{ FloatRegister src_reg = as_FloatRegister($src$$reg); loadStore(masm, &MacroAssembler::strd, src_reg, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 8); @@ -3016,7 +3012,7 @@ encode %{ // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0_ordered(memory mem) %{ + enc_class aarch64_enc_strb0_ordered(memory4 mem) %{ __ membar(Assembler::StoreStore); loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); @@ -3218,7 +3214,7 @@ encode %{ // synchronized read/update encodings - enc_class aarch64_enc_ldaxr(iRegL dst, memory mem) %{ + enc_class aarch64_enc_ldaxr(iRegL dst, memory8 mem) %{ Register dst_reg = as_Register($dst$$reg); Register base = as_Register($mem$$base); int index = $mem$$index; @@ -3246,7 +3242,7 @@ encode %{ } %} - enc_class aarch64_enc_stlxr(iRegLNoSp src, memory mem) %{ + enc_class aarch64_enc_stlxr(iRegLNoSp src, memory8 mem) %{ Register src_reg = as_Register($src$$reg); Register base = as_Register($mem$$base); int index = $mem$$index; @@ -4174,10 +4170,60 @@ operand immIU7() interface(CONST_INTER); %} -// Offset for immediate loads and stores +// Offset for scaled or unscaled immediate loads and stores operand immIOffset() %{ - predicate(n->get_int() >= -256 && n->get_int() <= 65520); + predicate(Address::offset_ok_for_immed(n->get_int(), 0)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset1() +%{ + predicate(Address::offset_ok_for_immed(n->get_int(), 0)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset2() +%{ + predicate(Address::offset_ok_for_immed(n->get_int(), 1)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset4() +%{ + predicate(Address::offset_ok_for_immed(n->get_int(), 2)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset8() +%{ + predicate(Address::offset_ok_for_immed(n->get_int(), 3)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset16() +%{ + predicate(Address::offset_ok_for_immed(n->get_int(), 4)); match(ConI); op_cost(0); @@ -4195,6 +4241,56 @@ operand immLOffset() interface(CONST_INTER); %} +operand immLoffset1() +%{ + predicate(Address::offset_ok_for_immed(n->get_long(), 0)); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immLoffset2() +%{ + predicate(Address::offset_ok_for_immed(n->get_long(), 1)); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immLoffset4() +%{ + predicate(Address::offset_ok_for_immed(n->get_long(), 2)); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immLoffset8() +%{ + predicate(Address::offset_ok_for_immed(n->get_long(), 3)); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immLoffset16() +%{ + predicate(Address::offset_ok_for_immed(n->get_long(), 4)); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + // 5 bit signed long integer operand immL5() %{ @@ -5107,7 +5203,21 @@ operand indIndex(iRegP reg, iRegL lreg) %} %} -operand indOffI(iRegP reg, immIOffset off) +operand indOffI1(iRegP reg, immIOffset1 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffI2(iRegP reg, immIOffset2 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); @@ -5121,7 +5231,105 @@ operand indOffI(iRegP reg, immIOffset off) %} %} -operand indOffL(iRegP reg, immLOffset off) +operand indOffI4(iRegP reg, immIOffset4 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffI8(iRegP reg, immIOffset8 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffI16(iRegP reg, immIOffset16 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffL1(iRegP reg, immLoffset1 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffL2(iRegP reg, immLoffset2 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffL4(iRegP reg, immLoffset4 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffL8(iRegP reg, immLoffset8 off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffL16(iRegP reg, immLoffset16 off) %{ constraint(ALLOC_IN_RC(ptr_reg)); match(AddP reg off); @@ -5497,7 +5705,10 @@ operand iRegL2P(iRegL reg) %{ interface(REG_INTER) %} -opclass vmem(indirect, indIndex, indOffI, indOffL, indOffIN, indOffLN); +opclass vmem2(indirect, indIndex, indOffI2, indOffL2); +opclass vmem4(indirect, indIndex, indOffI4, indOffL4); +opclass vmem8(indirect, indIndex, indOffI8, indOffL8); +opclass vmem16(indirect, indIndex, indOffI16, indOffL16); //----------OPERAND CLASSES---------------------------------------------------- // Operand Classes are groups of operands that are used as to simplify @@ -5509,9 +5720,23 @@ opclass vmem(indirect, indIndex, indOffI, indOffL, indOffIN, indOffLN); // memory is used to define read/write location for load/store // instruction defs. we can turn a memory op into an Address -opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI, indOffL, - indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, - indOffLN, indirectX2P, indOffX2P); +opclass memory1(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI1, indOffL1, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indirectX2P, indOffX2P); + +opclass memory2(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI2, indOffL2, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indirectX2P, indOffX2P); + +opclass memory4(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI4, indOffL4, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); + +opclass memory8(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, indOffI8, indOffL8, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); + +// All of the memory operands. For the pipeline description. +opclass memory(indirect, indIndexScaled, indIndexScaledI2L, indIndexI2L, indIndex, + indOffI1, indOffL1, indOffI2, indOffL2, indOffI4, indOffL4, indOffI8, indOffL8, + indirectN, indIndexScaledN, indIndexScaledI2LN, indIndexI2LN, indIndexN, indOffIN, indOffLN, indirectX2P, indOffX2P); + // iRegIorL2I is used for src inputs in rules for 32 bit int (I) // operations. it allows the src to be either an iRegI or a (ConvL2I @@ -6213,7 +6438,7 @@ define %{ // Load Instructions // Load Byte (8 bit signed) -instruct loadB(iRegINoSp dst, memory mem) +instruct loadB(iRegINoSp dst, memory1 mem) %{ match(Set dst (LoadB mem)); predicate(!needs_acquiring_load(n)); @@ -6227,7 +6452,7 @@ instruct loadB(iRegINoSp dst, memory mem) %} // Load Byte (8 bit signed) into long -instruct loadB2L(iRegLNoSp dst, memory mem) +instruct loadB2L(iRegLNoSp dst, memory1 mem) %{ match(Set dst (ConvI2L (LoadB mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6241,7 +6466,7 @@ instruct loadB2L(iRegLNoSp dst, memory mem) %} // Load Byte (8 bit unsigned) -instruct loadUB(iRegINoSp dst, memory mem) +instruct loadUB(iRegINoSp dst, memory1 mem) %{ match(Set dst (LoadUB mem)); predicate(!needs_acquiring_load(n)); @@ -6255,7 +6480,7 @@ instruct loadUB(iRegINoSp dst, memory mem) %} // Load Byte (8 bit unsigned) into long -instruct loadUB2L(iRegLNoSp dst, memory mem) +instruct loadUB2L(iRegLNoSp dst, memory1 mem) %{ match(Set dst (ConvI2L (LoadUB mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6269,7 +6494,7 @@ instruct loadUB2L(iRegLNoSp dst, memory mem) %} // Load Short (16 bit signed) -instruct loadS(iRegINoSp dst, memory mem) +instruct loadS(iRegINoSp dst, memory2 mem) %{ match(Set dst (LoadS mem)); predicate(!needs_acquiring_load(n)); @@ -6283,7 +6508,7 @@ instruct loadS(iRegINoSp dst, memory mem) %} // Load Short (16 bit signed) into long -instruct loadS2L(iRegLNoSp dst, memory mem) +instruct loadS2L(iRegLNoSp dst, memory2 mem) %{ match(Set dst (ConvI2L (LoadS mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6297,7 +6522,7 @@ instruct loadS2L(iRegLNoSp dst, memory mem) %} // Load Char (16 bit unsigned) -instruct loadUS(iRegINoSp dst, memory mem) +instruct loadUS(iRegINoSp dst, memory2 mem) %{ match(Set dst (LoadUS mem)); predicate(!needs_acquiring_load(n)); @@ -6311,7 +6536,7 @@ instruct loadUS(iRegINoSp dst, memory mem) %} // Load Short/Char (16 bit unsigned) into long -instruct loadUS2L(iRegLNoSp dst, memory mem) +instruct loadUS2L(iRegLNoSp dst, memory2 mem) %{ match(Set dst (ConvI2L (LoadUS mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6325,7 +6550,7 @@ instruct loadUS2L(iRegLNoSp dst, memory mem) %} // Load Integer (32 bit signed) -instruct loadI(iRegINoSp dst, memory mem) +instruct loadI(iRegINoSp dst, memory4 mem) %{ match(Set dst (LoadI mem)); predicate(!needs_acquiring_load(n)); @@ -6339,7 +6564,7 @@ instruct loadI(iRegINoSp dst, memory mem) %} // Load Integer (32 bit signed) into long -instruct loadI2L(iRegLNoSp dst, memory mem) +instruct loadI2L(iRegLNoSp dst, memory4 mem) %{ match(Set dst (ConvI2L (LoadI mem))); predicate(!needs_acquiring_load(n->in(1))); @@ -6353,7 +6578,7 @@ instruct loadI2L(iRegLNoSp dst, memory mem) %} // Load Integer (32 bit unsigned) into long -instruct loadUI2L(iRegLNoSp dst, memory mem, immL_32bits mask) +instruct loadUI2L(iRegLNoSp dst, memory4 mem, immL_32bits mask) %{ match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); predicate(!needs_acquiring_load(n->in(1)->in(1)->as_Load())); @@ -6367,7 +6592,7 @@ instruct loadUI2L(iRegLNoSp dst, memory mem, immL_32bits mask) %} // Load Long (64 bit signed) -instruct loadL(iRegLNoSp dst, memory mem) +instruct loadL(iRegLNoSp dst, memory8 mem) %{ match(Set dst (LoadL mem)); predicate(!needs_acquiring_load(n)); @@ -6381,7 +6606,7 @@ instruct loadL(iRegLNoSp dst, memory mem) %} // Load Range -instruct loadRange(iRegINoSp dst, memory mem) +instruct loadRange(iRegINoSp dst, memory4 mem) %{ match(Set dst (LoadRange mem)); @@ -6394,7 +6619,7 @@ instruct loadRange(iRegINoSp dst, memory mem) %} // Load Pointer -instruct loadP(iRegPNoSp dst, memory mem) +instruct loadP(iRegPNoSp dst, memory8 mem) %{ match(Set dst (LoadP mem)); predicate(!needs_acquiring_load(n) && (n->as_Load()->barrier_data() == 0)); @@ -6408,7 +6633,7 @@ instruct loadP(iRegPNoSp dst, memory mem) %} // Load Compressed Pointer -instruct loadN(iRegNNoSp dst, memory mem) +instruct loadN(iRegNNoSp dst, memory4 mem) %{ match(Set dst (LoadN mem)); predicate(!needs_acquiring_load(n) && n->as_Load()->barrier_data() == 0); @@ -6422,7 +6647,7 @@ instruct loadN(iRegNNoSp dst, memory mem) %} // Load Klass Pointer -instruct loadKlass(iRegPNoSp dst, memory mem) +instruct loadKlass(iRegPNoSp dst, memory8 mem) %{ match(Set dst (LoadKlass mem)); predicate(!needs_acquiring_load(n)); @@ -6436,7 +6661,7 @@ instruct loadKlass(iRegPNoSp dst, memory mem) %} // Load Narrow Klass Pointer -instruct loadNKlass(iRegNNoSp dst, memory mem) +instruct loadNKlass(iRegNNoSp dst, memory4 mem) %{ match(Set dst (LoadNKlass mem)); predicate(!needs_acquiring_load(n)); @@ -6450,7 +6675,7 @@ instruct loadNKlass(iRegNNoSp dst, memory mem) %} // Load Float -instruct loadF(vRegF dst, memory mem) +instruct loadF(vRegF dst, memory4 mem) %{ match(Set dst (LoadF mem)); predicate(!needs_acquiring_load(n)); @@ -6464,7 +6689,7 @@ instruct loadF(vRegF dst, memory mem) %} // Load Double -instruct loadD(vRegD dst, memory mem) +instruct loadD(vRegD dst, memory8 mem) %{ match(Set dst (LoadD mem)); predicate(!needs_acquiring_load(n)); @@ -6668,7 +6893,7 @@ instruct loadConD(vRegD dst, immD con) %{ // Store Instructions // Store CMS card-mark Immediate -instruct storeimmCM0(immI0 zero, memory mem) +instruct storeimmCM0(immI0 zero, memory1 mem) %{ match(Set mem (StoreCM mem zero)); @@ -6683,7 +6908,7 @@ instruct storeimmCM0(immI0 zero, memory mem) // Store CMS card-mark Immediate with intervening StoreStore // needed when using CMS with no conditional card marking -instruct storeimmCM0_ordered(immI0 zero, memory mem) +instruct storeimmCM0_ordered(immI0 zero, memory1 mem) %{ match(Set mem (StoreCM mem zero)); @@ -6698,7 +6923,7 @@ instruct storeimmCM0_ordered(immI0 zero, memory mem) %} // Store Byte -instruct storeB(iRegIorL2I src, memory mem) +instruct storeB(iRegIorL2I src, memory1 mem) %{ match(Set mem (StoreB mem src)); predicate(!needs_releasing_store(n)); @@ -6712,7 +6937,7 @@ instruct storeB(iRegIorL2I src, memory mem) %} -instruct storeimmB0(immI0 zero, memory mem) +instruct storeimmB0(immI0 zero, memory1 mem) %{ match(Set mem (StoreB mem zero)); predicate(!needs_releasing_store(n)); @@ -6726,7 +6951,7 @@ instruct storeimmB0(immI0 zero, memory mem) %} // Store Char/Short -instruct storeC(iRegIorL2I src, memory mem) +instruct storeC(iRegIorL2I src, memory2 mem) %{ match(Set mem (StoreC mem src)); predicate(!needs_releasing_store(n)); @@ -6739,7 +6964,7 @@ instruct storeC(iRegIorL2I src, memory mem) ins_pipe(istore_reg_mem); %} -instruct storeimmC0(immI0 zero, memory mem) +instruct storeimmC0(immI0 zero, memory2 mem) %{ match(Set mem (StoreC mem zero)); predicate(!needs_releasing_store(n)); @@ -6754,7 +6979,7 @@ instruct storeimmC0(immI0 zero, memory mem) // Store Integer -instruct storeI(iRegIorL2I src, memory mem) +instruct storeI(iRegIorL2I src, memory4 mem) %{ match(Set mem(StoreI mem src)); predicate(!needs_releasing_store(n)); @@ -6767,7 +6992,7 @@ instruct storeI(iRegIorL2I src, memory mem) ins_pipe(istore_reg_mem); %} -instruct storeimmI0(immI0 zero, memory mem) +instruct storeimmI0(immI0 zero, memory4 mem) %{ match(Set mem(StoreI mem zero)); predicate(!needs_releasing_store(n)); @@ -6781,7 +7006,7 @@ instruct storeimmI0(immI0 zero, memory mem) %} // Store Long (64 bit signed) -instruct storeL(iRegL src, memory mem) +instruct storeL(iRegL src, memory8 mem) %{ match(Set mem (StoreL mem src)); predicate(!needs_releasing_store(n)); @@ -6795,7 +7020,7 @@ instruct storeL(iRegL src, memory mem) %} // Store Long (64 bit signed) -instruct storeimmL0(immL0 zero, memory mem) +instruct storeimmL0(immL0 zero, memory8 mem) %{ match(Set mem (StoreL mem zero)); predicate(!needs_releasing_store(n)); @@ -6809,7 +7034,7 @@ instruct storeimmL0(immL0 zero, memory mem) %} // Store Pointer -instruct storeP(iRegP src, memory mem) +instruct storeP(iRegP src, memory8 mem) %{ match(Set mem (StoreP mem src)); predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); @@ -6823,7 +7048,7 @@ instruct storeP(iRegP src, memory mem) %} // Store Pointer -instruct storeimmP0(immP0 zero, memory mem) +instruct storeimmP0(immP0 zero, memory8 mem) %{ match(Set mem (StoreP mem zero)); predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); @@ -6837,7 +7062,7 @@ instruct storeimmP0(immP0 zero, memory mem) %} // Store Compressed Pointer -instruct storeN(iRegN src, memory mem) +instruct storeN(iRegN src, memory4 mem) %{ match(Set mem (StoreN mem src)); predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); @@ -6850,7 +7075,7 @@ instruct storeN(iRegN src, memory mem) ins_pipe(istore_reg_mem); %} -instruct storeImmN0(immN0 zero, memory mem) +instruct storeImmN0(immN0 zero, memory4 mem) %{ match(Set mem (StoreN mem zero)); predicate(!needs_releasing_store(n) && n->as_Store()->barrier_data() == 0); @@ -6864,7 +7089,7 @@ instruct storeImmN0(immN0 zero, memory mem) %} // Store Float -instruct storeF(vRegF src, memory mem) +instruct storeF(vRegF src, memory4 mem) %{ match(Set mem (StoreF mem src)); predicate(!needs_releasing_store(n)); @@ -6881,7 +7106,7 @@ instruct storeF(vRegF src, memory mem) // implement storeImmF0 and storeFImmPacked // Store Double -instruct storeD(vRegD src, memory mem) +instruct storeD(vRegD src, memory8 mem) %{ match(Set mem (StoreD mem src)); predicate(!needs_releasing_store(n)); @@ -6895,7 +7120,7 @@ instruct storeD(vRegD src, memory mem) %} // Store Compressed Klass Pointer -instruct storeNKlass(iRegN src, memory mem) +instruct storeNKlass(iRegN src, memory4 mem) %{ predicate(!needs_releasing_store(n)); match(Set mem (StoreNKlass mem src)); @@ -6914,7 +7139,7 @@ instruct storeNKlass(iRegN src, memory mem) // prefetch instructions // Must be safe to execute with invalid address (cannot fault). -instruct prefetchalloc( memory mem ) %{ +instruct prefetchalloc( memory8 mem ) %{ match(PrefetchAllocation mem); ins_cost(INSN_COST); @@ -7486,7 +7711,7 @@ instruct popCountI(iRegINoSp dst, iRegIorL2I src, vRegF tmp) %{ ins_pipe(pipe_class_default); %} -instruct popCountI_mem(iRegINoSp dst, memory mem, vRegF tmp) %{ +instruct popCountI_mem(iRegINoSp dst, memory4 mem, vRegF tmp) %{ match(Set dst (PopCountI (LoadI mem))); effect(TEMP tmp); ins_cost(INSN_COST * 13); @@ -7527,7 +7752,7 @@ instruct popCountL(iRegINoSp dst, iRegL src, vRegD tmp) %{ ins_pipe(pipe_class_default); %} -instruct popCountL_mem(iRegINoSp dst, memory mem, vRegD tmp) %{ +instruct popCountL_mem(iRegINoSp dst, memory8 mem, vRegD tmp) %{ match(Set dst (PopCountL (LoadL mem))); effect(TEMP tmp); ins_cost(INSN_COST * 13); @@ -16680,7 +16905,7 @@ instruct compressBitsI_reg(iRegINoSp dst, iRegIorL2I src, iRegIorL2I mask, ins_pipe(pipe_slow); %} -instruct compressBitsI_memcon(iRegINoSp dst, memory mem, immI mask, +instruct compressBitsI_memcon(iRegINoSp dst, memory4 mem, immI mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (CompressBits (LoadI mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -16717,7 +16942,7 @@ instruct compressBitsL_reg(iRegLNoSp dst, iRegL src, iRegL mask, ins_pipe(pipe_slow); %} -instruct compressBitsL_memcon(iRegLNoSp dst, memory mem, immL mask, +instruct compressBitsL_memcon(iRegLNoSp dst, memory8 mem, immL mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (CompressBits (LoadL mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -16754,7 +16979,7 @@ instruct expandBitsI_reg(iRegINoSp dst, iRegIorL2I src, iRegIorL2I mask, ins_pipe(pipe_slow); %} -instruct expandBitsI_memcon(iRegINoSp dst, memory mem, immI mask, +instruct expandBitsI_memcon(iRegINoSp dst, memory4 mem, immI mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (ExpandBits (LoadI mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); @@ -16792,7 +17017,7 @@ instruct expandBitsL_reg(iRegLNoSp dst, iRegL src, iRegL mask, %} -instruct expandBitsL_memcon(iRegINoSp dst, memory mem, immL mask, +instruct expandBitsL_memcon(iRegINoSp dst, memory8 mem, immL mask, vRegF tdst, vRegF tsrc, vRegF tmask) %{ match(Set dst (ExpandBits (LoadL mem) mask)); effect(TEMP tdst, TEMP tsrc, TEMP tmask); diff --git a/src/hotspot/cpu/aarch64/aarch64_vector.ad b/src/hotspot/cpu/aarch64/aarch64_vector.ad index cdbc4103df89a..0d3a240cecfd3 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector.ad +++ b/src/hotspot/cpu/aarch64/aarch64_vector.ad @@ -345,7 +345,7 @@ source %{ // ------------------------------ Vector load/store ---------------------------- // Load Vector (16 bits) -instruct loadV2(vReg dst, vmem mem) %{ +instruct loadV2(vReg dst, vmem2 mem) %{ predicate(n->as_LoadVector()->memory_size() == 2); match(Set dst (LoadVector mem)); format %{ "loadV2 $dst, $mem\t# vector (16 bits)" %} @@ -354,7 +354,7 @@ instruct loadV2(vReg dst, vmem mem) %{ %} // Store Vector (16 bits) -instruct storeV2(vReg src, vmem mem) %{ +instruct storeV2(vReg src, vmem2 mem) %{ predicate(n->as_StoreVector()->memory_size() == 2); match(Set mem (StoreVector mem src)); format %{ "storeV2 $mem, $src\t# vector (16 bits)" %} @@ -363,7 +363,7 @@ instruct storeV2(vReg src, vmem mem) %{ %} // Load Vector (32 bits) -instruct loadV4(vReg dst, vmem mem) %{ +instruct loadV4(vReg dst, vmem4 mem) %{ predicate(n->as_LoadVector()->memory_size() == 4); match(Set dst (LoadVector mem)); format %{ "loadV4 $dst, $mem\t# vector (32 bits)" %} @@ -372,7 +372,7 @@ instruct loadV4(vReg dst, vmem mem) %{ %} // Store Vector (32 bits) -instruct storeV4(vReg src, vmem mem) %{ +instruct storeV4(vReg src, vmem4 mem) %{ predicate(n->as_StoreVector()->memory_size() == 4); match(Set mem (StoreVector mem src)); format %{ "storeV4 $mem, $src\t# vector (32 bits)" %} @@ -381,7 +381,7 @@ instruct storeV4(vReg src, vmem mem) %{ %} // Load Vector (64 bits) -instruct loadV8(vReg dst, vmem mem) %{ +instruct loadV8(vReg dst, vmem8 mem) %{ predicate(n->as_LoadVector()->memory_size() == 8); match(Set dst (LoadVector mem)); format %{ "loadV8 $dst, $mem\t# vector (64 bits)" %} @@ -390,7 +390,7 @@ instruct loadV8(vReg dst, vmem mem) %{ %} // Store Vector (64 bits) -instruct storeV8(vReg src, vmem mem) %{ +instruct storeV8(vReg src, vmem8 mem) %{ predicate(n->as_StoreVector()->memory_size() == 8); match(Set mem (StoreVector mem src)); format %{ "storeV8 $mem, $src\t# vector (64 bits)" %} @@ -399,7 +399,7 @@ instruct storeV8(vReg src, vmem mem) %{ %} // Load Vector (128 bits) -instruct loadV16(vReg dst, vmem mem) %{ +instruct loadV16(vReg dst, vmem16 mem) %{ predicate(n->as_LoadVector()->memory_size() == 16); match(Set dst (LoadVector mem)); format %{ "loadV16 $dst, $mem\t# vector (128 bits)" %} @@ -408,7 +408,7 @@ instruct loadV16(vReg dst, vmem mem) %{ %} // Store Vector (128 bits) -instruct storeV16(vReg src, vmem mem) %{ +instruct storeV16(vReg src, vmem16 mem) %{ predicate(n->as_StoreVector()->memory_size() == 16); match(Set mem (StoreVector mem src)); format %{ "storeV16 $mem, $src\t# vector (128 bits)" %} diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index 020a75b51fa8f..99708e9ef317d 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -338,7 +338,7 @@ dnl VECTOR_LOAD_STORE($1, $2, $3, $4, $5 ) dnl VECTOR_LOAD_STORE(type, nbytes, arg_name, nbits, size) define(`VECTOR_LOAD_STORE', ` // ifelse(load, $1, Load, Store) Vector ($4 bits) -instruct $1V$2(vReg $3, vmem mem) %{ +instruct $1V$2(vReg $3, vmem$2 mem) %{ predicate(`n->as_'ifelse(load, $1, Load, Store)Vector()->memory_size() == $2); match(Set ifelse(load, $1, dst (LoadVector mem), mem (StoreVector mem src))); format %{ "$1V$2 ifelse(load, $1, `$dst, $mem', `$mem, $src')\t# vector ($4 bits)" %} diff --git a/src/hotspot/cpu/aarch64/ad_encode.m4 b/src/hotspot/cpu/aarch64/ad_encode.m4 index e3d8ea661b60a..008dbd2c9369c 100644 --- a/src/hotspot/cpu/aarch64/ad_encode.m4 +++ b/src/hotspot/cpu/aarch64/ad_encode.m4 @@ -34,7 +34,7 @@ define(access, ` define(load,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2($1 dst, memory mem) %{dnl + enc_class aarch64_enc_$2($1 dst, memory$5 mem) %{dnl access(dst,$2,$3,$4,$5)')dnl load(iRegI,ldrsbw,,,1) load(iRegI,ldrsb,,,1) @@ -53,12 +53,12 @@ load(vRegD,ldrd,Float,,8) define(STORE,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2($1 src, memory mem) %{dnl + enc_class aarch64_enc_$2($1 src, memory$5 mem) %{dnl access(src,$2,$3,$4,$5)')dnl define(STORE0,` // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_$2`'0(memory mem) %{ + enc_class aarch64_enc_$2`'0(memory$4 mem) %{ choose(masm,zr,$2,$mem->opcode(), as_$3Register($mem$$base),$mem$$index,$mem$$scale,$mem$$disp,$4)')dnl STORE(iRegI,strb,,,1) @@ -82,7 +82,7 @@ STORE(vRegD,strd,Float,,8) // This encoding class is generated automatically from ad_encode.m4. // DO NOT EDIT ANYTHING IN THIS SECTION OF THE FILE - enc_class aarch64_enc_strb0_ordered(memory mem) %{ + enc_class aarch64_enc_strb0_ordered(memory4 mem) %{ __ membar(Assembler::StoreStore); loadStore(masm, &MacroAssembler::strb, zr, $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp, 1); diff --git a/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad b/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad index 5e690a8e47b94..6e401724baa82 100644 --- a/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/x/x_aarch64.ad @@ -51,7 +51,7 @@ static void x_load_barrier_slow_path(MacroAssembler* masm, const MachNode* node, %} // Load Pointer -instruct xLoadP(iRegPNoSp dst, memory mem, rFlagsReg cr) +instruct xLoadP(iRegPNoSp dst, memory8 mem, rFlagsReg cr) %{ match(Set dst (LoadP mem)); predicate(UseZGC && !ZGenerational && !needs_acquiring_load(n) && (n->as_Load()->barrier_data() != 0)); diff --git a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad index 1510b42bfe97d..56d4538477920 100644 --- a/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad +++ b/src/hotspot/cpu/aarch64/gc/z/z_aarch64.ad @@ -100,7 +100,7 @@ static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address %} // Load Pointer -instruct zLoadP(iRegPNoSp dst, memory mem, rFlagsReg cr) +instruct zLoadP(iRegPNoSp dst, memory8 mem, rFlagsReg cr) %{ match(Set dst (LoadP mem)); predicate(UseZGC && ZGenerational && !needs_acquiring_load(n) && n->as_Load()->barrier_data() != 0); diff --git a/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java b/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java index 033ea49e60955..d05dbad4a73ba 100644 --- a/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java +++ b/test/hotspot/jtreg/compiler/c2/TestUnalignedAccess.java @@ -46,11 +46,20 @@ public class TestUnalignedAccess { static final Unsafe UNSAFE = Unsafe.getUnsafe(); static void sink(int x) {} + public static long lseed = 1; + public static int iseed = 2; + public static short sseed = 3; + public static byte bseed = 4; + public static long lres = lseed; + public static int ires = iseed; + public static short sres = sseed; + public static byte bres = bseed; + public static class TestLong { private static final byte[] BYTES = new byte[LEN]; private static final long rawdata = 0xbeef; - private static final long lseed = 1; + private static final long data; static { sink(2); @@ -60,10 +69,13 @@ public static class TestLong { // 1030 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putLongUnaligned(BYTES, 1030, rawdata); + lres += UNSAFE.getLongUnaligned(BYTES, 1030); // 127 can be encoded into simm9 field. - UNSAFE.putLongUnaligned(BYTES, 127, rawdata+lseed); + UNSAFE.putLongUnaligned(BYTES, 127, lres); + lres += UNSAFE.getLongUnaligned(BYTES, 127); // 1096 can be encoded into uimm12 field. - UNSAFE.putLongUnaligned(BYTES, 1096, rawdata-lseed); + UNSAFE.putLongUnaligned(BYTES, 1096, lres); + data = UNSAFE.getLongUnaligned(BYTES, 1096); } } @@ -72,7 +84,7 @@ public static class TestInt { private static final byte[] BYTES = new byte[LEN]; private static final int rawdata = 0xbeef; - private static final int iseed = 2; + private static final int data; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -81,10 +93,13 @@ public static class TestInt { // 274 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putIntUnaligned(BYTES, 274, rawdata); + ires += UNSAFE.getIntUnaligned(BYTES, 274); // 255 can be encoded into simm9 field. - UNSAFE.putIntUnaligned(BYTES, 255, rawdata + iseed); + UNSAFE.putIntUnaligned(BYTES, 255, ires); + ires += UNSAFE.getIntUnaligned(BYTES, 255); // 528 can be encoded into uimm12 field. - UNSAFE.putIntUnaligned(BYTES, 528, rawdata - iseed); + UNSAFE.putIntUnaligned(BYTES, 528, ires); + data = UNSAFE.getIntUnaligned(BYTES, 528); } } @@ -93,7 +108,7 @@ public static class TestShort { private static final byte[] BYTES = new byte[LEN]; private static final short rawdata = (short)0xbeef; - private static final short sseed = 3; + private static final short data; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -102,10 +117,13 @@ public static class TestShort { // 257 can't be encoded as "base + offset" mode into the instruction field. UNSAFE.putShortUnaligned(BYTES, 257, rawdata); + sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 257)); // 253 can be encoded into simm9 field. - UNSAFE.putShortUnaligned(BYTES, 253, (short) (rawdata + sseed)); + UNSAFE.putShortUnaligned(BYTES, 253, sres); + sres = (short) (sres + UNSAFE.getShortUnaligned(BYTES, 253)); // 272 can be encoded into uimm12 field. - UNSAFE.putShortUnaligned(BYTES, 272, (short) (rawdata - sseed)); + UNSAFE.putShortUnaligned(BYTES, 272, sres); + data = UNSAFE.getShortUnaligned(BYTES, 272); } } @@ -114,7 +132,7 @@ public static class TestByte { private static final byte[] BYTES = new byte[LEN]; private static final byte rawdata = (byte)0x3f; - private static final byte bseed = 4; + private static final byte data; static { sink(2); // Signed immediate byte offset: range -256 to 255 @@ -123,34 +141,29 @@ public static class TestByte { // 272 can be encoded into simm9 field. UNSAFE.putByte(BYTES, 272, rawdata); + bres = (byte) (bres + UNSAFE.getByte(BYTES, 272)); // 53 can be encoded into simm9 field. - UNSAFE.putByte(BYTES, 53, (byte) (rawdata + bseed)); + UNSAFE.putByte(BYTES, 53, bres); + bres = (byte) (bres + UNSAFE.getByte(BYTES, 53)); // 1027 can be encoded into uimm12 field. - UNSAFE.putByte(BYTES, 1027, (byte) (rawdata - bseed)); + UNSAFE.putByte(BYTES, 1027, bres); + data = UNSAFE.getByte(BYTES, 1027); } } static void test() { TestLong ta = new TestLong(); - Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 1030), ta.rawdata, "putUnaligned long failed!"); - Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 127), ta.rawdata + ta.lseed, "putUnaligned long failed!"); - Asserts.assertEquals(UNSAFE.getLongUnaligned(ta.BYTES, 1096), ta.rawdata - ta.lseed, "putUnaligned long failed!"); + Asserts.assertEquals(ta.data, (ta.rawdata + lseed) * 2, "putUnaligned long failed!"); TestInt tb = new TestInt(); - Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 274), tb.rawdata, "putUnaligned int failed!"); - Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 255), tb.rawdata + tb.iseed, "putUnaligned int failed!"); - Asserts.assertEquals(UNSAFE.getIntUnaligned(tb.BYTES, 528), tb.rawdata - tb.iseed, "putUnaligned int failed!"); + Asserts.assertEquals(tb.data, (tb.rawdata + iseed) * 2, "putUnaligned int failed!"); TestShort tc = new TestShort(); - Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 257), tc.rawdata, "putUnaligned short failed!"); - Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 253), (short) (tc.rawdata + tc.sseed), "putUnaligned short failed!"); - Asserts.assertEquals(UNSAFE.getShortUnaligned(tc.BYTES, 272), (short) (tc.rawdata - tc.sseed), "putUnaligned short failed!"); + Asserts.assertEquals(tc.data, (short) (((short) (tc.rawdata + sseed)) * 2), "putUnaligned short failed!"); TestByte td = new TestByte(); - Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 272), td.rawdata, "put byte failed!"); - Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 53), (byte) (td.rawdata + td.bseed), "put byte failed!"); - Asserts.assertEquals(UNSAFE.getByte(td.BYTES, 1027), (byte) (td.rawdata - td.bseed), "put byte failed!"); + Asserts.assertEquals(td.data, (byte) (((byte) (td.rawdata + bseed)) * 2), "put byte failed!"); } public static void main(String[] strArr) { From 81ebbb2463df8b014bb209dc4028668fc78e8327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 7 Oct 2024 08:28:18 +0000 Subject: [PATCH 168/188] 8341525: G1: use bit clearing to remove tightly-coupled initialization store pre-barriers Reviewed-by: mdoerr, kbarrett, shade, tschatzl --- src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 8e17d1d2a7a4e..4ec7e10cd9a86 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -332,7 +332,8 @@ Node* G1BarrierSetC2::store_at_resolved(C2Access& access, C2AccessValue& val) co if (tightly_coupled_alloc) { assert(!use_ReduceInitialCardMarks(), "post-barriers are only needed for tightly-coupled initialization stores when ReduceInitialCardMarks is disabled"); - access.set_barrier_data(access.barrier_data() ^ G1C2BarrierPre); + // Pre-barriers are unnecessary for tightly-coupled initialization stores. + access.set_barrier_data(access.barrier_data() & ~G1C2BarrierPre); } } return BarrierSetC2::store_at_resolved(access, val); From 747a3fa31d9a9512475615c91d2ee9c2d2a94e8e Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 7 Oct 2024 08:39:44 +0000 Subject: [PATCH 169/188] 8341562: RISC-V: Generate comments in -XX:+PrintInterpreter to link to source code Reviewed-by: fyang, luhenry --- src/hotspot/cpu/riscv/methodHandles_riscv.cpp | 5 ++-- .../templateInterpreterGenerator_riscv.cpp | 27 ++++++++++++------- src/hotspot/cpu/riscv/templateTable_riscv.cpp | 3 ++- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp index 280ae6062a946..f638db9f0bfe4 100644 --- a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -28,6 +28,7 @@ #include "asm/macroAssembler.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/vmClasses.hpp" +#include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/interpreterRuntime.hpp" #include "memory/allocation.inline.hpp" @@ -37,7 +38,7 @@ #include "runtime/frame.inline.hpp" #include "runtime/stubRoutines.hpp" -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> #ifdef PRODUCT #define BLOCK_COMMENT(str) /* nothing */ diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp index 1f32488777d57..7c811aa3a0c26 100644 --- a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -27,6 +27,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" #include "classfile/javaClasses.hpp" +#include "compiler/disassembler.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "interpreter/bytecodeHistogram.hpp" #include "interpreter/bytecodeTracer.hpp" @@ -70,7 +71,7 @@ // Max size with JVMTI int TemplateInterpreter::InterpreterCodeSize = 256 * 1024; -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> //----------------------------------------------------------------------------- @@ -1748,13 +1749,21 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address& vep) { assert(t != nullptr && t->is_valid() && t->tos_in() == vtos, "illegal template"); Label L; - aep = __ pc(); __ push_ptr(); __ j(L); - fep = __ pc(); __ push_f(); __ j(L); - dep = __ pc(); __ push_d(); __ j(L); - lep = __ pc(); __ push_l(); __ j(L); - bep = cep = sep = - iep = __ pc(); __ push_i(); - vep = __ pc(); + aep = __ pc(); // atos entry point + __ push_ptr(); + __ j(L); + fep = __ pc(); // ftos entry point + __ push_f(); + __ j(L); + dep = __ pc(); // dtos entry point + __ push_d(); + __ j(L); + lep = __ pc(); // ltos entry point + __ push_l(); + __ j(L); + bep = cep = sep = iep = __ pc(); // [bcsi]tos entry point + __ push_i(); + vep = __ pc(); // vtos entry point __ bind(L); generate_and_dispatch(t); } diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 2e6902180a892..2fede262057ce 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.inline.hpp" +#include "compiler/disassembler.hpp" #include "gc/shared/barrierSetAssembler.hpp" #include "gc/shared/collectedHeap.hpp" #include "gc/shared/tlab_globals.hpp" @@ -49,7 +50,7 @@ #include "runtime/synchronizer.hpp" #include "utilities/powerOfTwo.hpp" -#define __ _masm-> +#define __ Disassembler::hook(__FILE__, __LINE__, _masm)-> // Address computation: local variables From 28977972a0129892543222eada4dc99f4cd62574 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Mon, 7 Oct 2024 09:32:40 +0000 Subject: [PATCH 170/188] 8340880: RISC-V: add t3-t6 alias into assemler_riscv.hpp Reviewed-by: luhenry, fyang --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 4 ++++ src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 20 +++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index d1021d9e283d2..a8675907907e7 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -143,6 +143,10 @@ constexpr Register x19_sender_sp = x19; // Sender's SP while in interpreter constexpr Register t0 = x5; constexpr Register t1 = x6; constexpr Register t2 = x7; +constexpr Register t3 = x28; +constexpr Register t4 = x29; +constexpr Register t5 = x30; +constexpr Register t6 = x31; const Register g_INTArgReg[Argument::n_int_register_parameters_c] = { c_rarg0, c_rarg1, c_rarg2, c_rarg3, c_rarg4, c_rarg5, c_rarg6, c_rarg7 diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 8bf3ac5c90163..bc2816147a0d0 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -4482,7 +4482,7 @@ class StubGenerator: public StubCodeGenerator { RegSet reg_cache_saved_regs = RegSet::of(x24, x25, x26, x27); // s8, s9, s10, s11 RegSet reg_cache_regs; reg_cache_regs += reg_cache_saved_regs; - reg_cache_regs += RegSet::of(x28, x29, x30, x31); // t3, t4, t5, t6 + reg_cache_regs += RegSet::of(t3, t4, t5, t6); BufRegCache reg_cache(_masm, reg_cache_regs); RegSet saved_regs; @@ -5462,8 +5462,8 @@ class StubGenerator: public StubCodeGenerator { Register isMIME = c_rarg6; Register codec = c_rarg7; - Register dstBackup = x31; - Register length = x28; // t3, total length of src data in bytes + Register dstBackup = t6; + Register length = t3; // total length of src data in bytes Label ProcessData, Exit; Label ProcessScalar, ScalarLoop; @@ -5498,7 +5498,7 @@ class StubGenerator: public StubCodeGenerator { Register stepSrcM1 = send; Register stepSrcM2 = doff; Register stepDst = isURL; - Register size = x29; // t4 + Register size = t4; __ mv(size, MaxVectorSize * 2); __ mv(stepSrcM1, MaxVectorSize * 4); @@ -5550,7 +5550,7 @@ class StubGenerator: public StubCodeGenerator { // scalar version { Register byte0 = soff, byte1 = send, byte2 = doff, byte3 = isURL; - Register combined32Bits = x29; // t5 + Register combined32Bits = t4; // encoded: [byte0[5:0] : byte1[5:0] : byte2[5:0]] : byte3[5:0]] => // plain: [byte0[5:0]+byte1[5:4] : byte1[3:0]+byte2[5:2] : byte2[1:0]+byte3[5:0]] @@ -5708,10 +5708,10 @@ class StubGenerator: public StubCodeGenerator { Register nmax = c_rarg4; Register base = c_rarg5; Register count = c_rarg6; - Register temp0 = x28; // t3 - Register temp1 = x29; // t4 - Register temp2 = x30; // t5 - Register temp3 = x31; // t6 + Register temp0 = t3; + Register temp1 = t4; + Register temp2 = t5; + Register temp3 = t6; VectorRegister vzero = v31; VectorRegister vbytes = v8; // group: v8, v9, v10, v11 @@ -6102,7 +6102,7 @@ static const int64_t right_3_bits = right_n_bits(3); __ kernel_crc32(crc, buf, len, c_rarg3, c_rarg4, c_rarg5, c_rarg6, // tmp's for tables - c_rarg7, t2, x28, x29, x30, x31); // misc tmps + c_rarg7, t2, t3, t4, t5, t6); // misc tmps __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(); From 520060f79a3cedb8f93e6bbd0e9b2823eaabf79a Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Mon, 7 Oct 2024 12:44:42 +0000 Subject: [PATCH 171/188] 8340799: Add border inside instruction frame in PassFailJFrame Reviewed-by: prr, dnguyen --- .../awt/regtesthelpers/PassFailJFrame.java | 60 +++++++++++++++---- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index feb5da43a5ced..9fc3abe4b7d83 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -24,6 +24,7 @@ import java.awt.AWTException; import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Font; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; @@ -69,6 +70,7 @@ import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.Timer; +import javax.swing.border.Border; import javax.swing.text.JTextComponent; import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; @@ -655,6 +657,8 @@ private static JComponent createInstructionUIPanel(String instructions, boolean addLogArea, int logAreaRows) { JPanel main = new JPanel(new BorderLayout()); + main.setBorder(createFrameBorder()); + timeoutHandlerPanel = new TimeoutHandlerPanel(testTimeOut); main.add(timeoutHandlerPanel, BorderLayout.NORTH); @@ -664,7 +668,7 @@ private static JComponent createInstructionUIPanel(String instructions, text.setEditable(false); JPanel textPanel = new JPanel(new BorderLayout()); - textPanel.setBorder(createEmptyBorder(4, 0, 0, 0)); + textPanel.setBorder(createEmptyBorder(GAP, 0, GAP, 0)); textPanel.add(new JScrollPane(text), BorderLayout.CENTER); main.add(textPanel, BorderLayout.CENTER); @@ -681,7 +685,8 @@ private static JComponent createInstructionUIPanel(String instructions, timeoutHandlerPanel.stop(); }); - JPanel buttonsPanel = new JPanel(); + JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, + GAP, 0)); buttonsPanel.add(btnPass); buttonsPanel.add(btnFail); @@ -692,10 +697,12 @@ private static JComponent createInstructionUIPanel(String instructions, if (addLogArea) { logArea = new JTextArea(logAreaRows, columns); logArea.setEditable(false); + logArea.setBorder(createTextBorder()); Box buttonsLogPanel = Box.createVerticalBox(); buttonsLogPanel.add(buttonsPanel); + buttonsLogPanel.add(Box.createVerticalStrut(GAP)); buttonsLogPanel.add(new JScrollPane(logArea)); main.add(buttonsLogPanel, BorderLayout.SOUTH); @@ -713,7 +720,7 @@ private static JTextComponent configurePlainText(String instructions, JTextArea text = new JTextArea(instructions, rows, columns); text.setLineWrap(true); text.setWrapStyleWord(true); - text.setBorder(createEmptyBorder(4, 4, 4, 4)); + text.setBorder(createTextBorder()); return text; } @@ -735,6 +742,29 @@ private static JTextComponent configureHTML(String instructions, return text; } + /** A default gap between components. */ + private static final int GAP = 4; + + /** + * Creates a default border for frames or dialogs. + * It uses the default gap of {@value GAP}. + * + * @return the border for frames and dialogs + */ + private static Border createFrameBorder() { + return createEmptyBorder(GAP, GAP, GAP, GAP); + } + + /** + * Creates a border set to text area. + * It uses the default gap of {@value GAP}. + * + * @return the border for text area + */ + private static Border createTextBorder() { + return createEmptyBorder(GAP, GAP, GAP, GAP); + } + /** * Creates a test UI window. @@ -1086,26 +1116,30 @@ public void awaitAndCheck() throws InterruptedException, InvocationTargetExcepti * Requests the description of the test failure reason from the tester. */ private static void requestFailureReason() { - final JDialog dialog = new JDialog(frame, "Test Failure ", true); - dialog.setTitle("Failure reason"); - JPanel jPanel = new JPanel(new BorderLayout()); - JTextArea jTextArea = new JTextArea(5, 20); + final JDialog dialog = new JDialog(frame, "Failure reason", true); + + JTextArea reason = new JTextArea(5, 20); + reason.setBorder(createTextBorder()); JButton okButton = new JButton("OK"); okButton.addActionListener((ae) -> { - String text = jTextArea.getText(); + String text = reason.getText(); setFailureReason(FAILURE_REASON + (!text.isEmpty() ? text : EMPTY_REASON)); dialog.setVisible(false); }); - jPanel.add(new JScrollPane(jTextArea), BorderLayout.CENTER); - - JPanel okayBtnPanel = new JPanel(); + JPanel okayBtnPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, + GAP, 0)); + okayBtnPanel.setBorder(createEmptyBorder(GAP, 0, 0, 0)); okayBtnPanel.add(okButton); - jPanel.add(okayBtnPanel, BorderLayout.SOUTH); - dialog.add(jPanel); + JPanel main = new JPanel(new BorderLayout()); + main.setBorder(createFrameBorder()); + main.add(new JScrollPane(reason), BorderLayout.CENTER); + main.add(okayBtnPanel, BorderLayout.SOUTH); + + dialog.add(main); dialog.setLocationRelativeTo(frame); dialog.pack(); dialog.setVisible(true); From 4ba170c403ae85576f84dafd4a157ba0db99873f Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Mon, 7 Oct 2024 12:45:04 +0000 Subject: [PATCH 172/188] 8341235: Improve default instruction frame title in PassFailJFrame Reviewed-by: prr --- .../awt/regtesthelpers/PassFailJFrame.java | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 9fc3abe4b7d83..41c5fdf8ccdbf 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -45,6 +45,7 @@ import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -289,9 +290,15 @@ */ public final class PassFailJFrame { - private static final String TITLE = "Test Instruction Frame"; + /** A default title for the instruction frame. */ + private static final String TITLE = "Test Instructions"; + + /** A default test timeout. */ private static final long TEST_TIMEOUT = 5; + + /** A default number of rows for displaying the test instructions. */ private static final int ROWS = 10; + /** A default number of columns for displaying the test instructions. */ private static final int COLUMNS = 40; /** @@ -304,7 +311,7 @@ public final class PassFailJFrame { */ private static final String FAILURE_REASON = "Failure Reason:\n"; /** - * The failure reason message when the user didn't provide one. + * The failure reason message when the user doesn't provide one. */ private static final String EMPTY_REASON = "(no reason provided)"; @@ -1824,9 +1831,41 @@ public PassFailJFrame build() throws InterruptedException, return new PassFailJFrame(this); } + /** + * Returns the file name of the test, if the {@code test.file} property + * is defined, concatenated with {@code " - "} which serves as a prefix + * to the default instruction frame title; + * or an empty string if the {@code test.file} property is not defined. + * + * @return the prefix to the default title: + * either the file name of the test or an empty string + * + * @see jtreg + * test-specific system properties and environment variables + */ + private static String getTestFileNamePrefix() { + String testFile = System.getProperty("test.file"); + if (testFile == null) { + return ""; + } + + return Paths.get(testFile).getFileName().toString() + + " - "; + } + + /** + * Validates the state of the builder and + * expands parameters that have no assigned values + * to their default values. + * + * @throws IllegalStateException if no instructions are provided, + * or if {@code PositionWindows} implementation is + * provided but neither window creator nor + * test window list are set + */ private void validate() { if (title == null) { - title = TITLE; + title = getTestFileNamePrefix() + TITLE; } if (instructions == null || instructions.isEmpty()) { From a2372c607c940589f239d4e59b675d3b2e626fd9 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Mon, 7 Oct 2024 13:26:16 +0000 Subject: [PATCH 173/188] 8341238: G1: Refactor G1Policy to move collection set selection methods into G1CollectionSet Reviewed-by: tschatzl, mli --- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 232 ++++++++++++++++++-- src/hotspot/share/gc/g1/g1CollectionSet.hpp | 16 ++ src/hotspot/share/gc/g1/g1Policy.cpp | 213 ------------------ src/hotspot/share/gc/g1/g1Policy.hpp | 24 +- 4 files changed, 236 insertions(+), 249 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index d315497268f99..ec90fd377503d 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -26,7 +26,7 @@ #include "gc/g1/g1Analytics.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" -#include "gc/g1/g1CollectionSetCandidates.hpp" +#include "gc/g1/g1CollectionSetCandidates.inline.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" #include "gc/g1/g1HeapRegionRemSet.inline.hpp" @@ -346,20 +346,16 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { G1CollectionCandidateRegionList pinned_retained_regions; if (collector_state()->in_mixed_phase()) { - time_remaining_ms = _policy->select_candidates_from_marking(&candidates()->marking_regions(), - time_remaining_ms, - &initial_old_regions, - &_optional_old_regions, - &pinned_marking_regions); + time_remaining_ms = select_candidates_from_marking(time_remaining_ms, + &initial_old_regions, + &pinned_marking_regions); } else { log_debug(gc, ergo, cset)("Do not add marking candidates to collection set due to pause type."); } - _policy->select_candidates_from_retained(&candidates()->retained_regions(), - time_remaining_ms, - &initial_old_regions, - &_optional_old_regions, - &pinned_retained_regions); + select_candidates_from_retained(time_remaining_ms, + &initial_old_regions, + &pinned_retained_regions); // Move initially selected old regions to collection set directly. move_candidates_to_collection_set(&initial_old_regions); @@ -394,6 +390,215 @@ void G1CollectionSet::move_candidates_to_collection_set(G1CollectionCandidateReg candidates()->remove(regions); } +static void print_finish_message(const char* reason, bool from_marking) { + log_debug(gc, ergo, cset)("Finish adding %s candidates to collection set (%s).", + from_marking ? "marking" : "retained", reason); +} + +double G1CollectionSet::select_candidates_from_marking(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions) { + uint num_expensive_regions = 0; + + uint num_initial_regions_selected = 0; + uint num_optional_regions_selected = 0; + uint num_pinned_regions = 0; + + double predicted_initial_time_ms = 0.0; + double predicted_optional_time_ms = 0.0; + + double optional_threshold_ms = time_remaining_ms * _policy->optional_prediction_fraction(); + + const uint min_old_cset_length = _policy->calc_min_old_cset_length(candidates()->last_marking_candidates_length()); + const uint max_old_cset_length = MAX2(min_old_cset_length, _policy->calc_max_old_cset_length()); + const uint max_optional_regions = max_old_cset_length - min_old_cset_length; + bool check_time_remaining = _policy->use_adaptive_young_list_length(); + + G1CollectionCandidateList* marking_list = &candidates()->marking_regions(); + assert(marking_list != nullptr, "must be"); + + log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. " + "Min %u regions, max %u regions, available %u regions" + "time remaining %1.2fms, optional threshold %1.2fms", + min_old_cset_length, max_old_cset_length, marking_list->length(), time_remaining_ms, optional_threshold_ms); + + G1CollectionCandidateListIterator iter = marking_list->begin(); + for (; iter != marking_list->end(); ++iter) { + if (num_initial_regions_selected + num_optional_regions_selected >= max_old_cset_length) { + // Added maximum number of old regions to the CSet. + print_finish_message("Maximum number of regions reached", true); + break; + } + G1HeapRegion* hr = (*iter)->_r; + // Skip evacuating pinned marking regions because we are not getting any free + // space from them (and we expect to get free space from marking candidates). + // Also prepare to move them to retained regions to be evacuated optionally later + // to not impact the mixed phase too much. + if (hr->has_pinned_objects()) { + num_pinned_regions++; + (*iter)->update_num_unreclaimed(); + log_trace(gc, ergo, cset)("Marking candidate %u can not be reclaimed currently. Skipping.", hr->hrm_index()); + pinned_old_regions->append(hr); + continue; + } + double predicted_time_ms = _policy->predict_region_total_time_ms(hr, false); + time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); + // Add regions to old set until we reach the minimum amount + if (initial_old_regions->length() < min_old_cset_length) { + initial_old_regions->append(hr); + num_initial_regions_selected++; + predicted_initial_time_ms += predicted_time_ms; + // Record the number of regions added with no time remaining + if (time_remaining_ms == 0.0) { + num_expensive_regions++; + } + } else if (!check_time_remaining) { + // In the non-auto-tuning case, we'll finish adding regions + // to the CSet if we reach the minimum. + print_finish_message("Region amount reached min", true); + break; + } else { + // Keep adding regions to old set until we reach the optional threshold + if (time_remaining_ms > optional_threshold_ms) { + predicted_initial_time_ms += predicted_time_ms; + initial_old_regions->append(hr); + num_initial_regions_selected++; + } else if (time_remaining_ms > 0) { + // Keep adding optional regions until time is up. + assert(_optional_old_regions.length() < max_optional_regions, "Should not be possible."); + predicted_optional_time_ms += predicted_time_ms; + _optional_old_regions.append(hr); + num_optional_regions_selected++; + } else { + print_finish_message("Predicted time too high", true); + break; + } + } + } + if (iter == marking_list->end()) { + log_debug(gc, ergo, cset)("Marking candidates exhausted."); + } + + if (num_expensive_regions > 0) { + log_debug(gc, ergo, cset)("Added %u marking candidates to collection set although the predicted time was too high.", + num_expensive_regions); + } + + log_debug(gc, ergo, cset)("Finish adding marking candidates to collection set. Initial: %u, optional: %u, pinned: %u, " + "predicted initial time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2fms", + num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, + predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms); + + assert(initial_old_regions->length() == num_initial_regions_selected, "must be"); + assert(_optional_old_regions.length() == num_optional_regions_selected, "must be"); + return time_remaining_ms; +} + +void G1CollectionSet::select_candidates_from_retained(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions) { + uint num_initial_regions_selected = 0; + uint num_optional_regions_selected = 0; + uint num_expensive_regions_selected = 0; + uint num_pinned_regions = 0; + + double predicted_initial_time_ms = 0.0; + double predicted_optional_time_ms = 0.0; + + uint const min_regions = _policy->min_retained_old_cset_length(); + // We want to make sure that on the one hand we process the retained regions asap, + // but on the other hand do not take too many of them as optional regions. + // So we split the time budget into budget we will unconditionally take into the + // initial old regions, and budget for taking optional regions from the retained + // list. + double optional_time_remaining_ms = _policy->max_time_for_retaining(); + time_remaining_ms = MIN2(time_remaining_ms, optional_time_remaining_ms); + + G1CollectionCandidateList* retained_list = &candidates()->retained_regions(); + + log_debug(gc, ergo, cset)("Start adding retained candidates to collection set. " + "Min %u regions, available %u, " + "time remaining %1.2fms, optional remaining %1.2fms", + min_regions, retained_list->length(), time_remaining_ms, optional_time_remaining_ms); + + for (G1CollectionSetCandidateInfo* ci : *retained_list) { + G1HeapRegion* r = ci->_r; + double predicted_time_ms = _policy->predict_region_total_time_ms(r, collector_state()->in_young_only_phase()); + bool fits_in_remaining_time = predicted_time_ms <= time_remaining_ms; + // If we can't reclaim that region ignore it for now. + if (r->has_pinned_objects()) { + num_pinned_regions++; + if (ci->update_num_unreclaimed()) { + log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Skipping.", r->hrm_index()); + } else { + log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Dropping.", r->hrm_index()); + pinned_old_regions->append(r); + } + continue; + } + + if (fits_in_remaining_time || (num_expensive_regions_selected < min_regions)) { + predicted_initial_time_ms += predicted_time_ms; + if (!fits_in_remaining_time) { + num_expensive_regions_selected++; + } + initial_old_regions->append(r); + num_initial_regions_selected++; + } else if (predicted_time_ms <= optional_time_remaining_ms) { + predicted_optional_time_ms += predicted_time_ms; + _optional_old_regions.append(r); + num_optional_regions_selected++; + } else { + // Fits neither initial nor optional time limit. Exit. + break; + } + time_remaining_ms = MAX2(0.0, time_remaining_ms - predicted_time_ms); + optional_time_remaining_ms = MAX2(0.0, optional_time_remaining_ms - predicted_time_ms); + } + + uint num_regions_selected = num_initial_regions_selected + num_optional_regions_selected; + if (num_regions_selected == retained_list->length()) { + log_debug(gc, ergo, cset)("Retained candidates exhausted."); + } + if (num_expensive_regions_selected > 0) { + log_debug(gc, ergo, cset)("Added %u retained candidates to collection set although the predicted time was too high.", + num_expensive_regions_selected); + } + + log_debug(gc, ergo, cset)("Finish adding retained candidates to collection set. Initial: %u, optional: %u, pinned: %u, " + "predicted initial time: %1.2fms, predicted optional time: %1.2fms, " + "time remaining: %1.2fms optional time remaining %1.2fms", + num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, + predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms, optional_time_remaining_ms); +} + +void G1CollectionSet::select_candidates_from_optional_regions(double time_remaining_ms, + G1CollectionCandidateRegionList* selected_regions) { + assert(optional_region_length() > 0, + "Should only be called when there are optional regions"); + + double total_prediction_ms = 0.0; + + for (G1HeapRegion* r : _optional_old_regions) { + double prediction_ms = _policy->predict_region_total_time_ms(r, false); + + if (prediction_ms > time_remaining_ms) { + log_debug(gc, ergo, cset)("Prediction %.3fms for region %u does not fit remaining time: %.3fms.", + prediction_ms, r->hrm_index(), time_remaining_ms); + break; + } + // This region will be included in the next optional evacuation. + + total_prediction_ms += prediction_ms; + time_remaining_ms -= prediction_ms; + + selected_regions->append(r); + } + + log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Total predicted time: %.3fms", + selected_regions->length(), _optional_old_regions.length(), total_prediction_ms); +} + void G1CollectionSet::prepare_optional_regions(G1CollectionCandidateRegionList* regions){ uint cur_index = 0; for (G1HeapRegion* r : *regions) { @@ -441,9 +646,8 @@ bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_ti update_incremental_marker(); G1CollectionCandidateRegionList selected_regions; - _policy->calculate_optional_collection_set_regions(&_optional_old_regions, - remaining_pause_time, - &selected_regions); + select_candidates_from_optional_regions(remaining_pause_time, + &selected_regions); move_candidates_to_collection_set(&selected_regions); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index e569d3ee966c3..5280ba7d0fd6c 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -196,6 +196,22 @@ class G1CollectionSet { // and retained collection set candidates. void finalize_old_part(double time_remaining_ms); + // Calculate and fill in the initial, optional and pinned old gen candidate regions from + // the given candidate list and the remaining time. + // Returns the remaining time. + double select_candidates_from_marking(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions); + + void select_candidates_from_retained(double time_remaining_ms, + G1CollectionCandidateRegionList* initial_old_regions, + G1CollectionCandidateRegionList* pinned_old_regions); + + // Calculate the number of optional regions from the given collection set candidates, + // the remaining time and the maximum number of these regions. + void select_candidates_from_optional_regions(double time_remaining_ms, + G1CollectionCandidateRegionList* selected); + // Iterate the part of the collection set given by the offset and length applying the given // G1HeapRegionClosure. The worker_id will determine where in the part to start the iteration // to allow for more efficient parallel iteration. diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index e7e57c962c734..6d0864f032c86 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -1467,219 +1467,6 @@ uint G1Policy::calc_max_old_cset_length() const { return (uint)ceil(result); } -static void print_finish_message(const char* reason, bool from_marking) { - log_debug(gc, ergo, cset)("Finish adding %s candidates to collection set (%s).", - from_marking ? "marking" : "retained", reason); -} - -double G1Policy::select_candidates_from_marking(G1CollectionCandidateList* marking_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions) { - assert(marking_list != nullptr, "must be"); - - uint num_expensive_regions = 0; - - uint num_initial_regions_selected = 0; - uint num_optional_regions_selected = 0; - uint num_pinned_regions = 0; - - double predicted_initial_time_ms = 0.0; - double predicted_optional_time_ms = 0.0; - - double optional_threshold_ms = time_remaining_ms * optional_prediction_fraction(); - - const uint min_old_cset_length = calc_min_old_cset_length(candidates()->last_marking_candidates_length()); - const uint max_old_cset_length = MAX2(min_old_cset_length, calc_max_old_cset_length()); - const uint max_optional_regions = max_old_cset_length - min_old_cset_length; - bool check_time_remaining = use_adaptive_young_list_length(); - - log_debug(gc, ergo, cset)("Start adding marking candidates to collection set. " - "Min %u regions, max %u regions, available %u regions" - "time remaining %1.2fms, optional threshold %1.2fms", - min_old_cset_length, max_old_cset_length, marking_list->length(), time_remaining_ms, optional_threshold_ms); - - G1CollectionCandidateListIterator iter = marking_list->begin(); - for (; iter != marking_list->end(); ++iter) { - if (num_initial_regions_selected + num_optional_regions_selected >= max_old_cset_length) { - // Added maximum number of old regions to the CSet. - print_finish_message("Maximum number of regions reached", true); - break; - } - G1HeapRegion* hr = (*iter)->_r; - // Skip evacuating pinned marking regions because we are not getting any free - // space from them (and we expect to get free space from marking candidates). - // Also prepare to move them to retained regions to be evacuated optionally later - // to not impact the mixed phase too much. - if (hr->has_pinned_objects()) { - num_pinned_regions++; - (*iter)->update_num_unreclaimed(); - log_trace(gc, ergo, cset)("Marking candidate %u can not be reclaimed currently. Skipping.", hr->hrm_index()); - pinned_old_regions->append(hr); - continue; - } - double predicted_time_ms = predict_region_total_time_ms(hr, false); - time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); - // Add regions to old set until we reach the minimum amount - if (initial_old_regions->length() < min_old_cset_length) { - initial_old_regions->append(hr); - num_initial_regions_selected++; - predicted_initial_time_ms += predicted_time_ms; - // Record the number of regions added with no time remaining - if (time_remaining_ms == 0.0) { - num_expensive_regions++; - } - } else if (!check_time_remaining) { - // In the non-auto-tuning case, we'll finish adding regions - // to the CSet if we reach the minimum. - print_finish_message("Region amount reached min", true); - break; - } else { - // Keep adding regions to old set until we reach the optional threshold - if (time_remaining_ms > optional_threshold_ms) { - predicted_initial_time_ms += predicted_time_ms; - initial_old_regions->append(hr); - num_initial_regions_selected++; - } else if (time_remaining_ms > 0) { - // Keep adding optional regions until time is up. - assert(optional_old_regions->length() < max_optional_regions, "Should not be possible."); - predicted_optional_time_ms += predicted_time_ms; - optional_old_regions->append(hr); - num_optional_regions_selected++; - } else { - print_finish_message("Predicted time too high", true); - break; - } - } - } - if (iter == marking_list->end()) { - log_debug(gc, ergo, cset)("Marking candidates exhausted."); - } - - if (num_expensive_regions > 0) { - log_debug(gc, ergo, cset)("Added %u marking candidates to collection set although the predicted time was too high.", - num_expensive_regions); - } - - log_debug(gc, ergo, cset)("Finish adding marking candidates to collection set. Initial: %u, optional: %u, pinned: %u, " - "predicted initial time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2fms", - num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, - predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms); - - assert(initial_old_regions->length() == num_initial_regions_selected, "must be"); - assert(optional_old_regions->length() == num_optional_regions_selected, "must be"); - return time_remaining_ms; -} - -void G1Policy::select_candidates_from_retained(G1CollectionCandidateList* retained_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions) { - - uint const min_regions = min_retained_old_cset_length(); - - uint num_initial_regions_selected = 0; - uint num_optional_regions_selected = 0; - uint num_expensive_regions_selected = 0; - uint num_pinned_regions = 0; - - double predicted_initial_time_ms = 0.0; - double predicted_optional_time_ms = 0.0; - - // We want to make sure that on the one hand we process the retained regions asap, - // but on the other hand do not take too many of them as optional regions. - // So we split the time budget into budget we will unconditionally take into the - // initial old regions, and budget for taking optional regions from the retained - // list. - double optional_time_remaining_ms = max_time_for_retaining(); - time_remaining_ms = MIN2(time_remaining_ms, optional_time_remaining_ms); - - log_debug(gc, ergo, cset)("Start adding retained candidates to collection set. " - "Min %u regions, available %u, " - "time remaining %1.2fms, optional remaining %1.2fms", - min_regions, retained_list->length(), time_remaining_ms, optional_time_remaining_ms); - - for (G1CollectionSetCandidateInfo* ci : *retained_list) { - G1HeapRegion* r = ci->_r; - double predicted_time_ms = predict_region_total_time_ms(r, collector_state()->in_young_only_phase()); - bool fits_in_remaining_time = predicted_time_ms <= time_remaining_ms; - // If we can't reclaim that region ignore it for now. - if (r->has_pinned_objects()) { - num_pinned_regions++; - if (ci->update_num_unreclaimed()) { - log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Skipping.", r->hrm_index()); - } else { - log_trace(gc, ergo, cset)("Retained candidate %u can not be reclaimed currently. Dropping.", r->hrm_index()); - pinned_old_regions->append(r); - } - continue; - } - - if (fits_in_remaining_time || (num_expensive_regions_selected < min_regions)) { - predicted_initial_time_ms += predicted_time_ms; - if (!fits_in_remaining_time) { - num_expensive_regions_selected++; - } - initial_old_regions->append(r); - num_initial_regions_selected++; - } else if (predicted_time_ms <= optional_time_remaining_ms) { - predicted_optional_time_ms += predicted_time_ms; - optional_old_regions->append(r); - num_optional_regions_selected++; - } else { - // Fits neither initial nor optional time limit. Exit. - break; - } - time_remaining_ms = MAX2(0.0, time_remaining_ms - predicted_time_ms); - optional_time_remaining_ms = MAX2(0.0, optional_time_remaining_ms - predicted_time_ms); - } - - uint num_regions_selected = num_initial_regions_selected + num_optional_regions_selected; - if (num_regions_selected == retained_list->length()) { - log_debug(gc, ergo, cset)("Retained candidates exhausted."); - } - if (num_expensive_regions_selected > 0) { - log_debug(gc, ergo, cset)("Added %u retained candidates to collection set although the predicted time was too high.", - num_expensive_regions_selected); - } - - log_debug(gc, ergo, cset)("Finish adding retained candidates to collection set. Initial: %u, optional: %u, pinned: %u, " - "predicted initial time: %1.2fms, predicted optional time: %1.2fms, " - "time remaining: %1.2fms optional time remaining %1.2fms", - num_initial_regions_selected, num_optional_regions_selected, num_pinned_regions, - predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms, optional_time_remaining_ms); -} - -void G1Policy::calculate_optional_collection_set_regions(G1CollectionCandidateRegionList* optional_regions, - double time_remaining_ms, - G1CollectionCandidateRegionList* selected_regions) { - assert(_collection_set->optional_region_length() > 0, - "Should only be called when there are optional regions"); - - double total_prediction_ms = 0.0; - - for (G1HeapRegion* r : *optional_regions) { - double prediction_ms = predict_region_total_time_ms(r, false); - - if (prediction_ms > time_remaining_ms) { - log_debug(gc, ergo, cset)("Prediction %.3fms for region %u does not fit remaining time: %.3fms.", - prediction_ms, r->hrm_index(), time_remaining_ms); - break; - } - // This region will be included in the next optional evacuation. - - total_prediction_ms += prediction_ms; - time_remaining_ms -= prediction_ms; - - selected_regions->append(r); - } - - log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Total predicted time: %.3fms", - selected_regions->length(), optional_regions->length(), total_prediction_ms); -} - void G1Policy::transfer_survivors_to_cset(const G1SurvivorRegions* survivors) { start_adding_survivor_regions(); diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 98d444084678c..9a6ffb570be70 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -335,27 +335,7 @@ class G1Policy: public CHeapObj { // Amount of allowed waste in bytes in the collection set. size_t allowed_waste_in_collection_set() const; - // Calculate and fill in the initial, optional and pinned old gen candidate regions from - // the given candidate list and the remaining time. - // Returns the remaining time. - double select_candidates_from_marking(G1CollectionCandidateList* marking_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions); - - void select_candidates_from_retained(G1CollectionCandidateList* retained_list, - double time_remaining_ms, - G1CollectionCandidateRegionList* initial_old_regions, - G1CollectionCandidateRegionList* optional_old_regions, - G1CollectionCandidateRegionList* pinned_old_regions); - - // Calculate the number of optional regions from the given collection set candidates, - // the remaining time and the maximum number of these regions and return the number - // of actually selected regions in num_optional_regions. - void calculate_optional_collection_set_regions(G1CollectionCandidateRegionList* optional_old_regions, - double time_remaining_ms, - G1CollectionCandidateRegionList* selected); + private: @@ -423,12 +403,12 @@ class G1Policy: public CHeapObj { size_t desired_survivor_size(uint max_regions) const; +public: // Fraction used when predicting how many optional regions to include in // the CSet. This fraction of the available time is used for optional regions, // the rest is used to add old regions to the normal CSet. double optional_prediction_fraction() const { return 0.2; } -public: // Fraction used when evacuating the optional regions. This fraction of the // remaining time is used to choose what regions to include in the evacuation. double optional_evacuation_fraction() const { return 0.75; } From 3359518986bd12b0d97e5df5b0154d0539639818 Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 7 Oct 2024 16:28:02 +0000 Subject: [PATCH 174/188] 8341593: Problemlist java/foreign/TestUpcallStress.java in Xcomp mode Reviewed-by: jvernee --- test/jdk/ProblemList-Xcomp.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 2fc09ee4df4a9..988b95a1b3507 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -29,4 +29,5 @@ java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all java/lang/management/MemoryMXBean/CollectionUsageThreshold.java 8318668 generic-all +java/foreign/TestUpcallStress.java 8341584 generic-all com/sun/jdi/InterruptHangTest.java 8043571 generic-all From d0c5e4bc50cc2cbb65efe827ae8cf3e077f45e07 Mon Sep 17 00:00:00 2001 From: Alexander Zvegintsev Date: Mon, 7 Oct 2024 16:32:01 +0000 Subject: [PATCH 175/188] 8341373: Open source closed frame tests # 4 Reviewed-by: prr --- .../awt/Frame/AddRemoveMenuBarTest_5.java | 120 ++++++++++++++++++ .../java/awt/Frame/FrameResizableTest.java | 97 ++++++++++++++ test/jdk/java/awt/Frame/I18NTitle.java | 65 ++++++++++ .../jdk/java/awt/Frame/MenuBarOffsetTest.java | 81 ++++++++++++ test/jdk/java/awt/Frame/MinimumSizeTest.java | 114 +++++++++++++++++ 5 files changed, 477 insertions(+) create mode 100644 test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java create mode 100644 test/jdk/java/awt/Frame/FrameResizableTest.java create mode 100644 test/jdk/java/awt/Frame/I18NTitle.java create mode 100644 test/jdk/java/awt/Frame/MenuBarOffsetTest.java create mode 100644 test/jdk/java/awt/Frame/MinimumSizeTest.java diff --git a/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java b/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java new file mode 100644 index 0000000000000..f5f1018c26282 --- /dev/null +++ b/test/jdk/java/awt/Frame/AddRemoveMenuBarTest_5.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Robot; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/* + * @test + * @key headful + * @bug 4159883 + * @summary Adding/Removing a menu causes frame to unexpected small size + * @requires (os.family == "linux" | os.family == "windows") + */ + +public class AddRemoveMenuBarTest_5 { + + static Frame frame; + static MenuBar menu; + static Button btnAdd, btnRemove; + static Dimension oldSize; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(AddRemoveMenuBarTest_5::initAndShowGui); + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(() -> { + oldSize = frame.getSize(); + changeMenubar(true); + }); + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(() -> { + checkSize(); + changeMenubar(false); + }); + robot.waitForIdle(); + robot.delay(500); + + EventQueue.invokeAndWait(AddRemoveMenuBarTest_5::checkSize); + } finally { + EventQueue.invokeAndWait(frame::dispose); + } + } + + public static void initAndShowGui() { + frame = new Frame(); + frame.setLocationRelativeTo(null); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + System.out.println("Frame size:" + frame.getSize().toString()); + System.out.println("Button size:" + btnAdd.getSize().toString()); + } + }); + frame.add("West", btnAdd = new Button("TRY:ADD")); + frame.add("East", btnRemove = new Button("TRY:REMOVE")); + + + btnAdd.addActionListener((e) -> changeMenubar(true)); + btnRemove.addActionListener((e) -> changeMenubar(false)); + frame.setSize(500, 100); + frame.setVisible(true); + } + + private static void changeMenubar(boolean enable) { + if (enable) { + menu = new MenuBar(); + menu.add(new Menu("BAAAAAAAAAAAAAAA")); + menu.add(new Menu("BZZZZZZZZZZZZZZZ")); + menu.add(new Menu("BXXXXXXXXXXXXXXX")); + } else { + menu = null; + } + frame.setMenuBar(menu); + frame.invalidate(); + frame.validate(); + + System.out.println("Frame size:" + frame.getSize().toString()); + System.out.println("Button size:" + btnAdd.getSize().toString()); + } + + private static void checkSize() { + Dimension newSize = frame.getSize(); + if (!oldSize.equals(newSize)) { + throw new RuntimeException("Frame size changed: old %s new %s" + .formatted(oldSize, newSize)); + } + } +} diff --git a/test/jdk/java/awt/Frame/FrameResizableTest.java b/test/jdk/java/awt/Frame/FrameResizableTest.java new file mode 100644 index 0000000000000..4734ce71670aa --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameResizableTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Panel; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 1231233 + * @summary Tests whether the resizable property of a Frame is + * respected after it is set. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameResizableTest + */ + +public class FrameResizableTest { + private static final String INSTRUCTIONS = """ + There is a frame with two buttons and a label. The label + reads 'true' or 'false' to indicate whether the frame can be + resized or not. + + When the first button, 'Set Resizable', is + clicked, you should be able to resize the frame. + When the second button, 'UnSet Resizable', is clicked, you should + not be able to resize the frame. + + A frame is resized in a way which depends upon the window manager (WM) running. + You may resize the frame by dragging the corner resize handles or the borders, + or you may use the title bar's resize menu items and buttons. + + Upon test completion, click Pass or Fail appropriately. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("FrameResizableTest Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(FrameResizable::new) + .build() + .awaitAndCheck(); + } + + private static class FrameResizable extends Frame { + Label label; + Button buttonResizable; + Button buttonNotResizable; + + public FrameResizable() { + super("FrameResizable"); + setResizable(false); + Panel panel = new Panel(); + + add("North", panel); + ActionListener actionListener = (e) -> { + if (e.getSource() == buttonResizable) { + setResizable(true); + } else if (e.getSource() == buttonNotResizable) { + setResizable(false); + } + label.setText("Resizable: " + isResizable()); + }; + + panel.add(buttonResizable = new Button("Set Resizable")); + panel.add(buttonNotResizable = new Button("UnSet Resizable")); + panel.add(label = new Label("Resizable: " + isResizable())); + buttonResizable.addActionListener(actionListener); + buttonNotResizable.addActionListener(actionListener); + + setSize(400, 200); + } + } +} diff --git a/test/jdk/java/awt/Frame/I18NTitle.java b/test/jdk/java/awt/Frame/I18NTitle.java new file mode 100644 index 0000000000000..7127fc3dfbf6b --- /dev/null +++ b/test/jdk/java/awt/Frame/I18NTitle.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Window; + +/* + * @test + * @bug 6269884 4929291 + * @summary Tests that title which contains mix of non-English characters is displayed correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual I18NTitle + */ + +public class I18NTitle { + private static final String INSTRUCTIONS = """ + You will see a frame with some title (S. Chinese, Cyrillic and German). + Please check if non-English characters are visible and compare + the visible title with the same string shown in the label + (it should not look worse than the label). + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("I18NTitle Instructions") + .instructions(INSTRUCTIONS) + .columns(50) + .testUI(I18NTitle::createAndShowGUI) + .build() + .awaitAndCheck(); + } + + private static Window createAndShowGUI() { + String s = "\u4e2d\u6587\u6d4b\u8bd5 \u0420\u0443\u0441\u0441\u043a\u0438\u0439 Zur\u00FCck"; + Frame frame = new Frame(s); + frame.setLayout(new BorderLayout()); + Label l = new Label(s); + frame.add(l); + frame.setSize(400, 100); + return frame; + } +} diff --git a/test/jdk/java/awt/Frame/MenuBarOffsetTest.java b/test/jdk/java/awt/Frame/MenuBarOffsetTest.java new file mode 100644 index 0000000000000..65a4a8ef4bd59 --- /dev/null +++ b/test/jdk/java/awt/Frame/MenuBarOffsetTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Menu; +import java.awt.MenuBar; + +/* + * @test + * @bug 4180577 + * @summary offset problems with menus in frames: (2 * 1) should be (2 * menuBarBorderSize) + * @requires (os.family == "linux" | os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MenuBarOffsetTest +*/ + +public class MenuBarOffsetTest { + private static final String INSTRUCTIONS = """ + If a menubar containing a menubar item labeled Test appears. + in a frame, and fits within the frame, press Pass, else press Fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("MenuBarOffsetTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(FrameTest::new) + .build() + .awaitAndCheck(); + } + + private static class FrameTest extends Frame { + public FrameTest() { + super("MenuBarOffsetTest FrameTest"); + MenuBar m = new MenuBar(); + setMenuBar(m); + Menu test = m.add(new Menu("Test")); + test.add("1"); + test.add("2"); + setSize(100, 100); + } + + public void paint(Graphics g) { + setForeground(Color.red); + Insets i = getInsets(); + Dimension d = getSize(); + System.err.println(getBounds()); + System.err.println("" + i); + + g.drawRect(i.left, i.top, + d.width - i.left - i.right - 1, + d.height - i.top - i.bottom - 1); + } + } +} diff --git a/test/jdk/java/awt/Frame/MinimumSizeTest.java b/test/jdk/java/awt/Frame/MinimumSizeTest.java new file mode 100644 index 0000000000000..cfff77be5f93c --- /dev/null +++ b/test/jdk/java/awt/Frame/MinimumSizeTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.imageio.ImageIO; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +/* + * @test + * @key headful + * @bug 1256759 + * @summary Checks that Frames with a very small size don't cause Motif + * to generate VendorShells which consume the entire desktop. + */ + +public class MinimumSizeTest { + + private static final Color BG_COLOR = Color.RED; + private static Frame backgroundFrame; + private static Frame testedFrame; + + private static Robot robot; + private static final Point location = new Point(200, 200); + private static final Point[] testPointLocations = { + new Point(100, 200), + new Point(200, 100), + new Point(450, 210), + new Point(210, 350), + }; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + + try { + EventQueue.invokeAndWait(MinimumSizeTest::initAndShowGui); + robot.waitForIdle(); + robot.delay(500); + test(); + System.out.println("Test passed."); + } finally { + EventQueue.invokeAndWait(() -> { + backgroundFrame.dispose(); + testedFrame.dispose(); + }); + } + } + + private static void test() { + for (Point testLocation : testPointLocations) { + Color pixelColor = robot.getPixelColor(testLocation.x, testLocation.y); + + if (!pixelColor.equals(BG_COLOR)) { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + BufferedImage screenCapture = robot.createScreenCapture(new Rectangle(screenSize)); + try { + ImageIO.write(screenCapture, "png", new File("failure.png")); + } catch (IOException ignored) {} + throw new RuntimeException("Pixel color does not match expected color %s at %s" + .formatted(pixelColor, testLocation)); + } + } + } + + private static void initAndShowGui() { + backgroundFrame = new Frame("MinimumSizeTest background"); + backgroundFrame.setUndecorated(true); + backgroundFrame.setBackground(BG_COLOR); + backgroundFrame.setBounds(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())); + backgroundFrame.setVisible(true); + + testedFrame = new MinimumSizeTestFrame(); + testedFrame.setVisible(true); + } + + private static class MinimumSizeTestFrame extends Frame { + public MinimumSizeTestFrame() { + super("MinimumSizeTest"); + setVisible(true); + setBackground(Color.BLUE); + setSize(0, 0); + setLocation(location); + } + } +} + From f7bb647dc88f835fe819e7ab0434c931f243304a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Mon, 7 Oct 2024 16:34:08 +0000 Subject: [PATCH 176/188] 8341595: Clean up iteration of CEN headers in ZipFile.Source.initCEN Reviewed-by: lancea, redestad --- .../share/classes/java/util/zip/ZipFile.java | 28 +- .../java/util/zip/ZipFile/CenSizeMaximum.java | 246 ++++++++++++++++++ 2 files changed, 261 insertions(+), 13 deletions(-) create mode 100644 test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 43b2261f1c60a..a6b6dce1a14ef 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1239,12 +1239,12 @@ private int checkAndAddEntry(int pos, int index) int nlen = CENNAM(cen, pos); int elen = CENEXT(cen, pos); int clen = CENCOM(cen, pos); - long headerSize = (long)CENHDR + nlen + clen + elen; + int headerSize = CENHDR + nlen + clen + elen; // CEN header size + name length + comment length + extra length // should not exceed 65,535 bytes per the PKWare APP.NOTE // 4.4.10, 4.4.11, & 4.4.12. Also check that current CEN header will // not exceed the length of the CEN array - if (headerSize > 0xFFFF || pos + headerSize > cen.length) { + if (headerSize > 0xFFFF || pos > cen.length - headerSize) { zerror("invalid CEN header (bad header size)"); } @@ -1768,18 +1768,18 @@ private void initCEN(int knownTotal) throws IOException { // Iterate through the entries in the central directory int idx = 0; // Index into the entries array int pos = 0; - int entryPos = CENHDR; - int limit = cen.length; manifestNum = 0; - while (entryPos <= limit) { + int limit = cen.length - CENHDR; + while (pos <= limit) { if (idx >= entriesLength) { // This will only happen if the ZIP file has an incorrect // ENDTOT field, which usually means it contains more than // 65535 entries. - initCEN(countCENHeaders(cen, limit)); + initCEN(countCENHeaders(cen)); return; } + int entryPos = pos + CENHDR; // Checks the entry and adds values to entries[idx ... idx+2] int nlen = checkAndAddEntry(pos, idx); idx += 3; @@ -1810,7 +1810,6 @@ private void initCEN(int knownTotal) throws IOException { } // skip to the start of the next entry pos = nextEntryPos(pos, entryPos, nlen); - entryPos = pos + CENHDR; } // Adjust the total entries @@ -2034,17 +2033,20 @@ private int getMetaVersion(int off, int len) { /** * Returns the number of CEN headers in a central directory. - * Will not throw, even if the ZIP file is corrupt. * * @param cen copy of the bytes in a ZIP file's central directory - * @param size number of bytes in central directory + * @throws ZipException if a CEN header exceeds the length of the CEN array */ - private static int countCENHeaders(byte[] cen, int size) { + private static int countCENHeaders(byte[] cen) throws ZipException { int count = 0; - for (int p = 0; - p + CENHDR <= size; - p += CENHDR + CENNAM(cen, p) + CENEXT(cen, p) + CENCOM(cen, p)) + for (int p = 0; p <= cen.length - CENHDR;) { + int headerSize = CENHDR + CENNAM(cen, p) + CENEXT(cen, p) + CENCOM(cen, p); + if (p > cen.length - headerSize) { + zerror("invalid CEN header (bad header size)"); + } + p += headerSize; count++; + } return count; } } diff --git a/test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java b/test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java new file mode 100644 index 0000000000000..a63464eb72b88 --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/CenSizeMaximum.java @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8341595 + * @modules java.base/jdk.internal.util + * @summary Verify that ZipFile can read from a ZIP file with a maximally large CEN size + * @run junit/othervm/manual -Xmx2500M CenSizeMaximum + */ + +import jdk.internal.util.ArraysSupport; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.*; + +public class CenSizeMaximum { + + // Maximum allowed CEN size allowed by the ZipFile implementation + static final int MAX_CEN_SIZE = ArraysSupport.SOFT_MAX_ARRAY_LENGTH; + + /** + * From the APPNOTE.txt specification: + * 4.4.10 file name length: (2 bytes) + * 4.4.11 extra field length: (2 bytes) + * 4.4.12 file comment length: (2 bytes) + * + * The length of the file name, extra field, and comment + * fields respectively. The combined length of any + * directory record and these three fields SHOULD NOT + * generally exceed 65,535 bytes. + *. + * Create a maximum extra field which does not exceed 65,535 bytes + */ + static final int MAX_EXTRA_FIELD_SIZE = 65_535 - ZipFile.CENHDR; + + // Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings' + static final short UNKNOWN_ZIP_TAG = (short) 0x9902; + + // The size of one CEN header, including the name and the extra field + static final int CEN_HEADER_SIZE = ZipFile.CENHDR + MAX_EXTRA_FIELD_SIZE; + + // The size of the extra data field header (tag id + data block length) + static final int EXTRA_FIELD_HEADER_SIZE = 2 * Short.BYTES; + + // Zip file to create for testing + private Path hugeZipFile = Path.of("cen-size-on-limit.zip"); + + /** + * Clean up ZIP file created in this test + */ + @AfterEach + public void cleanup() throws IOException { + //Files.deleteIfExists(hugeZipFile); + } + + /** + * Validates that ZipFile opens a ZIP file with a CEN size close + * to the {@link #MAX_CEN_SIZE} implementation limit. + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + public void maximumCenSize() throws IOException { + int numCenHeaders = zipWithWithExactCenSize(MAX_CEN_SIZE, true, false); + try (var zf = new ZipFile(hugeZipFile.toFile())) { + assertEquals(numCenHeaders, zf.size()); + } + } + + /** + * Validates that ZipFile rejects a ZIP where the last CEN record + * overflows the CEN size and the END header CENTOT field is smaller + * than the actual number of headers + * + * @throws IOException if an unexpected IO error occurs + */ + @Test + public void lastCENHeaderBadSize() throws IOException { + int numCenHeaders = zipWithWithExactCenSize(1024, true, true); + ZipException zipException = assertThrows(ZipException.class, () -> { + try (var zf = new ZipFile(hugeZipFile.toFile())) { + assertEquals(numCenHeaders, zf.size()); + } + }); + assertEquals("invalid CEN header (bad header size)", zipException.getMessage()); + + } + + /** + * Produce a ZIP file with an exact CEN size. To minimize the number of CEN headers + * written, maximally large, empty extra data blocks are written sparsely. + * + * @param cenSize the exact CEN size of the ZIP file to produce + * @param invalidateEndTotal whether to decrement the END header's TOT field by one + * @return the number of CEN headers produced + * @throws IOException if an unexpected IO error occurs + */ + private int zipWithWithExactCenSize(long cenSize, boolean invalidateEndTotal, boolean overflowLastCEN) + throws IOException { + // Sanity check + assertTrue(cenSize <= MAX_CEN_SIZE); + + // The number of CEN headers we need to write + int numCenHeaders = (int) (cenSize / CEN_HEADER_SIZE) + 1; + // Size if all extra data fields were of maximum size + long overSized = numCenHeaders * (long) CEN_HEADER_SIZE; + // Length to trim from the first CEN's extra data + int negativPadding = (int) (overSized - cenSize); + int firstExtraSize = MAX_EXTRA_FIELD_SIZE - negativPadding; + + // Sanity check + long computedCenSize = (numCenHeaders -1L ) * CEN_HEADER_SIZE + ZipEntry.CENHDR + firstExtraSize; + assertEquals(computedCenSize, cenSize); + + // A CEN header, followed by the four-bytes extra data header + ByteBuffer cenHeader = createCENHeader(); + // An END header + ByteBuffer endHeader = createENDHeader(); + // Update the END header + if (invalidateEndTotal) { + // To trigger countCENHeaders + endHeader.putShort(ZipEntry.ENDTOT, (short) (numCenHeaders -1 & 0xFFFF)); + } else { + endHeader.putShort(ZipEntry.ENDTOT, (short) (numCenHeaders & 0xFFFF)); + } + // Update CEN size and offset fields + endHeader.putInt(ZipEntry.ENDSIZ, (int) (cenSize & 0xFFFFFFFFL)); + endHeader.putInt(ZipEntry.ENDOFF, 0); + + // When creating a sparse file, the file must not already exit + Files.deleteIfExists(hugeZipFile); + + // Open a FileChannel for writing a sparse file + EnumSet options = EnumSet.of(StandardOpenOption.CREATE_NEW, + StandardOpenOption.WRITE, + StandardOpenOption.SPARSE); + + try (FileChannel channel = FileChannel.open(hugeZipFile, options)) { + // Write CEN headers + for (int i = 0; i < numCenHeaders; i++) { + // The first CEN header has trimmed extra data + int extraSize = i == 0 ? firstExtraSize : MAX_EXTRA_FIELD_SIZE; + if (overflowLastCEN && i == numCenHeaders - 1) { + // make last CEN header overflow the CEN size + cenHeader.putShort(ZipEntry.CENNAM, Short.MAX_VALUE); + } + // update elen field + cenHeader.putShort(ZipEntry.CENEXT, (short) (extraSize & 0xFFFF)); + // update data block len of the extra field header + short dlen = (short) ((extraSize - EXTRA_FIELD_HEADER_SIZE) & 0xFFFF); + cenHeader.putShort(ZipEntry.CENHDR + Short.BYTES, dlen); + // Write the CEN header plus the four-byte extra header + channel.write(cenHeader.rewind()); + // Sparse "write" of the extra data block + channel.position(channel.position() + extraSize - EXTRA_FIELD_HEADER_SIZE); + } + // Sanity check + assertEquals(cenSize, channel.position()); + // Write the END header + channel.write(endHeader.rewind()); + } + return numCenHeaders; + } + + // Creates a ByteBuffer representing a CEN header with a trailing extra field header + private ByteBuffer createCENHeader() throws IOException { + byte[] bytes = smallZipfile(); + ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + int endOff = bytes.length - ZipEntry.ENDHDR; + int cenSize = buf.getInt(endOff + ZipEntry.ENDSIZ); + int cenOff = buf.getInt(endOff + ZipEntry.ENDOFF); + return ByteBuffer.wrap( + Arrays.copyOfRange(bytes, cenOff, cenOff + ZipEntry.CENHDR + EXTRA_FIELD_HEADER_SIZE) + ).order(ByteOrder.LITTLE_ENDIAN); + } + + // Creates a ByteBuffer representing an END header + private ByteBuffer createENDHeader() throws IOException { + byte[] bytes = smallZipfile(); + ByteBuffer buf = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + int endOff = bytes.length - ZipEntry.ENDHDR; + return ByteBuffer.wrap( + Arrays.copyOfRange(bytes, endOff, endOff + ZipEntry.ENDHDR) + ).order(ByteOrder.LITTLE_ENDIAN); + } + + // Create a byte array with a minimal ZIP file + private static byte[] smallZipfile() throws IOException { + var out = new ByteArrayOutputStream(); + try (var zo = new ZipOutputStream(out)) { + ZipEntry entry = new ZipEntry(""); + entry.setExtra(makeDummyExtraField()); + zo.putNextEntry(entry); + } + return out.toByteArray(); + } + + // Create a minimally sized extra field + private static byte[] makeDummyExtraField() { + byte[] extra = new byte[EXTRA_FIELD_HEADER_SIZE]; + // Little-endian ByteBuffer for updating the header fields + ByteBuffer buffer = ByteBuffer.wrap(extra).order(ByteOrder.LITTLE_ENDIAN); + + // We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings' + buffer.putShort(UNKNOWN_ZIP_TAG); + + // Size of the actual (empty) data + buffer.putShort((short) 0); + return extra; + } +} From fc7244da96a9423146c4a46bcc3bbfc205900c3b Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Mon, 7 Oct 2024 17:42:17 +0000 Subject: [PATCH 177/188] 8340713: Open source DnD tests - Set5 Reviewed-by: azvegint, dnguyen --- test/jdk/ProblemList.txt | 3 + .../java/awt/dnd/DragExitBeforeDropTest.java | 257 ++++++++++++++++++ test/jdk/java/awt/dnd/DragThresholdTest.java | 134 +++++++++ .../java/awt/dnd/WinMoveFileToShellTest.java | 131 +++++++++ 4 files changed, 525 insertions(+) create mode 100644 test/jdk/java/awt/dnd/DragExitBeforeDropTest.java create mode 100644 test/jdk/java/awt/dnd/DragThresholdTest.java create mode 100644 test/jdk/java/awt/dnd/WinMoveFileToShellTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 12954e6174daa..1f96e2b0f426f 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -128,6 +128,8 @@ java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion.java 8060176 java/awt/event/MouseWheelEvent/InfiniteRecursion/InfiniteRecursion_1.java 8060176 windows-all,macosx-all java/awt/dnd/URIListBetweenJVMsTest/URIListBetweenJVMsTest.java 8171510 macosx-all java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java 8288839 windows-x64 +java/awt/dnd/DragExitBeforeDropTest.java 8242805 macosx-all +java/awt/dnd/DragThresholdTest.java 8076299 macosx-all java/awt/Focus/ChoiceFocus/ChoiceFocus.java 8169103 windows-all,macosx-all java/awt/Focus/ClearLwQueueBreakTest/ClearLwQueueBreakTest.java 8198618 macosx-all java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java 6986252 macosx-all @@ -806,3 +808,4 @@ java/awt/List/HandlingKeyEventIfMousePressedTest.java 6848358 macosx-all,windows java/awt/Checkbox/CheckboxBoxSizeTest.java 8340870 windows-all java/awt/Checkbox/CheckboxIndicatorSizeTest.java 8340870 windows-all java/awt/Checkbox/CheckboxNullLabelTest.java 8340870 windows-all +java/awt/dnd/WinMoveFileToShellTest.java 8341665 windows-all diff --git a/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java b/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java new file mode 100644 index 0000000000000..2ef778a18ba46 --- /dev/null +++ b/test/jdk/java/awt/dnd/DragExitBeforeDropTest.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/* + * @test + * @bug 4395290 + * @key headful + * @summary tests that dragExit() is not called before drop() + */ + +public class DragExitBeforeDropTest { + private static Frame frame; + private static final DragSourceButton dragSourceButton = new DragSourceButton(); + private static final DropTargetPanel dropTargetPanel = new DropTargetPanel(); + private static volatile Point srcPoint; + private static volatile Point dstPoint; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + EventQueue.invokeAndWait(DragExitBeforeDropTest::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point p = dragSourceButton.getLocationOnScreen(); + Dimension d = dragSourceButton.getSize(); + p.translate(d.width / 2, d.height / 2); + srcPoint = p; + + p = dropTargetPanel.getLocationOnScreen(); + d = dropTargetPanel.getSize(); + p.translate(d.width / 2, d.height / 2); + dstPoint = p; + }); + + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (; !srcPoint.equals(dstPoint); + srcPoint.translate(sign(dstPoint.x - srcPoint.x), + sign(dstPoint.y - srcPoint.y))) { + robot.mouseMove(srcPoint.x, srcPoint.y); + robot.delay(10); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + robot.delay(1000); + + if (!dropTargetPanel.getStatus()) { + throw new RuntimeException("The test failed: dragExit()" + + " is called before drop()"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + frame = new Frame("DragExitBeforeDropTest"); + frame.setLayout(new GridLayout(2, 1)); + frame.add(dragSourceButton); + frame.add(dropTargetPanel); + frame.setLocationRelativeTo(null); + frame.setSize(300, 400); + frame.setVisible(true); + } + + public static int sign(int n) { + return Integer.compare(n, 0); + } + + private static class DragSourceButton extends Button implements Serializable, + Transferable, + DragGestureListener, + DragSourceListener { + private final DataFlavor dataflavor = + new DataFlavor(Button.class, "DragSourceButton"); + + public DragSourceButton() { + this("DragSourceButton"); + } + + public DragSourceButton(String str) { + super(str); + + DragSource ds = DragSource.getDefaultDragSource(); + ds.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + dge.startDrag(null, this, this); + } + + public void dragEnter(DragSourceDragEvent dsde) {} + + public void dragExit(DragSourceEvent dse) {} + + public void dragOver(DragSourceDragEvent dsde) {} + + public void dragDropEnd(DragSourceDropEvent dsde) {} + + public void dropActionChanged(DragSourceDragEvent dsde) {} + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException { + + if (!isDataFlavorSupported(flavor)) { + throw new UnsupportedFlavorException(flavor); + } + + Object retObj; + + ByteArrayOutputStream baoStream = new ByteArrayOutputStream(); + ObjectOutputStream ooStream = new ObjectOutputStream(baoStream); + ooStream.writeObject(this); + + ByteArrayInputStream baiStream = + new ByteArrayInputStream(baoStream.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(baiStream); + try { + retObj = ois.readObject(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e.toString()); + } + + return retObj; + } + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[] { dataflavor }; + } + + public boolean isDataFlavorSupported(DataFlavor dflavor) { + return dataflavor.equals(dflavor); + } + } + + private static class DropTargetPanel extends Panel implements DropTargetListener { + + final Dimension preferredDimension = new Dimension(200, 100); + volatile boolean testPassed = true; + + public DropTargetPanel() { + setDropTarget(new DropTarget(this, this)); + } + + public boolean getStatus() { + return testPassed; + } + + public Dimension getPreferredSize() { + return preferredDimension; + } + + public void dragEnter(DropTargetDragEvent dtde) {} + + public void dragExit(DropTargetEvent dte) { + testPassed = false; + } + + public void dragOver(DropTargetDragEvent dtde) {} + + public void dropActionChanged(DropTargetDragEvent dtde) {} + + public void drop(DropTargetDropEvent dtde) { + DropTargetContext dtc = dtde.getDropTargetContext(); + + if ((dtde.getSourceActions() & DnDConstants.ACTION_COPY) != 0) { + dtde.acceptDrop(DnDConstants.ACTION_COPY); + } else { + dtde.rejectDrop(); + } + + DataFlavor[] dfs = dtde.getCurrentDataFlavors(); + Component comp = null; + + if(dfs != null && dfs.length >= 1) { + Transferable transfer = dtde.getTransferable(); + + try { + comp = (Component)transfer.getTransferData(dfs[0]); + } catch (Throwable e) { + e.printStackTrace(); + dtc.dropComplete(false); + } + } + dtc.dropComplete(true); + add(comp); + } + } +} + + + diff --git a/test/jdk/java/awt/dnd/DragThresholdTest.java b/test/jdk/java/awt/dnd/DragThresholdTest.java new file mode 100644 index 0000000000000..bcb3bbf91c2ce --- /dev/null +++ b/test/jdk/java/awt/dnd/DragThresholdTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; + +/* + @test + @key headful + @bug 4415175 + @summary tests DragSource.getDragThreshold() and + that the AWT default drag gesture recognizers + honor the drag gesture motion threshold +*/ + +public class DragThresholdTest { + private static Frame frame; + private static Panel panel; + private static MouseEvent lastMouseEvent; + private static volatile boolean failed; + private static volatile Point startPoint; + private static volatile Point endPoint; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + + EventQueue.invokeAndWait(DragThresholdTest::createAndShowDnD); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + Point p = panel.getLocationOnScreen(); + p.translate(50, 50); + startPoint = p; + endPoint = new Point(p.x + 2 * DragSource.getDragThreshold(), + p.y + 2 * DragSource.getDragThreshold()); + }); + + robot.mouseMove(startPoint.x, startPoint.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (Point p = new Point(startPoint); !p.equals(endPoint); + p.translate(sign(endPoint.x - p.x), + sign(endPoint.y - p.y))) { + robot.mouseMove(p.x, p.y); + robot.delay(100); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(200); + + if (failed) { + throw new RuntimeException("drag gesture recognized too early"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createAndShowDnD() { + frame = new Frame("DragThresholdTest"); + panel = new Panel(); + // Mouse motion listener mml is added to the panel first. + // We rely on it that this listener will be called first. + panel.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseDragged(MouseEvent evt) { + lastMouseEvent = evt; + System.out.println(evt); + } + }); + frame.add(panel); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + + DragGestureListener dgl = dge -> { + Point dragOrigin = dge.getDragOrigin(); + int diffx = Math.abs(dragOrigin.x - lastMouseEvent.getX()); + int diffy = Math.abs(dragOrigin.y - lastMouseEvent.getY()); + System.out.println("dragGestureRecognized(): " + + " diffx=" + diffx + " diffy=" + diffy + + " DragSource.getDragThreshold()=" + + DragSource.getDragThreshold()); + if (diffx <= DragSource.getDragThreshold() && + diffy <= DragSource.getDragThreshold()) { + failed = true; + System.out.println("drag gesture recognized too early!"); + } + }; + + // Default drag gesture recognizer is a mouse motion listener. + // It is added to the panel second. + new DragSource().createDefaultDragGestureRecognizer( + panel, + DnDConstants.ACTION_COPY_OR_MOVE, dgl); + frame.setVisible(true); + } + + private static int sign(int n) { + return Integer.compare(n, 0); + } +} diff --git a/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java b/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java new file mode 100644 index 0000000000000..5ae7dd3890d71 --- /dev/null +++ b/test/jdk/java/awt/dnd/WinMoveFileToShellTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceAdapter; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceListener; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/* + * @test + * @bug 4414739 + * @requires (os.family == "windows") + * @summary verifies that getDropSuccess() returns correct value for moving + a file from a Java drag source to the Windows shell + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual WinMoveFileToShellTest + */ + +public class WinMoveFileToShellTest { + private static final String INSTRUCTIONS = """ + Drag from the frame titled "Drag Frame" and drop on to Windows Desktop. + After Drag and Drop, check for "Drop Success" status in the log area. + If "Drop Success" is true press PASS else FAIL. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(WinMoveFileToShellTest::createAndShowUI) + .logArea(5) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame frame = new Frame("Drag Frame"); + final DragSourceListener dsl = new DragSourceAdapter() { + public void dragDropEnd(DragSourceDropEvent e) { + PassFailJFrame.log("Drop Success: " + e.getDropSuccess()); + } + }; + + DragGestureListener dgl = dge -> { + File file = new File(System.getProperty("test.classes", ".") + + File.separator + "move.me"); + try { + file.createNewFile(); + } catch (IOException exc) { + exc.printStackTrace(); + } + ArrayList list = new ArrayList<>(); + list.add(file); + dge.startDrag(null, new FileListSelection(list), dsl); + }; + + new DragSource().createDefaultDragGestureRecognizer(frame, + DnDConstants.ACTION_MOVE, dgl); + frame.setSize(200, 100); + return frame; + } + + private static class FileListSelection implements Transferable { + private static final int FL = 0; + + private static final DataFlavor[] flavors = + new DataFlavor[] { DataFlavor.javaFileListFlavor }; + + + private List data; + + public FileListSelection(List data) { + this.data = data; + } + + public DataFlavor[] getTransferDataFlavors() { + return flavors.clone(); + } + + public boolean isDataFlavorSupported(DataFlavor flavor) { + for (DataFlavor dataFlavor : flavors) { + if (flavor.equals(dataFlavor)) { + return true; + } + } + return false; + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, IOException + { + if (flavor.equals(flavors[FL])) { + return data; + } else { + throw new UnsupportedFlavorException(flavor); + } + } + } +} From 23f3ca254a2558ddaaf29714b0a5fc22daeed013 Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Mon, 7 Oct 2024 19:33:48 +0000 Subject: [PATCH 178/188] 8330206: Bump minimum boot jdk to JDK 23 Reviewed-by: darcy, iris, erikj --- make/conf/github-actions.conf | 20 ++++++++++---------- make/conf/jib-profiles.js | 4 ++-- make/conf/version-numbers.conf | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf index eca6c05033d88..a6b383daa8fd4 100644 --- a/make/conf/github-actions.conf +++ b/make/conf/github-actions.conf @@ -29,21 +29,21 @@ GTEST_VERSION=1.14.0 JTREG_VERSION=7.4+1 LINUX_X64_BOOT_JDK_EXT=tar.gz -LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_linux-x64_bin.tar.gz -LINUX_X64_BOOT_JDK_SHA256=41536f115668308ecf4eba92aaf6acaeb0936225828b741efd83b6173ba82963 +LINUX_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_linux-x64_bin.tar.gz +LINUX_X64_BOOT_JDK_SHA256=08fea92724127c6fa0f2e5ea0b07ff4951ccb1e2f22db3c21eebbd7347152a67 ALPINE_LINUX_X64_BOOT_JDK_EXT=tar.gz -ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin22-binaries/releases/download/jdk-22.0.2%2B9/OpenJDK22U-jdk_x64_alpine-linux_hotspot_22.0.2_9.tar.gz -ALPINE_LINUX_X64_BOOT_JDK_SHA256=49f73414824b1a7c268a611225fa4d7ce5e25600201e0f1cd59f94d1040b5264 +ALPINE_LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin23-binaries/releases/download/jdk-23%2B37/OpenJDK23U-jdk_x64_alpine-linux_hotspot_23_37.tar.gz +ALPINE_LINUX_X64_BOOT_JDK_SHA256=bff4c78f30d8d173e622bf2f40c36113df47337fc6d1ee5105ed2459841165aa MACOS_AARCH64_BOOT_JDK_EXT=tar.gz -MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_macos-aarch64_bin.tar.gz -MACOS_AARCH64_BOOT_JDK_SHA256=3dab98730234e1a87aec14bcb8171d2cae101e96ff4eed1dab96abbb08e843fd +MACOS_AARCH64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_macos-aarch64_bin.tar.gz +MACOS_AARCH64_BOOT_JDK_SHA256=9527bf080a74ae6dca51df413aa826f0c011c6048885e4c8ad112172be8815f3 MACOS_X64_BOOT_JDK_EXT=tar.gz -MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_macos-x64_bin.tar.gz -MACOS_X64_BOOT_JDK_SHA256=e8b3ec7a7077711223d31156e771f11723cd7af31c2017f1bd2eda20855940fb +MACOS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_macos-x64_bin.tar.gz +MACOS_X64_BOOT_JDK_SHA256=5c3a909fd2079d0e376dd43c85c4f7d02d08914866f196480bd47784b2a0121e WINDOWS_X64_BOOT_JDK_EXT=zip -WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk22.0.2/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-22.0.2_windows-x64_bin.zip -WINDOWS_X64_BOOT_JDK_SHA256=f2a9b9ab944e71a64637fcdc6b13a1188cf02d4eb9ecf71dc927e98b3e45f5dc +WINDOWS_X64_BOOT_JDK_URL=https://download.java.net/java/GA/jdk23/3c5b90190c68498b986a97f276efd28a/37/GPL/openjdk-23_windows-x64_bin.zip +WINDOWS_X64_BOOT_JDK_SHA256=cba5013874ba50cae543c86fe6423453816c77281e2751a8a9a633d966f1dc04 diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 30c45d4cde161..a85c20b2098ea 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -390,8 +390,8 @@ var getJibProfilesCommon = function (input, data) { }; }; - common.boot_jdk_version = "22"; - common.boot_jdk_build_number = "36"; + common.boot_jdk_version = "23"; + common.boot_jdk_build_number = "37"; common.boot_jdk_home = input.get("boot_jdk", "install_path") + "/jdk-" + common.boot_jdk_version + (input.build_os == "macosx" ? ".jdk/Contents/Home" : ""); diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 1d47c2cddd001..055f9ca886618 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -37,6 +37,6 @@ DEFAULT_VERSION_DATE=2025-03-18 DEFAULT_VERSION_CLASSFILE_MAJOR=68 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 -DEFAULT_ACCEPTABLE_BOOT_VERSIONS="22 23 24" +DEFAULT_ACCEPTABLE_BOOT_VERSIONS="23 24" DEFAULT_JDK_SOURCE_TARGET_VERSION=24 DEFAULT_PROMOTED_VERSION_PRE=ea From 4d50cbb5a73ad1f84ecd6a895045ecfdb0835adc Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Mon, 7 Oct 2024 21:29:21 +0000 Subject: [PATCH 179/188] 8341278: Open source few TrayIcon tests - Set7 Reviewed-by: azvegint --- test/jdk/ProblemList.txt | 2 + .../java/awt/TrayIcon/ClearPrevImageTest.java | 126 ++++++++++++++++ .../awt/TrayIcon/FocusLostAfterTrayTest.java | 136 ++++++++++++++++++ test/jdk/java/awt/TrayIcon/MouseMoveTest.java | 107 ++++++++++++++ .../awt/TrayIcon/TrayIconKeySelectTest.java | 122 ++++++++++++++++ 5 files changed, 493 insertions(+) create mode 100644 test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java create mode 100644 test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java create mode 100644 test/jdk/java/awt/TrayIcon/MouseMoveTest.java create mode 100644 test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1f96e2b0f426f..303e449e4a583 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -212,6 +212,8 @@ java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java 8150540,8295300 windows java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java 8150540 windows-all java/awt/TrayIcon/TrayIconPopup/TrayIconPopupClickTest.java 8150540 windows-all,macosx-all java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java 8150540 windows-all +java/awt/TrayIcon/MouseMoveTest.java 8203053 linux-all +java/awt/TrayIcon/TrayIconKeySelectTest.java 8341557 windows-all java/awt/Window/ShapedAndTranslucentWindows/SetShapeAndClick.java 8197936 macosx-all java/awt/Window/ShapedAndTranslucentWindows/SetShapeDynamicallyAndClick.java 8013450 macosx-all diff --git a/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java b/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java new file mode 100644 index 0000000000000..e97f645bec594 --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/ClearPrevImageTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6267936 + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary Tests that the previous image in TrayIcon is cleared + * when a new image is set + * @run main/manual ClearPrevImageTest + */ + +public class ClearPrevImageTest { + private static SystemTray tray; + private static TrayIcon icon; + private static final String INSTRUCTIONS = """ + This test checks that the previous image in TrayIcon is cleared + when a new image is set. + + When the test starts, a RED square TrayIcon is added + to the SystemTray (also, called Taskbar Status Area in MS Windows, + Notification Area in, GNOME and System Tray in KDE). + + You should see it change into YELLOW after 5 seconds. + If you still see RED TrayIcon after 5 seconds, + press FAIL, otherwise press PASS + """; + + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + + PassFailJFrame passFailJFrame + = PassFailJFrame.builder() + .title("TrayIcon Change Test Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .build(); + + EventQueue.invokeAndWait(ClearPrevImageTest::createAndShowTrayIcon); + try { + changeTrayIcon(); + passFailJFrame.awaitAndCheck(); + } catch (Exception e) { + throw new RuntimeException("Test failed: ", e); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static void createAndShowTrayIcon() { + Image img1 = createIcon(Color.RED); + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(img1); + icon.setImageAutoSize(true); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + } + + private static void changeTrayIcon() { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Image img2 = createIcon(Color.YELLOW); + icon.setImage(img2); + } + + private static Image createIcon(Color color) { + BufferedImage image = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setColor(color); + g.fillRect(0, 0, 16, 16); + g.dispose(); + return image; + } +} diff --git a/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java b/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java new file mode 100644 index 0000000000000..bd831ce94e4c0 --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/FocusLostAfterTrayTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.SystemTray; +import java.awt.TextArea; +import java.awt.TrayIcon; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6269309 + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary Tests that focus is transferred properly back + * to toplevel after clicking on a tray icon. + * @run main/manual FocusLostAfterTrayTest + */ + +public class FocusLostAfterTrayTest { + private static SystemTray tray; + private static TrayIcon icon; + + private static final String INSTRUCTIONS = """ + This test checks that focus is transferred properly back + to top-level after clicking on a tray icon. + + When the test starts, a Frame with a text area & a RED tray icon + are shown. If you don't see a tray icon please make sure that + the tray area (also called Taskbar Status Area on MS Windows + Notification Area on Gnome or System Tray on KDE) is visible. + + Click with a mouse inside a text area and make sure that it has + received input focus. Then click on the tray icon and then back + on the text area and verify that it has input focus again. Repeat + the last step several times. Ensure that the text area always + has the input focus and there are no "FOCUS LOST" event + for text area in the log section. + + If above is true, Press PASS, else FAIL. + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + + try { + PassFailJFrame.builder() + .title("FocusLostAfterTrayTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(FocusLostAfterTrayTest::createAndShowTrayIcon) + .logArea() + .build() + .awaitAndCheck(); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static Frame createAndShowTrayIcon() { + Frame frame = new Frame("FocusLostAfterTrayTest"); + frame.setBounds(100, 300, 200, 200); + frame.setLayout(new BorderLayout()); + TextArea ta = new TextArea(); + ta.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + PassFailJFrame.log("FOCUS GAINED: " + + e.getComponent().getClass().toString()); + } + @Override + public void focusLost(FocusEvent e) { + PassFailJFrame.log("FOCUS LOST !! " + + e.getComponent().getClass().toString()); + } + }); + frame.add(ta); + + BufferedImage image = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics2D g = image.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setColor(Color.RED); + g.fillRect(0, 0, 16, 16); + g.dispose(); + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(image); + icon.setImageAutoSize(true); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + return frame; + } +} diff --git a/test/jdk/java/awt/TrayIcon/MouseMoveTest.java b/test/jdk/java/awt/TrayIcon/MouseMoveTest.java new file mode 100644 index 0000000000000..51d80ff127b1b --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/MouseMoveTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6267980 + * @summary PIT:Spurious MouseMoved events are triggered by Tray Icon + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @run main/manual MouseMoveTest + */ + +public class MouseMoveTest { + private static SystemTray tray; + private static TrayIcon icon; + private static final String INSTRUCTIONS = """ + 1) You will see a tray icon (white square) in notification area, + 2) Move mouse pointer to the icon and leave it somewhere inside the icon, + 3) Verify that MOUSE_MOVE events are NOT triggered after you have STOPPED + moving mouse. + 4) If events are still triggered Press FAIL else PASS. + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + + PassFailJFrame passFailJFrame + = PassFailJFrame.builder() + .title("TrayIcon Change Test Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .logArea() + .build(); + + try { + EventQueue.invokeAndWait(MouseMoveTest::createAndShowTrayIcon); + passFailJFrame.awaitAndCheck(); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static void createAndShowTrayIcon() { + BufferedImage img = new BufferedImage(32, 32, + BufferedImage.TYPE_INT_ARGB); + Graphics g = img.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, 32, 32); + g.dispose(); + + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(img); + icon.setImageAutoSize(true); + + icon.addMouseMotionListener(new MouseMotionAdapter() { + public void mouseMoved(MouseEvent me){ + PassFailJFrame.log(me.toString()); + } + }); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + } +} diff --git a/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java b/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java new file mode 100644 index 0000000000000..5e41f54638236 --- /dev/null +++ b/test/jdk/java/awt/TrayIcon/TrayIconKeySelectTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AWTException; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.SystemTray; +import java.awt.TrayIcon; +import java.awt.image.BufferedImage; + +import jtreg.SkippedException; + +/* + * @test + * @bug 6267943 + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jtreg.SkippedException + * @summary Tests the possibility of selecting a tray icon with the keyboard. + * @run main/manual TrayIconKeySelectTest + */ + +public class TrayIconKeySelectTest { + private static SystemTray tray; + private static TrayIcon icon; + private static final String INSTRUCTIONS = """ + Tests that TrayIcon is selectable with the keyboard + When the test is started you will see three-color icon + in the system tray. + + 1. Bring the focus to the icon with TAB. Press ENTER key. + - One or more ActionEvent should be generated + (see the output area of the test) + + 2. Bring the focus again to the icon. Press SPACE key twice. + - One or more ActionEvent should be generated. + + 3. Bring the focus again to the icon. Click on the icon with + the LEFT mouse button twice. + - One or more ActionEvent should be generated. + + 4. Again bring the focus to the icon. Click on the icon with + the LEFT mouse button just once. + - NO ActionEvent should be generated. + + 5. Repeat the 4th step with other mouse buttons. + + If all the above are true press PASS, else FAIL + """; + + public static void main(String[] args) throws Exception { + if (!SystemTray.isSupported()) { + throw new SkippedException("Test not applicable as" + + " System Tray not supported"); + } + PassFailJFrame passFailJFrame; + try { + passFailJFrame + = PassFailJFrame.builder() + .title("TrayIconKeySelectTest Instructions") + .instructions(INSTRUCTIONS) + .columns(40) + .logArea() + .build(); + + EventQueue.invokeAndWait(TrayIconKeySelectTest::createAndShowTrayIcon); + passFailJFrame.awaitAndCheck(); + } finally { + EventQueue.invokeAndWait(() -> { + if (tray != null) { + tray.remove(icon); + } + }); + } + } + + private static void createAndShowTrayIcon() { + BufferedImage im = new BufferedImage(16, 16, + BufferedImage.TYPE_INT_ARGB); + Graphics gr = im.createGraphics(); + gr.setColor(Color.white); + gr.fillRect(0, 0, 16, 5); + gr.setColor(Color.blue); + gr.fillRect(0, 5, 16, 10); + gr.setColor(Color.red); + gr.fillRect(0, 10, 16, 16); + gr.dispose(); + + tray = SystemTray.getSystemTray(); + icon = new TrayIcon(im); + icon.setImageAutoSize(true); + icon.addActionListener(e -> PassFailJFrame.log(e.toString())); + + try { + tray.add(icon); + } catch (AWTException e) { + throw new RuntimeException("Error while adding" + + " icon to system tray", e); + } + } +} From d996ca863deef50ba7c1c8878cc4c202fa1a9d6b Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Mon, 7 Oct 2024 23:30:06 +0000 Subject: [PATCH 180/188] 8341581: Optimize BytecodeHelpers validate slot Reviewed-by: liach --- .../classfile/impl/BytecodeHelpers.java | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index 6994a62c0ab06..4f4e10217128a 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -88,9 +88,9 @@ public static Opcode aload(int slot) { case 2 -> Opcode.ALOAD_2; case 3 -> Opcode.ALOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ALOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ALOAD_W; throw slotOutOfBounds(slot); } @@ -104,9 +104,9 @@ public static Opcode fload(int slot) { case 2 -> Opcode.FLOAD_2; case 3 -> Opcode.FLOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.FLOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.FLOAD_W; throw slotOutOfBounds(slot); } @@ -120,9 +120,9 @@ public static Opcode dload(int slot) { case 2 -> Opcode.DLOAD_2; case 3 -> Opcode.DLOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.DLOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.DLOAD_W; throw slotOutOfBounds(slot); } @@ -136,9 +136,9 @@ public static Opcode lload(int slot) { case 2 -> Opcode.LLOAD_2; case 3 -> Opcode.LLOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.LLOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.LLOAD_W; throw slotOutOfBounds(slot); } @@ -152,9 +152,9 @@ public static Opcode iload(int slot) { case 2 -> Opcode.ILOAD_2; case 3 -> Opcode.ILOAD_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ILOAD; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ILOAD_W; throw slotOutOfBounds(slot); } @@ -180,9 +180,9 @@ public static Opcode astore(int slot) { case 2 -> Opcode.ASTORE_2; case 3 -> Opcode.ASTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ASTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ASTORE_W; throw slotOutOfBounds(slot); } @@ -196,9 +196,9 @@ public static Opcode fstore(int slot) { case 2 -> Opcode.FSTORE_2; case 3 -> Opcode.FSTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.FSTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.FSTORE_W; throw slotOutOfBounds(slot); } @@ -212,9 +212,9 @@ public static Opcode dstore(int slot) { case 2 -> Opcode.DSTORE_2; case 3 -> Opcode.DSTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.DSTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.DSTORE_W; throw slotOutOfBounds(slot); } @@ -228,9 +228,9 @@ public static Opcode lstore(int slot) { case 2 -> Opcode.LSTORE_2; case 3 -> Opcode.LSTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.LSTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.LSTORE_W; throw slotOutOfBounds(slot); } @@ -244,9 +244,9 @@ public static Opcode istore(int slot) { case 2 -> Opcode.ISTORE_2; case 3 -> Opcode.ISTORE_3; default -> { - if ((slot & 0xFF) == slot) + if ((slot & ~0xFF) == 0) yield Opcode.ISTORE; - if ((slot & 0xFFFF) == slot) + if ((slot & ~0xFFFF) == 0) yield Opcode.ISTORE_W; throw slotOutOfBounds(slot); } @@ -377,20 +377,20 @@ public static TypeKind convertToType(Opcode opcode) { public static void validateSlot(Opcode opcode, int slot, boolean load) { int size = opcode.sizeIfFixed(); if (size == 1 && slot == (load ? intrinsicLoadSlot(opcode) : intrinsicStoreSlot(opcode)) || - size == 2 && slot == (slot & 0xFF) || - size == 4 && slot == (slot & 0xFFFF)) + size == 2 && (slot & ~0xFF) == 0 || + size == 4 && (slot & ~0xFFFF) == 0) return; throw slotOutOfBounds(opcode, slot); } public static void validateSlot(int slot) { - if ((slot & 0xFFFF) != slot) + if ((slot & ~0xFFFF) != 0) throw slotOutOfBounds(slot); } public static boolean validateAndIsWideIinc(int slot, int val) { var ret = false; - if ((slot & 0xFF) != slot) { + if ((slot & ~0xFF) != 0) { validateSlot(slot); ret = true; } @@ -404,8 +404,8 @@ public static boolean validateAndIsWideIinc(int slot, int val) { } public static void validateRet(Opcode opcode, int slot) { - if (opcode == Opcode.RET && slot == (slot & 0xFF) || - opcode == Opcode.RET_W && slot == (slot & 0xFFFF)) + if (opcode == Opcode.RET && (slot & ~0xFF) == 0 || + opcode == Opcode.RET_W && (slot & ~0xFFFF) == 0) return; Objects.requireNonNull(opcode); throw slotOutOfBounds(opcode, slot); From 45a6359588996d25e5e8dadebdcd8d6a00ef786f Mon Sep 17 00:00:00 2001 From: William Kemper Date: Tue, 8 Oct 2024 01:26:16 +0000 Subject: [PATCH 181/188] 8341668: Shenandoah: assert(tail_bits < (idx_t)BitsPerWord) failed: precondition Reviewed-by: ysr --- src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp | 2 ++ .../share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp index 6b95303fb3341..55d21b06e4bbd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.hpp @@ -80,6 +80,8 @@ class ShenandoahSimpleBitMap { bool is_forward_consecutive_ones(idx_t start_idx, idx_t count) const; bool is_backward_consecutive_ones(idx_t last_idx, idx_t count) const; + static inline uintx tail_mask(uintx bit_number); + public: inline idx_t aligned_index(idx_t idx) const { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp index c047e1ed66349..4582ab9a781dd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.inline.hpp @@ -27,7 +27,7 @@ #include "gc/shenandoah/shenandoahSimpleBitMap.hpp" -inline uintx tail_mask(uintx bit_number) { +inline uintx ShenandoahSimpleBitMap::tail_mask(uintx bit_number) { if (bit_number >= BitsPerWord) { return -1; } From b6a4047387dbe4e07df0032dfdd7ee5ad8f571a4 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 8 Oct 2024 06:33:11 +0000 Subject: [PATCH 182/188] 8339982: Open source several AWT Mouse tests - Batch 2 Reviewed-by: psadhukhan --- test/jdk/ProblemList.txt | 1 + .../DefaultScreenDeviceTest.java | 116 ++++++++++ test/jdk/java/awt/Mouse/DoubleClickTest.java | 88 +++++++ test/jdk/java/awt/Mouse/MouseClickCount.java | 69 ++++++ .../awt/Mouse/MouseDragEnterExitTest.java | 117 ++++++++++ test/jdk/java/awt/Mouse/MouseDragTest.java | 215 ++++++++++++++++++ 6 files changed, 606 insertions(+) create mode 100644 test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java create mode 100644 test/jdk/java/awt/Mouse/DoubleClickTest.java create mode 100644 test/jdk/java/awt/Mouse/MouseClickCount.java create mode 100644 test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java create mode 100644 test/jdk/java/awt/Mouse/MouseDragTest.java diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 303e449e4a583..664a7ac02da93 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -437,6 +437,7 @@ java/awt/SplashScreen/MultiResolutionSplash/unix/UnixMultiResolutionSplashTest.j java/awt/Robot/AcceptExtraMouseButtons/AcceptExtraMouseButtons.java 7107528 linux-all,macosx-all java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java 8080676 linux-all java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersInKeyEvent.java 8157147 linux-all,windows-all,macosx-all +java/awt/Mouse/MouseClickCount.java 8017182 macosx-all java/awt/Toolkit/ToolkitPropertyTest/ToolkitPropertyTest_Enable.java 6847163 linux-all java/awt/xembed/server/RunTestXEmbed.java 7034201 linux-all java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsDocModalTest.java 8164473 linux-all diff --git a/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java b/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java new file mode 100644 index 0000000000000..b59460322daf6 --- /dev/null +++ b/test/jdk/java/awt/GraphicsEnvironment/DefaultScreenDeviceTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Color; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Label; +import java.awt.Rectangle; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.List; + +/* + * @test + * @bug 4473671 + * @summary Test to verify GraphicsEnvironment.getDefaultScreenDevice always + * returning first screen + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DefaultScreenDeviceTest + */ + +public class DefaultScreenDeviceTest { + private static Frame testFrame; + + public static void main(String[] args) throws Exception { + GraphicsEnvironment ge = GraphicsEnvironment. + getLocalGraphicsEnvironment(); + GraphicsDevice[] gds = ge.getScreenDevices(); + if (gds.length < 2) { + System.out.println("Test requires at least 2 displays"); + return; + } + + String INSTRUCTIONS = """ + 1. The test is for systems which allows primary display + selection in multiscreen systems. + Set the system primary screen to be the rightmost + (i.e. the right screen in two screen configuration) + This can be done by going to OS Display Settings + selecting the screen and checking the 'Use this device + as primary monitor' checkbox. + 2. When done, click on 'Frame on Primary Screen' button and + see where the frame will pop up + 3. If Primary Frame pops up on the primary display, + the test passed, otherwise it failed + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + private static List initialize() { + Frame frame = new Frame("Default screen device test"); + GraphicsConfiguration gc = + GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + + testFrame = new Frame("Primary screen frame", gc); + frame.setLayout(new BorderLayout()); + frame.setSize(200, 200); + + Button b = new Button("Frame on Primary Screen"); + b.addActionListener(e -> { + if (testFrame != null) { + testFrame.setVisible(false); + testFrame.dispose(); + } + + testFrame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e1) { + testFrame.setVisible(false); + testFrame.dispose(); + } + }); + testFrame.add(new Label("This frame should be on the primary screen")); + testFrame.setBackground(Color.red); + testFrame.pack(); + Rectangle rect = gc.getBounds(); + testFrame.setLocation(rect.x + 100, rect.y + 100); + testFrame.setVisible(true); + }); + frame.add(b); + return List.of(testFrame, frame); + } +} diff --git a/test/jdk/java/awt/Mouse/DoubleClickTest.java b/test/jdk/java/awt/Mouse/DoubleClickTest.java new file mode 100644 index 0000000000000..037332a40981e --- /dev/null +++ b/test/jdk/java/awt/Mouse/DoubleClickTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Event; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.TextArea; + +/* + * @test + * @bug 4092370 + * @summary Test to verify double click + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DoubleClickTest + */ + +public class DoubleClickTest { + static TextArea ta = new TextArea("", 10, 40); + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Double click on the red area. + 2. Verify that the event reports click_count > 1 on + Double-Click. If click_count shows only 1 for every + Double-Clicks then test FAILS, else test PASS. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame frame = new Frame("Double-click Test"); + frame.setLayout(new BorderLayout()); + frame.add("East", new MyPanel(ta)); + frame.add("West", ta); + frame.setSize(200, 200); + return frame; + } +} + +class MyPanel extends Panel { + TextArea ta; + + MyPanel(TextArea ta) { + this.ta = ta; + setBackground(Color.red); + } + + public Dimension getPreferredSize() { + return new Dimension(50, 50); + } + + + public boolean mouseDown(Event event, int x, int y) { + ta.append("event click count= " + event.clickCount + "\n"); + return false; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseClickCount.java b/test/jdk/java/awt/Mouse/MouseClickCount.java new file mode 100644 index 0000000000000..a63d24fcb9ffb --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseClickCount.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Frame; +import java.awt.TextArea; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +/* + * @test + * @bug 4199397 + * @summary Test to mouse click count + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseClickCount + */ + +public class MouseClickCount { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Clicking on Frame panel quickly will produce clickCount larger than 1 + in the TextArea the count is printed for each mouse click + 2. Verify that a left-button click followed by a right button click quickly + will not generate 1, 2, i.e. it's not considered a double clicking. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + private static Frame initialize() { + Frame f = new Frame("Mouse Click Count Test"); + final TextArea ta = new TextArea(); + f.add("South", ta); + f.addMouseListener(new MouseAdapter() { + public void mousePressed(MouseEvent e) { + if (e.getClickCount() == 1) ta.append("\n1"); + else ta.append(", " + e.getClickCount()); + } + }); + f.setSize(300, 500); + return f; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java b/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java new file mode 100644 index 0000000000000..b2d8e446ffc36 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseDragEnterExitTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.List; + +/* + * @test + * @bug 4141361 + * @summary Test to Ensures that mouse enter / exit is delivered to a new + * frame or component during a drag + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseDragEnterExitTest + */ + +public class MouseDragEnterExitTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click on the blue frame, drag to the white frame, and back + You should get enter/exit messages for the frames when dragging + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(MouseEvents.initialize()) + .logArea(8) + .build() + .awaitAndCheck(); + } +} + +class MouseEvents extends Frame { + static int WITH_WIDGET = 0; + + public MouseEvents(int mode) { + super("Mouse Drag Enter/Exit Test"); + setSize(300, 300); + + addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + PassFailJFrame.log("Frame MOUSE_ENTERED" + ": " + " " + + e.getX() + " " + e.getY()); + } + + @Override + public void mouseExited(MouseEvent e) { + PassFailJFrame.log("Frame MOUSE_EXITED" + ": " + " " + + e.getX() + " " + e.getY()); + } + }); + + if (mode == WITH_WIDGET) { + setLayout(new BorderLayout()); + add("Center", new SimplePanel()); + } + } + + public static List initialize() { + MouseEvents m = new MouseEvents(MouseEvents.WITH_WIDGET); + m.setLocation(500, 300); + MouseEvents t = new MouseEvents(MouseEvents.WITH_WIDGET + 1); + t.setLocation(200, 200); + return List.of(m, t); + } +} + +class SimplePanel extends Panel { + public SimplePanel() { + super(); + setName("Test Panel"); + addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + PassFailJFrame.log("Panel MOUSE_ENTERED" + ": " + " " + + e.getX() + " " + e.getY()); + } + + @Override + public void mouseExited(MouseEvent e) { + PassFailJFrame.log("Panel MOUSE_EXITED" + ": " + " " + + e.getX() + " " + e.getY()); + } + }); + setSize(100, 100); + setBackground(Color.blue); + } +} + diff --git a/test/jdk/java/awt/Mouse/MouseDragTest.java b/test/jdk/java/awt/Mouse/MouseDragTest.java new file mode 100644 index 0000000000000..cb8be7b0de25b --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseDragTest.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseMotionListener; + +/* + * @test + * @bug 4035189 + * @summary Test to verify that Drag events go to wrong component + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseDragTest + */ + +class HeavySquare extends Canvas { + private final Color colorNormal; + private boolean gotADragEvent; + + public HeavySquare(Color color) { + colorNormal = color; + setBackground(colorNormal); + new MouseChecker(this); + addMouseMotionListener(new DragAdapter()); + addMouseListener(new PressReleaseAdapter()); + } + + class DragAdapter extends MouseMotionAdapter { + public void mouseDragged(MouseEvent ev) { + if (gotADragEvent) + return; + + Point mousePt = ev.getPoint(); + Dimension csize = getSize(); + boolean inBounds = + (mousePt.x >= 0 && mousePt.x <= csize.width && + mousePt.y >= 0 && mousePt.y <= csize.height); + if (!inBounds) { + setBackground(Color.green); + } + gotADragEvent = true; + } + } + + class PressReleaseAdapter extends MouseAdapter { + public void mousePressed(MouseEvent ev) { + gotADragEvent = false; + } + + public void mouseReleased(MouseEvent ev) { + setBackground(colorNormal); + } + } + + public Dimension preferredSize() { + return new Dimension(50, 50); + } +} + +class MouseFrame extends Frame { + public MouseFrame() { + super("MouseDragTest"); + new MouseChecker(this); + setLayout(new FlowLayout()); + add(new HeavySquare(Color.red)); + add(new HeavySquare(Color.blue)); + setBounds(new Rectangle(20, 20, 400, 300)); + } +} + +public class MouseDragTest { + static Frame TestFrame; + + public MouseDragTest() { + TestFrame = new MouseFrame(); + } + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. A frame with two boxes will appear. Click and drag _very_ quickly + off one of the components. You will know you were quick enough + when the component you dragged off of turns green + 2. Repeat this several times on both boxes, ensuring you get them + to turn green. The components should revert to their original + color when you release the mouse + 3. The test FAILS if the component doesn't revert to original + color, else PASS. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(new MouseFrame()) + .build() + .awaitAndCheck(); + } +} + +class MouseChecker implements MouseListener, MouseMotionListener { + private boolean isPressed = false; + private MouseEvent evPrev = null; + private MouseEvent evPrevPrev = null; + + public MouseChecker(Component comp) { + comp.addMouseListener(this); + comp.addMouseMotionListener(this); + } + + private void recordEv(MouseEvent ev) { + evPrevPrev = evPrev; + evPrev = ev; + } + + private synchronized void failure(String str) { + PassFailJFrame.forceFail("Test Failed : "+str); + } + + public void mouseClicked(MouseEvent ev) { + if (!(evPrev.getID() == MouseEvent.MOUSE_RELEASED && + evPrevPrev.getID() == MouseEvent.MOUSE_PRESSED)) { + failure("Got mouse click without press/release preceding."); + } + recordEv(ev); + } + + public void mousePressed(MouseEvent ev) { + recordEv(ev); + if (isPressed) { + failure("Got two mouse presses without a release."); + } + isPressed = true; + } + + public void mouseReleased(MouseEvent ev) { + recordEv(ev); + if (!isPressed) { + failure("Got mouse release without being pressed."); + } + isPressed = false; + } + + public void mouseEntered(MouseEvent ev) { + recordEv(ev); + Point mousePt = ev.getPoint(); + Component comp = (Component) ev.getSource(); + Dimension size = comp.getSize(); + boolean inBounds = + (mousePt.x >= 0 && mousePt.x <= size.width && + mousePt.y >= 0 && mousePt.y <= size.height); + + if (!inBounds) { + failure("Got mouse entered, but mouse not inside component."); + } + } + + public void mouseExited(MouseEvent ev) { + recordEv(ev); + Point mousePt = ev.getPoint(); + Component comp = (Component) ev.getSource(); + if (comp instanceof Frame) { + return; + } + Dimension size = comp.getSize(); + boolean isOnChild = (comp != comp.getComponentAt(mousePt)); + boolean inBounds = + (mousePt.x >= 0 && mousePt.x <= size.width && + mousePt.y >= 0 && mousePt.y <= size.height); + if (!isOnChild && inBounds) { + failure("Got mouse exit, but mouse still inside component."); + } + } + + public void mouseDragged(MouseEvent ev) { + recordEv(ev); + if (!isPressed) { + failure("Got drag without a press first."); + } + } + + public void mouseMoved(MouseEvent ev) { + recordEv(ev); + } +} From 57c859e4adfedc963b1f4b3bf066453ace41ee36 Mon Sep 17 00:00:00 2001 From: Tejesh R Date: Tue, 8 Oct 2024 06:33:22 +0000 Subject: [PATCH 183/188] 8339836: Open source several AWT Mouse tests - Batch 1 Reviewed-by: honkar, prr --- .../java/awt/Mouse/MouseEnterExitTest.java | 174 ++++++++++++++++++ .../java/awt/Mouse/MouseEnterExitTest2.java | 140 ++++++++++++++ .../java/awt/Mouse/MouseEnterExitTest3.java | 84 +++++++++ .../java/awt/Mouse/MouseEnterExitTest4.java | 96 ++++++++++ test/jdk/java/awt/Mouse/MousePressedTest.java | 87 +++++++++ 5 files changed, 581 insertions(+) create mode 100644 test/jdk/java/awt/Mouse/MouseEnterExitTest.java create mode 100644 test/jdk/java/awt/Mouse/MouseEnterExitTest2.java create mode 100644 test/jdk/java/awt/Mouse/MouseEnterExitTest3.java create mode 100644 test/jdk/java/awt/Mouse/MouseEnterExitTest4.java create mode 100644 test/jdk/java/awt/Mouse/MousePressedTest.java diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest.java new file mode 100644 index 0000000000000..059ad5c054829 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Robot; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/* + * @test + * @bug 4050138 + * @key headful + * @summary Test to verify Lightweight components don't get + * enter/exit during drags + * @run main MouseEnterExitTest + */ + +class LWSquare extends Container { + int width; + int height; + + public LWSquare(Color color, int w, int h) { + setBackground(color); + setLayout(new FlowLayout()); + width = w; + height = h; + addMouseListener(new EnterExitAdapter(this)); + setName("LWSquare-" + color.toString()); + } + + public void paint(Graphics g) { + g.setColor(getBackground()); + g.fillRect(0, 0, getSize().width, getSize().height); + super.paint(g); + } + + public Dimension getPreferredSize() { + return new Dimension(width, height); + } + + public Cursor getCursor() { + return new Cursor(Cursor.CROSSHAIR_CURSOR); + } +} + +class MouseFrame extends Frame { + public LWSquare lw; + + public MouseFrame() { + super("MouseEnterExitTest"); + setLayout(new FlowLayout()); + + lw = new LWSquare(Color.red, 75, 75); + add(lw); + setBounds(50, 50, 300, 200); + setVisible(true); + System.out.println(getInsets()); + + addMouseListener(new EnterExitAdapter(this)); + addWindowListener( + new WindowAdapter() { + public void windowClosing(WindowEvent ev) { + dispose(); + } + } + ); + addKeyListener( + new KeyAdapter() { + public void keyPressed(KeyEvent ev) { + MouseEnterExitTest.getFrame().setTitle("MouseEnterExitTest"); + } + } + ); + } +} + + +public class MouseEnterExitTest { + static MouseFrame testFrame; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> testFrame = new MouseFrame()); + if (testFrame.lw.getBackground() != Color.red) { + throw new RuntimeException("Initial Background color not matching"); + } + robot.waitForIdle(); + robot.delay(100); + EventQueue.invokeAndWait(() -> robot.mouseMove( + testFrame.getLocationOnScreen().x + testFrame.getSize().width / 2, + testFrame.getLocationOnScreen().y + testFrame.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(100); + + if (testFrame.lw.getBackground() != Color.green) { + throw new RuntimeException("Initial Background color not matching"); + } + EventQueue.invokeAndWait(() -> robot.mouseMove( + testFrame.getLocationOnScreen().x + testFrame.getSize().width * 2, + testFrame.getLocationOnScreen().y + testFrame.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(100); + + if (testFrame.lw.getBackground() != Color.red) { + throw new RuntimeException("Initial Background color not matching"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (testFrame != null) { + testFrame.dispose(); + } + }); + } + } + + public static Frame getFrame() { + return testFrame; + } +} + +class EnterExitAdapter extends MouseAdapter { + Component compToColor; + Color colorNormal; + + EnterExitAdapter(Component comp) { + compToColor = comp; + colorNormal = comp.getBackground(); + } + + public void mouseEntered(MouseEvent ev) { + compToColor.setBackground(Color.green); + compToColor.repaint(); + } + + public void mouseExited(MouseEvent ev) { + compToColor.setBackground(colorNormal); + compToColor.repaint(); + } +} diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java new file mode 100644 index 0000000000000..e09ac333447f6 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest2.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Rectangle; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +/* + * @test + * @bug 4150851 + * @summary Tests enter and exit events when a lightweight component is on a border + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseEnterExitTest2 + */ + +public class MouseEnterExitTest2 { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Verify that white component turns black whenever mouse enters the frame, + except when it enters the red rectangle. + 2. When the mouse enters the red part of the frame the component should stay white. + """; + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(EntryExitTest.initialize()) + .build() + .awaitAndCheck(); + } +} + +class EntryExitTest extends Component { + boolean inWin; + + public Dimension getPreferredSize() { + return new Dimension(200, 150); + } + + public void paint(Graphics g) { + Color c1, c2; + String s; + if (inWin) { + c1 = Color.black; + c2 = Color.white; + s = "IN"; + } else { + c2 = Color.black; + c1 = Color.white; + s = "OUT"; + } + g.setColor(c1); + Rectangle r = getBounds(); + g.fillRect(0, 0, r.width, r.height); + g.setColor(c2); + g.drawString(s, r.width / 2, r.height / 2); + } + + public static Frame initialize() { + EntryExitTest test = new EntryExitTest(); + MouseListener frameEnterExitListener = new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + test.inWin = true; + test.repaint(); + } + + public void mouseExited(MouseEvent e) { + test.inWin = false; + test.repaint(); + } + }; + + Frame f = new Frame("Mouse Modifier Test"); + + f.add(test); + Component jc = new Component() { + public Dimension getPreferredSize() { + return new Dimension(100, 50); + } + + public void paint(Graphics g) { + Dimension d = getSize(); + g.setColor(Color.red); + g.fillRect(0, 0, d.width, d.height); + } + }; + final Container cont = new Container() { + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } + }; + cont.setLayout(new GridLayout(2, 1)); + cont.add(jc); + jc.addMouseListener(new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + //System.out.println("Component entered"); + } + public void mouseExited(MouseEvent e) { + //System.out.println("Component exited"); + } + }); + + f.add(cont, BorderLayout.NORTH); + f.addMouseListener(frameEnterExitListener); + f.pack(); + return f; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java new file mode 100644 index 0000000000000..d5096d7acf022 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest3.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import javax.swing.JButton; + +/* + * @test + * @bug 4431868 + * @summary Tests that hw container doesn't receive mouse enter/exit events when mouse + * is moved between its lw and hw children + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MouseEnterExitTest3 + */ + +public class MouseEnterExitTest3 { + static final Button button = new Button("Button"); + static final JButton jbutton = new JButton("JButton"); + static final Frame frame = new Frame("Mouse Enter/Exit Test"); + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Move the mouse between Button and JButton + 2. Verify that the frame doesn't receive enter/exit events + (Enter/exit events are dumped to the area below) + 4. If you see enter/exit events dumped the test fails + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .logArea(4) + .build() + .awaitAndCheck(); + } + + final static MouseListener listener = new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + PassFailJFrame.log(e.toString()); + } + + public void mouseExited(MouseEvent e) { + PassFailJFrame.log(e.toString()); + } + }; + + public static Frame initialize() { + frame.setLayout(new GridLayout(2, 1)); + frame.add(button); + frame.add(jbutton); + frame.addMouseListener(listener); + frame.pack(); + return frame; + } +} diff --git a/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java b/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java new file mode 100644 index 0000000000000..2ee3993ae4ede --- /dev/null +++ b/test/jdk/java/awt/Mouse/MouseEnterExitTest4.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.Window; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +/* + * @test + * @bug 4431868 + * @key headful + * @summary Tests that window totally obscured by its child doesn't receive + * enter/exit events when located over another frame + * @run main MouseEnterExitTest4 + */ + +public class MouseEnterExitTest4 { + static Button button = new Button("Button"); + static Frame frame = new Frame("Mouse Enter/Exit test"); + static Window window = new Window(frame); + static MouseListener listener = new MouseAdapter() { + public void mouseEntered(MouseEvent e) { + throw new RuntimeException("Test failed due to Mouse Enter event"); + } + + public void mouseExited(MouseEvent e) { + throw new RuntimeException("Test failed due to Mouse Exit event"); + } + }; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> { + button.setBackground(Color.red); + window.add(button); + frame.setBounds(100, 100, 300, 300); + window.setBounds(200, 200, 100, 100); + window.addMouseListener(listener); + window.setVisible(true); + frame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(200); + EventQueue.invokeAndWait(() -> robot.mouseMove( + frame.getLocationOnScreen().x + frame.getSize().width / 2, + frame.getLocationOnScreen().y + frame.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(200); + EventQueue.invokeAndWait(() -> robot.mouseMove( + window.getLocationOnScreen().x + window.getSize().width * 2, + window.getLocationOnScreen().y + window.getSize().height / 2)); + robot.waitForIdle(); + robot.delay(500); + System.out.println("Test Passed"); + + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + if (window != null) { + window.dispose(); + } + }); + } + } +} diff --git a/test/jdk/java/awt/Mouse/MousePressedTest.java b/test/jdk/java/awt/Mouse/MousePressedTest.java new file mode 100644 index 0000000000000..721d69bd5ddf0 --- /dev/null +++ b/test/jdk/java/awt/Mouse/MousePressedTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Container; +import java.awt.GridLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JScrollPane; +import javax.swing.JToggleButton; + +/* + * @test + * @bug 4268759 + * @summary Tests whether clicking on the edge of a lightweight button + * causes sticking behavior + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MousePressedTest + */ + +public class MousePressedTest { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. Click and hold on the very bottom border (2-pixel-wide border) of the + JButton. Then drag the mouse straight down out of the JButton and + into the JRadioButton, and release the mouse button + 2. If the component remains highlighted as if the mouse button is still + down, the test fails + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(initialize()) + .build() + .awaitAndCheck(); + } + + public static JFrame initialize() { + JFrame f = new JFrame("JButton Test"); + JPanel p = new JPanel(); + p.setLayout(new GridLayout(2, 2)); + JButton b = new JButton("JButton"); + p.add(b); + JCheckBox cb = new JCheckBox("JCheckBox"); + p.add(cb); + JRadioButton rb = new JRadioButton("JRadioButton"); + p.add(rb); + p.add(new JToggleButton("JToggleButton")); + + JScrollPane j = new JScrollPane(p, + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + Container c = f.getContentPane(); + c.setLayout(new GridLayout(1, 1)); + c.add(j); + f.pack(); + return f; + } +} From ffb60e55cd77a92d19e1fde305f5d204b9fae429 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Tue, 8 Oct 2024 08:14:40 +0000 Subject: [PATCH 184/188] 8341594: Use Unsafe to coalesce reads in java.util.zip.ZipUtils Reviewed-by: lancea --- .../share/classes/java/util/zip/ZipEntry.java | 14 +- .../share/classes/java/util/zip/ZipFile.java | 25 ++-- .../classes/java/util/zip/ZipInputStream.java | 8 +- .../share/classes/java/util/zip/ZipUtils.java | 140 ++++++++---------- .../bench/java/util/zip/ZipFileOpen.java | 11 +- 5 files changed, 97 insertions(+), 101 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipEntry.java b/src/java.base/share/classes/java/util/zip/ZipEntry.java index 243779a7c4913..b7ecd1bea8fbb 100644 --- a/src/java.base/share/classes/java/util/zip/ZipEntry.java +++ b/src/java.base/share/classes/java/util/zip/ZipEntry.java @@ -564,20 +564,20 @@ void setExtra0(byte[] extra, boolean doZIP64, boolean isLOC) { // be the magic value and it "accidentally" has some // bytes in extra match the id. if (sz >= 16) { - size = get64(extra, off); - csize = get64(extra, off + 8); + size = get64S(extra, off); + csize = get64S(extra, off + 8); } } else { // CEN extra zip64 if (size == ZIP64_MAGICVAL) { if (off + 8 > len) // invalid zip64 extra break; // fields, just skip - size = get64(extra, off); + size = get64S(extra, off); } if (csize == ZIP64_MAGICVAL) { if (off + 16 > len) // invalid zip64 extra break; // fields, just skip - csize = get64(extra, off + 8); + csize = get64S(extra, off + 8); } } } @@ -588,15 +588,15 @@ void setExtra0(byte[] extra, boolean doZIP64, boolean isLOC) { int pos = off + 4; // reserved 4 bytes if (get16(extra, pos) != 0x0001 || get16(extra, pos + 2) != 24) break; - long wtime = get64(extra, pos + 4); + long wtime = get64S(extra, pos + 4); if (wtime != WINDOWS_TIME_NOT_AVAILABLE) { mtime = winTimeToFileTime(wtime); } - wtime = get64(extra, pos + 12); + wtime = get64S(extra, pos + 12); if (wtime != WINDOWS_TIME_NOT_AVAILABLE) { atime = winTimeToFileTime(wtime); } - wtime = get64(extra, pos + 20); + wtime = get64S(extra, pos + 20); if (wtime != WINDOWS_TIME_NOT_AVAILABLE) { ctime = winTimeToFileTime(wtime); } diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index a6b6dce1a14ef..17256f71929f7 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -906,21 +906,21 @@ private void checkZIP64(byte[] cen, int cenpos) { if (size == ZIP64_MAGICVAL) { if (sz < 8 || (off + 8) > end) break; - size = get64(cen, off); + size = get64S(cen, off); sz -= 8; off += 8; } if (rem == ZIP64_MAGICVAL) { if (sz < 8 || (off + 8) > end) break; - rem = get64(cen, off); + rem = get64S(cen, off); sz -= 8; off += 8; } if (pos == ZIP64_MAGICVAL) { if (sz < 8 || (off + 8) > end) break; - pos = get64(cen, off); + pos = get64S(cen, off); sz -= 8; off += 8; } @@ -1376,7 +1376,7 @@ private void checkZip64ExtraFieldValues(int off, int blockSize, long csize, // Check the uncompressed size is not negative if (size == ZIP64_MAGICVAL) { if ( blockSize >= Long.BYTES) { - if (get64(cen, off) < 0) { + if (get64S(cen, off) < 0) { zerror("Invalid zip64 extra block size value"); } off += Long.BYTES; @@ -1388,7 +1388,7 @@ private void checkZip64ExtraFieldValues(int off, int blockSize, long csize, // Check the compressed size is not negative if (csize == ZIP64_MAGICVAL) { if (blockSize >= Long.BYTES) { - if (get64(cen, off) < 0) { + if (get64S(cen, off) < 0) { zerror("Invalid zip64 extra block compressed size value"); } off += Long.BYTES; @@ -1400,7 +1400,7 @@ private void checkZip64ExtraFieldValues(int off, int blockSize, long csize, // Check the LOC offset is not negative if (locoff == ZIP64_MAGICVAL) { if (blockSize >= Long.BYTES) { - if (get64(cen, off) < 0) { + if (get64S(cen, off) < 0) { zerror("Invalid zip64 extra block LOC OFFSET value"); } // Note: We do not need to adjust the following fields as @@ -1641,10 +1641,7 @@ private End findEND() throws IOException { } // Now scan the block backwards for END header signature for (int i = buf.length - ENDHDR; i >= 0; i--) { - if (buf[i+0] == (byte)'P' && - buf[i+1] == (byte)'K' && - buf[i+2] == (byte)'\005' && - buf[i+3] == (byte)'\006') { + if (get32(buf, i) == ENDSIG) { // Found ENDSIG header byte[] endbuf = Arrays.copyOfRange(buf, i, i + ENDHDR); end.centot = ENDTOT(endbuf); @@ -1664,9 +1661,9 @@ private End findEND() throws IOException { if (cenpos < 0 || locpos < 0 || readFullyAt(sbuf, 0, sbuf.length, cenpos) != 4 || - GETSIG(sbuf) != CENSIG || + get32(sbuf, 0) != CENSIG || readFullyAt(sbuf, 0, sbuf.length, locpos) != 4 || - GETSIG(sbuf) != LOCSIG) { + get32(sbuf, 0) != LOCSIG) { continue; } } @@ -1681,13 +1678,13 @@ private End findEND() throws IOException { byte[] loc64 = new byte[ZIP64_LOCHDR]; if (end.endpos < ZIP64_LOCHDR || readFullyAt(loc64, 0, loc64.length, end.endpos - ZIP64_LOCHDR) - != loc64.length || GETSIG(loc64) != ZIP64_LOCSIG) { + != loc64.length || get32(loc64, 0) != ZIP64_LOCSIG) { return end; } long end64pos = ZIP64_LOCOFF(loc64); byte[] end64buf = new byte[ZIP64_ENDHDR]; if (readFullyAt(end64buf, 0, end64buf.length, end64pos) - != end64buf.length || GETSIG(end64buf) != ZIP64_ENDSIG) { + != end64buf.length || get32(end64buf, 0) != ZIP64_ENDSIG) { return end; } // end64 candidate found, diff --git a/src/java.base/share/classes/java/util/zip/ZipInputStream.java b/src/java.base/share/classes/java/util/zip/ZipInputStream.java index 5302cf7516077..3a433cf5c6d8f 100644 --- a/src/java.base/share/classes/java/util/zip/ZipInputStream.java +++ b/src/java.base/share/classes/java/util/zip/ZipInputStream.java @@ -603,14 +603,14 @@ private void readEnd(ZipEntry e) throws IOException { long sig = get32(tmpbuf, 0); if (sig != EXTSIG) { // no EXTSIG present e.crc = sig; - e.csize = get64(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC); - e.size = get64(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC); + e.csize = get64S(tmpbuf, ZIP64_EXTSIZ - ZIP64_EXTCRC); + e.size = get64S(tmpbuf, ZIP64_EXTLEN - ZIP64_EXTCRC); ((PushbackInputStream)in).unread( tmpbuf, ZIP64_EXTHDR - ZIP64_EXTCRC, ZIP64_EXTCRC); } else { e.crc = get32(tmpbuf, ZIP64_EXTCRC); - e.csize = get64(tmpbuf, ZIP64_EXTSIZ); - e.size = get64(tmpbuf, ZIP64_EXTLEN); + e.csize = get64S(tmpbuf, ZIP64_EXTSIZ); + e.size = get64S(tmpbuf, ZIP64_EXTLEN); } } else { readFully(tmpbuf, 0, EXTHDR); diff --git a/src/java.base/share/classes/java/util/zip/ZipUtils.java b/src/java.base/share/classes/java/util/zip/ZipUtils.java index ab37fc03a5699..5b1d896f4208e 100644 --- a/src/java.base/share/classes/java/util/zip/ZipUtils.java +++ b/src/java.base/share/classes/java/util/zip/ZipUtils.java @@ -39,6 +39,7 @@ import jdk.internal.access.JavaNioAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.misc.Unsafe; +import jdk.internal.util.Preconditions; class ZipUtils { @@ -170,7 +171,10 @@ static LocalDateTime javaEpochToLocalDateTime(long time) { * The bytes are assumed to be in Intel (little-endian) byte order. */ public static final int get16(byte[] b, int off) { - return (b[off] & 0xff) | ((b[off + 1] & 0xff) << 8); + Preconditions.checkIndex(off, b.length, Preconditions.AIOOBE_FORMATTER); + Preconditions.checkIndex(off + 1, b.length, Preconditions.AIOOBE_FORMATTER); + return Short.toUnsignedInt( + UNSAFE.getShortUnaligned(b, off + Unsafe.ARRAY_BYTE_BASE_OFFSET, false)); } /** @@ -178,15 +182,20 @@ public static final int get16(byte[] b, int off) { * The bytes are assumed to be in Intel (little-endian) byte order. */ public static final long get32(byte[] b, int off) { - return (get16(b, off) | ((long)get16(b, off+2) << 16)) & 0xffffffffL; + Preconditions.checkIndex(off, b.length, Preconditions.AIOOBE_FORMATTER); + Preconditions.checkIndex(off + 3, b.length, Preconditions.AIOOBE_FORMATTER); + return Integer.toUnsignedLong( + UNSAFE.getIntUnaligned(b, off + Unsafe.ARRAY_BYTE_BASE_OFFSET, false)); } /** * Fetches signed 64-bit value from byte array at specified offset. * The bytes are assumed to be in Intel (little-endian) byte order. */ - public static final long get64(byte[] b, int off) { - return get32(b, off) | (get32(b, off+4) << 32); + public static final long get64S(byte[] b, int off) { + Preconditions.checkIndex(off, b.length, Preconditions.AIOOBE_FORMATTER); + Preconditions.checkIndex(off + 7, b.length, Preconditions.AIOOBE_FORMATTER); + return UNSAFE.getLongUnaligned(b, off + Unsafe.ARRAY_BYTE_BASE_OFFSET, false); } /** @@ -195,28 +204,9 @@ public static final long get64(byte[] b, int off) { * */ public static final int get32S(byte[] b, int off) { - return (get16(b, off) | (get16(b, off+2) << 16)); - } - - // fields access methods - static final int CH(byte[] b, int n) { - return b[n] & 0xff ; - } - - static final int SH(byte[] b, int n) { - return (b[n] & 0xff) | ((b[n + 1] & 0xff) << 8); - } - - static final long LG(byte[] b, int n) { - return ((SH(b, n)) | (SH(b, n + 2) << 16)) & 0xffffffffL; - } - - static final long LL(byte[] b, int n) { - return (LG(b, n)) | (LG(b, n + 4) << 32); - } - - static final long GETSIG(byte[] b) { - return LG(b, 0); + Preconditions.checkIndex(off, b.length, Preconditions.AIOOBE_FORMATTER); + Preconditions.checkIndex(off + 3, b.length, Preconditions.AIOOBE_FORMATTER); + return UNSAFE.getIntUnaligned(b, off + Unsafe.ARRAY_BYTE_BASE_OFFSET, false); } /* @@ -231,56 +221,56 @@ static final long GETSIG(byte[] b) { // local file (LOC) header fields - static final long LOCSIG(byte[] b) { return LG(b, 0); } // signature - static final int LOCVER(byte[] b) { return SH(b, 4); } // version needed to extract - static final int LOCFLG(byte[] b) { return SH(b, 6); } // general purpose bit flags - static final int LOCHOW(byte[] b) { return SH(b, 8); } // compression method - static final long LOCTIM(byte[] b) { return LG(b, 10);} // modification time - static final long LOCCRC(byte[] b) { return LG(b, 14);} // crc of uncompressed data - static final long LOCSIZ(byte[] b) { return LG(b, 18);} // compressed data size - static final long LOCLEN(byte[] b) { return LG(b, 22);} // uncompressed data size - static final int LOCNAM(byte[] b) { return SH(b, 26);} // filename length - static final int LOCEXT(byte[] b) { return SH(b, 28);} // extra field length + static final long LOCSIG(byte[] b) { return get32(b, 0); } // signature + static final int LOCVER(byte[] b) { return get16(b, 4); } // version needed to extract + static final int LOCFLG(byte[] b) { return get16(b, 6); } // general purpose bit flags + static final int LOCHOW(byte[] b) { return get16(b, 8); } // compression method + static final long LOCTIM(byte[] b) { return get32(b, 10);} // modification time + static final long LOCCRC(byte[] b) { return get32(b, 14);} // crc of uncompressed data + static final long LOCSIZ(byte[] b) { return get32(b, 18);} // compressed data size + static final long LOCLEN(byte[] b) { return get32(b, 22);} // uncompressed data size + static final int LOCNAM(byte[] b) { return get16(b, 26);} // filename length + static final int LOCEXT(byte[] b) { return get16(b, 28);} // extra field length // extra local (EXT) header fields - static final long EXTCRC(byte[] b) { return LG(b, 4);} // crc of uncompressed data - static final long EXTSIZ(byte[] b) { return LG(b, 8);} // compressed size - static final long EXTLEN(byte[] b) { return LG(b, 12);} // uncompressed size + static final long EXTCRC(byte[] b) { return get32(b, 4);} // crc of uncompressed data + static final long EXTSIZ(byte[] b) { return get32(b, 8);} // compressed size + static final long EXTLEN(byte[] b) { return get32(b, 12);} // uncompressed size // end of central directory header (END) fields - static final int ENDSUB(byte[] b) { return SH(b, 8); } // number of entries on this disk - static final int ENDTOT(byte[] b) { return SH(b, 10);} // total number of entries - static final long ENDSIZ(byte[] b) { return LG(b, 12);} // central directory size - static final long ENDOFF(byte[] b) { return LG(b, 16);} // central directory offset - static final int ENDCOM(byte[] b) { return SH(b, 20);} // size of ZIP file comment - static final int ENDCOM(byte[] b, int off) { return SH(b, off + 20);} - - // zip64 end of central directory recoder fields - static final long ZIP64_ENDTOD(byte[] b) { return LL(b, 24);} // total number of entries on disk - static final long ZIP64_ENDTOT(byte[] b) { return LL(b, 32);} // total number of entries - static final long ZIP64_ENDSIZ(byte[] b) { return LL(b, 40);} // central directory size - static final long ZIP64_ENDOFF(byte[] b) { return LL(b, 48);} // central directory offset - static final long ZIP64_LOCOFF(byte[] b) { return LL(b, 8);} // zip64 end offset + static final int ENDSUB(byte[] b) { return get16(b, 8); } // number of entries on this disk + static final int ENDTOT(byte[] b) { return get16(b, 10);} // total number of entries + static final long ENDSIZ(byte[] b) { return get32(b, 12);} // central directory size + static final long ENDOFF(byte[] b) { return get32(b, 16);} // central directory offset + static final int ENDCOM(byte[] b) { return get16(b, 20);} // size of ZIP file comment + static final int ENDCOM(byte[] b, int off) { return get16(b, off + 20);} + + // zip64 end of central directory record fields + static final long ZIP64_ENDTOD(byte[] b) { return get64S(b, 24);} // total number of entries on disk + static final long ZIP64_ENDTOT(byte[] b) { return get64S(b, 32);} // total number of entries + static final long ZIP64_ENDSIZ(byte[] b) { return get64S(b, 40);} // central directory size + static final long ZIP64_ENDOFF(byte[] b) { return get64S(b, 48);} // central directory offset + static final long ZIP64_LOCOFF(byte[] b) { return get64S(b, 8);} // zip64 end offset // central directory header (CEN) fields - static final long CENSIG(byte[] b, int pos) { return LG(b, pos + 0); } - static final int CENVEM(byte[] b, int pos) { return SH(b, pos + 4); } - static final int CENVEM_FA(byte[] b, int pos) { return CH(b, pos + 5); } // file attribute compatibility - static final int CENVER(byte[] b, int pos) { return SH(b, pos + 6); } - static final int CENFLG(byte[] b, int pos) { return SH(b, pos + 8); } - static final int CENHOW(byte[] b, int pos) { return SH(b, pos + 10);} - static final long CENTIM(byte[] b, int pos) { return LG(b, pos + 12);} - static final long CENCRC(byte[] b, int pos) { return LG(b, pos + 16);} - static final long CENSIZ(byte[] b, int pos) { return LG(b, pos + 20);} - static final long CENLEN(byte[] b, int pos) { return LG(b, pos + 24);} - static final int CENNAM(byte[] b, int pos) { return SH(b, pos + 28);} - static final int CENEXT(byte[] b, int pos) { return SH(b, pos + 30);} - static final int CENCOM(byte[] b, int pos) { return SH(b, pos + 32);} - static final int CENDSK(byte[] b, int pos) { return SH(b, pos + 34);} - static final int CENATT(byte[] b, int pos) { return SH(b, pos + 36);} - static final long CENATX(byte[] b, int pos) { return LG(b, pos + 38);} - static final int CENATX_PERMS(byte[] b, int pos) { return SH(b, pos + 40);} // posix permission data - static final long CENOFF(byte[] b, int pos) { return LG(b, pos + 42);} + static final long CENSIG(byte[] b, int pos) { return get32(b, pos + 0); } + static final int CENVEM(byte[] b, int pos) { return get16(b, pos + 4); } + static final int CENVEM_FA(byte[] b, int pos) { return Byte.toUnsignedInt(b[pos + 5]); } // file attribute compatibility + static final int CENVER(byte[] b, int pos) { return get16(b, pos + 6); } + static final int CENFLG(byte[] b, int pos) { return get16(b, pos + 8); } + static final int CENHOW(byte[] b, int pos) { return get16(b, pos + 10);} + static final long CENTIM(byte[] b, int pos) { return get32(b, pos + 12);} + static final long CENCRC(byte[] b, int pos) { return get32(b, pos + 16);} + static final long CENSIZ(byte[] b, int pos) { return get32(b, pos + 20);} + static final long CENLEN(byte[] b, int pos) { return get32(b, pos + 24);} + static final int CENNAM(byte[] b, int pos) { return get16(b, pos + 28);} + static final int CENEXT(byte[] b, int pos) { return get16(b, pos + 30);} + static final int CENCOM(byte[] b, int pos) { return get16(b, pos + 32);} + static final int CENDSK(byte[] b, int pos) { return get16(b, pos + 34);} + static final int CENATT(byte[] b, int pos) { return get16(b, pos + 36);} + static final long CENATX(byte[] b, int pos) { return get32(b, pos + 38);} + static final int CENATX_PERMS(byte[] b, int pos) { return get16(b, pos + 40);} // posix permission data + static final long CENOFF(byte[] b, int pos) { return get32(b, pos + 42);} // The END header is followed by a variable length comment of size < 64k. static final long END_MAXLEN = 0xFFFF + ENDHDR; @@ -293,16 +283,16 @@ static void loadLibrary() { jdk.internal.loader.BootLoader.loadLibrary("zip"); } - private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - private static final long byteBufferArrayOffset = unsafe.objectFieldOffset(ByteBuffer.class, "hb"); - private static final long byteBufferOffsetOffset = unsafe.objectFieldOffset(ByteBuffer.class, "offset"); + private static final long byteBufferArrayOffset = UNSAFE.objectFieldOffset(ByteBuffer.class, "hb"); + private static final long byteBufferOffsetOffset = UNSAFE.objectFieldOffset(ByteBuffer.class, "offset"); static byte[] getBufferArray(ByteBuffer byteBuffer) { - return (byte[]) unsafe.getReference(byteBuffer, byteBufferArrayOffset); + return (byte[]) UNSAFE.getReference(byteBuffer, byteBufferArrayOffset); } static int getBufferOffset(ByteBuffer byteBuffer) { - return unsafe.getInt(byteBuffer, byteBufferOffsetOffset); + return UNSAFE.getInt(byteBuffer, byteBufferOffsetOffset); } } diff --git a/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java b/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java index e450fcfe9a0ae..4f6ae6373ec46 100644 --- a/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java +++ b/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,4 +107,13 @@ public void openCloseZipFilex2() throws Exception { zf.close(); zf2.close(); } + + // Provide a simple one-off run without JMH dependencies enable simple debugging, + // diagnostics and dual-purposing this micro as a startup test. + public static void main(String... args) throws Exception { + var bench = new ZipFileOpen(); + bench.size = 1024*4; + bench.beforeRun(); + bench.openCloseZipFile(); + } } From 59ac7039d3ace0ec481742c3a10c81f1675e12da Mon Sep 17 00:00:00 2001 From: Amit Kumar Date: Tue, 8 Oct 2024 09:19:40 +0000 Subject: [PATCH 185/188] 8339220: [s390x] TestIfMinMax.java failure Reviewed-by: lucy, aph --- src/hotspot/cpu/s390/matcher_s390.hpp | 17 +++++++++++------ test/hotspot/jtreg/ProblemList.txt | 1 - 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/hotspot/cpu/s390/matcher_s390.hpp b/src/hotspot/cpu/s390/matcher_s390.hpp index 6c6cae3c58fc3..d8b1ae68f6f50 100644 --- a/src/hotspot/cpu/s390/matcher_s390.hpp +++ b/src/hotspot/cpu/s390/matcher_s390.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2017, 2022 SAP SE. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 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 @@ -63,11 +63,16 @@ return true; } - // Suppress CMOVL. Conditional move available on z/Architecture only from z196 onwards. Not exploited yet. - static int long_cmove_cost() { return ConditionalMoveLimit; } + // Use conditional move (CMOVL) + static int long_cmove_cost() { + // z196/z11 or later hardware support conditional moves + return VM_Version::has_LoadStoreConditional() ? 0 : ConditionalMoveLimit; + } - // Suppress CMOVF. Conditional move available on z/Architecture only from z196 onwards. Not exploited yet. - static int float_cmove_cost() { return ConditionalMoveLimit; } + static int float_cmove_cost() { + // z196/z11 or later hardware support conditional moves + return VM_Version::has_LoadStoreConditional() ? 0 : ConditionalMoveLimit; + } // Set this as clone_shift_expressions. static bool narrow_oop_use_complex_address() { diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 0e75009ac8a1a..6a8798ce6172b 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -53,7 +53,6 @@ compiler/loopopts/TestUnreachableInnerLoop.java 8288981 linux-s390x compiler/c2/Test8004741.java 8235801 generic-all compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all -compiler/c2/irTests/TestIfMinMax.java 8339220 linux-s390x compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all compiler/codecache/CheckLargePages.java 8332654 linux-x64 From f62dba3651719bc0031522e171a6e42b362c1363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Tue, 8 Oct 2024 09:59:29 +0000 Subject: [PATCH 186/188] 8341597: ZipFileInflaterInputStream input buffer size uses uncompressed size Reviewed-by: lancea --- src/java.base/share/classes/java/util/zip/ZipFile.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 17256f71929f7..00d100b21a874 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -411,13 +411,10 @@ public InputStream getInputStream(ZipEntry entry) throws IOException { case DEFLATED: // Inflater likes a bit of slack // MORE: Compute good size for inflater stream: - long size = CENLEN(zsrc.cen, pos) + 2; + long size = CENSIZ(zsrc.cen, pos); if (size > 65536) { size = 8192; } - if (size <= 0) { - size = 4096; - } InputStream is = new ZipFileInflaterInputStream(in, res, (int) size); synchronized (istreams) { istreams.add(is); From 7a1e832ea997f9984eb5fc18474a8f1650ddb1bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eirik=20Bj=C3=B8rsn=C3=B8s?= Date: Tue, 8 Oct 2024 10:08:31 +0000 Subject: [PATCH 187/188] 8336843: Deprecate java.util.zip.ZipError for removal Reviewed-by: liach, lancea --- src/java.base/share/classes/java/util/zip/ZipError.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/util/zip/ZipError.java b/src/java.base/share/classes/java/util/zip/ZipError.java index 2aa37bef010c2..933cc4470916e 100644 --- a/src/java.base/share/classes/java/util/zip/ZipError.java +++ b/src/java.base/share/classes/java/util/zip/ZipError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,9 +28,12 @@ /** * Signals that an unrecoverable error has occurred. * + * @deprecated ZipError is no longer used and is obsolete. + * {@link ZipException} should be used instead. * @author Dave Bristor * @since 1.6 */ +@Deprecated(since="24", forRemoval = true) public class ZipError extends InternalError { @java.io.Serial private static final long serialVersionUID = 853973422266861979L; From 6e486181613bde8da6874eeed680c7136e8d778a Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 8 Oct 2024 12:36:31 +0000 Subject: [PATCH 188/188] 8341644: Compile error in cgroup coding when using toolchain clang Reviewed-by: stefank, mdoerr --- src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index 527573644a816..56dcadd670f82 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -64,16 +64,16 @@ class CgroupV2CpuController: public CgroupCpuController { bool is_read_only() override { return reader()->is_read_only(); } - const char* subsystem_path() { + const char* subsystem_path() override { return reader()->subsystem_path(); } bool needs_hierarchy_adjustment() override { return reader()->needs_hierarchy_adjustment(); } - void set_subsystem_path(const char* cgroup_path) { + void set_subsystem_path(const char* cgroup_path) override { reader()->set_subsystem_path(cgroup_path); } - const char* mount_point() { return reader()->mount_point(); } + const char* mount_point() override { return reader()->mount_point(); } const char* cgroup_path() override { return reader()->cgroup_path(); } }; @@ -97,16 +97,16 @@ class CgroupV2MemoryController final: public CgroupMemoryController { bool is_read_only() override { return reader()->is_read_only(); } - const char* subsystem_path() { + const char* subsystem_path() override { return reader()->subsystem_path(); } bool needs_hierarchy_adjustment() override { return reader()->needs_hierarchy_adjustment(); } - void set_subsystem_path(const char* cgroup_path) { + void set_subsystem_path(const char* cgroup_path) override { reader()->set_subsystem_path(cgroup_path); } - const char* mount_point() { return reader()->mount_point(); } + const char* mount_point() override { return reader()->mount_point(); } const char* cgroup_path() override { return reader()->cgroup_path(); } };