From 6829d9ac67fb131462d3ef1c4bdfaa07df5d6be6 Mon Sep 17 00:00:00 2001 From: Sonia Zaldana Calles Date: Thu, 23 May 2024 05:53:09 +0000 Subject: [PATCH 01/99] 8332122: [nmt] Totals for malloc should show total peak Reviewed-by: stuefe, jsjolen --- src/hotspot/share/nmt/mallocTracker.hpp | 10 ++ src/hotspot/share/nmt/memReporter.cpp | 6 +- .../jtreg/runtime/NMT/PeakMallocTest.java | 103 ++++++++++++++++++ 3 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/NMT/PeakMallocTest.java diff --git a/src/hotspot/share/nmt/mallocTracker.hpp b/src/hotspot/share/nmt/mallocTracker.hpp index 5d755f60ae6..9c14ea04bf0 100644 --- a/src/hotspot/share/nmt/mallocTracker.hpp +++ b/src/hotspot/share/nmt/mallocTracker.hpp @@ -179,6 +179,16 @@ class MallocMemorySnapshot { return _all_mallocs.size() + malloc_overhead() + total_arena(); } + // Total peak malloc + size_t total_peak() const { + return _all_mallocs.peak_size(); + } + + // Total peak count + size_t total_peak_count() const { + return _all_mallocs.peak_count(); + } + // Total malloc'd memory used by arenas size_t total_arena() const; diff --git a/src/hotspot/share/nmt/memReporter.cpp b/src/hotspot/share/nmt/memReporter.cpp index b880e56a853..96ad3c5cb1a 100644 --- a/src/hotspot/share/nmt/memReporter.cpp +++ b/src/hotspot/share/nmt/memReporter.cpp @@ -165,9 +165,11 @@ void MemSummaryReporter::report() { out->print("Total: "); print_total(total_reserved_amount, total_committed_amount); out->cr(); - out->print_cr(" malloc: " SIZE_FORMAT "%s #" SIZE_FORMAT, + out->print_cr(" malloc: " SIZE_FORMAT "%s #" SIZE_FORMAT ", peak=" SIZE_FORMAT "%s #" SIZE_FORMAT, amount_in_current_scale(total_malloced_bytes), current_scale(), - _malloc_snapshot->total_count()); + _malloc_snapshot->total_count(), + amount_in_current_scale(_malloc_snapshot->total_peak()), + current_scale(), _malloc_snapshot->total_peak_count()); out->print(" mmap: "); print_total(total_mmap_reserved_bytes, total_mmap_committed_bytes); out->cr(); diff --git a/test/hotspot/jtreg/runtime/NMT/PeakMallocTest.java b/test/hotspot/jtreg/runtime/NMT/PeakMallocTest.java new file mode 100644 index 00000000000..50757df61b1 --- /dev/null +++ b/test/hotspot/jtreg/runtime/NMT/PeakMallocTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Red Hat Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please 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 8332122 + * @summary Test to verify correctness of peak malloc tracking + * @key randomness + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=summary -Xms32m -Xmx32m -Xint PeakMallocTest + * + */ + +// Note we run the test with -Xint to keep compilers from running and reduce malloc noise. + +import jdk.test.lib.process.OutputAnalyzer; + +import jdk.test.whitebox.WhiteBox; + +public class PeakMallocTest { + + private static WhiteBox wb = WhiteBox.getWhiteBox(); + private static final double FUDGE_FACTOR = 0.2; + + public static void main(String[] args) throws Exception { + + // Measure early malloc total and peak + OutputAnalyzer output = NMTTestUtils.startJcmdVMNativeMemory("scale=1"); + long earlyTotal = getMallocTotal(output); + long earlyPeak = getMallocPeak(output); + System.out.println("Early malloc total: " + earlyTotal); + System.out.println("Early malloc peak: " + earlyPeak); + + // Allocate a large amount of memory and then free + long allocSize = Math.max(8 * earlyPeak, 250 * 1024 * 1024); // MAX(earlyPeak * 8, 250MB) + long addr = wb.NMTMalloc(allocSize); + System.out.println("Allocation size: " + allocSize); + wb.NMTFree(addr); + + // Measure again + output = NMTTestUtils.startJcmdVMNativeMemory("scale=1"); + long currTotal = getMallocTotal(output); + long currPeak = getMallocPeak(output); + System.out.println("Current malloc total: " + currTotal); + System.out.println("Current malloc peak: " + currPeak); + + // Verify total global malloc is similar with a fudge factor + double mallocLowerBound = earlyTotal * (1 - FUDGE_FACTOR); + double mallocUpperBound = earlyTotal * (1 + FUDGE_FACTOR); + if (currTotal < mallocLowerBound || currTotal > mallocUpperBound) { + throw new Exception("Global malloc measurement is incorrect. " + + "Expected range: [" + mallocLowerBound + " - " + mallocUpperBound + "]. " + + "Actual malloc total: " + currTotal); + } + + // Verify global malloc peak reflects large allocation with a fudge factor + long peakDiff = currPeak - earlyPeak; + double peakLowerBound = allocSize * (1 - FUDGE_FACTOR); + double peakUpperBound = allocSize * (1 + FUDGE_FACTOR); + if (peakDiff < peakLowerBound || peakDiff > peakUpperBound) { + throw new Exception("Global malloc peak measurement is incorrect. " + + "Expected peak diff range: [" + peakLowerBound + " - " + peakUpperBound + "]. " + + "Actual peak diff: " + peakDiff); + } + } + + private static long getMallocPeak(OutputAnalyzer output) { + // First match should correspond to global malloc peak + String global = output.firstMatch("peak=\\d*"); + return Long.parseLong(global.substring(global.indexOf("=") + 1)); + } + + private static long getMallocTotal(OutputAnalyzer output) { + // First match should correspond to global malloc total + String global = output.firstMatch("malloc: \\d*"); + return Long.parseLong(global.substring(global.indexOf(" ") + 1)); + } +} From 2a11e0da026066191e4d4f30b9daca986c484630 Mon Sep 17 00:00:00 2001 From: Dan Heidinga Date: Thu, 23 May 2024 05:55:16 +0000 Subject: [PATCH 02/99] 8332743: Update comment related to JDK-8320522 Reviewed-by: coleenp --- .../share/interpreter/interpreterRuntime.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 7d12797007b..dc5f2f5b637 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -223,20 +223,6 @@ JRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* current, ConstantPool* pool // Make sure klass is initialized klass->initialize(CHECK); - // At this point the class may not be fully initialized - // because of recursive initialization. If it is fully - // initialized & has_finalized is not set, we rewrite - // it into its fast version (Note: no locking is needed - // here since this is an atomic byte write and can be - // done more than once). - // - // Note: In case of classes with has_finalized we don't - // rewrite since that saves us an extra check in - // the fast version which then would call the - // slow version anyway (and do a call back into - // Java). - // If we have a breakpoint, then we don't rewrite - // because the _breakpoint bytecode would be lost. oop obj = klass->allocate_instance(CHECK); current->set_vm_result(obj); JRT_END From c2180d141ccca0e396ee9a0cd3044c4428b963d5 Mon Sep 17 00:00:00 2001 From: Sergey Chernyshev Date: Thu, 23 May 2024 06:12:45 +0000 Subject: [PATCH 03/99] 8315767: InetAddress: constructing objects from BSD literal addresses Reviewed-by: dfuchs, aefimov, michaelm, jpai --- .../share/classes/java/net/Inet4Address.java | 125 +++++++++++++++- .../share/classes/java/net/InetAddress.java | 1 + .../classes/sun/net/util/IPAddressUtil.java | 57 +++++++- .../java/net/InetAddress/OfLiteralTest.java | 138 +++++++++++++++++- 4 files changed, 301 insertions(+), 20 deletions(-) diff --git a/src/java.base/share/classes/java/net/Inet4Address.java b/src/java.base/share/classes/java/net/Inet4Address.java index bef9fa9500d..16cea2d10d7 100644 --- a/src/java.base/share/classes/java/net/Inet4Address.java +++ b/src/java.base/share/classes/java/net/Inet4Address.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, 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 @@ -70,9 +70,9 @@ *

When only one part is given, the value is stored directly in * the network address without any byte rearrangement. * - *

These forms support parts specified in decimal format only. - * For example, the following forms are supported by methods capable - * of parsing textual representations of IPv4 addresses: + *

For example, the following (decimal) forms are supported by the methods + * {@link Inet4Address#ofLiteral(String)} and {@link InetAddress#getByName(String)} + * which are capable of parsing textual representations of IPv4 addresses: * {@snippet : * // Dotted-decimal 'd.d.d.d' form with four part address literal * InetAddress.getByName("007.008.009.010"); // ==> /7.8.9.10 @@ -93,8 +93,16 @@ * Inet4Address.ofLiteral("02130706689"); // ==> /127.0.1.1 * } * + *

The above forms adhere to "strict" decimal-only syntax. + * Additionally, the {@link Inet4Address#ofPosixLiteral(String)} + * method implements a POSIX {@code inet_addr} compatible "loose" + * parsing algorithm, allowing octal and hexadecimal address segments. + * Please refer to + * RFC 6943: Issues in Identifier Comparison for Security + * Purposes. Aside from {@code Inet4Address.ofPosixLiteral(String)}, all methods only + * support strict decimal parsing. *

For methods that return a textual representation as output - * value, the first form, i.e. a dotted-quad string, is used. + * value, the first form, i.e. a dotted-quad string in strict decimal notation, is used. * *

The Scope of a Multicast Address

* @@ -112,6 +120,8 @@ * RFC 2365: Administratively Scoped IP Multicast * @spec https://www.rfc-editor.org/info/rfc790 * RFC 790: Assigned numbers + * @spec https://www.rfc-editor.org/rfc/rfc6943.html#section-3.1.1 + * RFC 6943: Issues in Identifier Comparison for Security Purposes * @since 1.4 */ @@ -180,6 +190,72 @@ public static Inet4Address ofLiteral(String ipv4AddressLiteral) { return parseAddressString(ipv4AddressLiteral, true); } + /** + * Creates an {@code Inet4Address} based on the provided {@linkplain + * Inet4Address##format-posix textual representation of an IPv4 address in + * POSIX {@code inet_addr} compatible form}. + *

The method {@code ofPosixLiteral} + * implements + * POSIX {@code inet_addr} compatible parsing algorithm, allowing + * octal and hexadecimal address segments. {@code "0"} is the prefix + * for octal numbers, {@code "0x"} and {@code "0X"} are the prefixes + * for hexadecimal numbers. Non-zero address segments that start from + * non-zero digits are parsed as decimal numbers. The following + * (non-decimal) forms are supported by this method: + * {@snippet : + * // Dotted-quad 'x.x.x.x' form with four part address literal + * Inet4Address.ofPosixLiteral("0177.0.0.1"); // ==> /127.0.0.1 + * Inet4Address.ofPosixLiteral("0x7F.0.0.1"); // ==> /127.0.0.1 + * + * // Dotted-triple 'x.x.x' form with three part address literal, + * // the last part is placed in the rightmost two bytes + * // of the constructed address + * Inet4Address.ofPosixLiteral("0177.0.0402"); // ==> /127.0.1.2 + * Inet4Address.ofPosixLiteral("0x7F.0.0x102"); // ==> /127.0.1.2 + * + * // Dotted-double 'x.x' form with two part address literal, + * // the last part is placed in the rightmost three bytes + * // of the constructed address + * Inet4Address.ofPosixLiteral("0177.0201003"); // ==> /127.1.2.3 + * Inet4Address.ofPosixLiteral("0x7F.0x10203"); // ==> /127.1.2.3 + * Inet4Address.ofPosixLiteral("127.66051"); // ==> /127.1.2.3 + * + * // Dotless 'x' form with one value that is stored directly in + * // the constructed address bytes without any rearrangement + * Inet4Address.ofPosixLiteral("0100401404"); // ==> /1.2.3.4 + * Inet4Address.ofPosixLiteral("0x1020304"); // ==> /1.2.3.4 + * Inet4Address.ofPosixLiteral("16909060"); // ==> /1.2.3.4 + * } + *

If the provided IPv4 address literal cannot represent a + * valid IPv4 address in {@linkplain Inet4Address##format-posix + * POSIX form} an {@code IllegalArgumentException} is thrown. + *

This method doesn't block, i.e. no hostname lookup is performed. + * + * @apiNote + * This method produces different results compared to {@linkplain Inet4Address#ofLiteral} + * when {@code posixIPAddressLiteral} parameter contains address segments with + * leading zeroes. An address segment with a leading zero is always parsed as an octal + * number by this method, therefore {@code 0255} (octal) will be parsed as + * {@code 173} (decimal). On the other hand, {@link Inet4Address#ofLiteral + * Inet4Address.ofLiteral} ignores leading zeros, parses all numbers as decimal and produces + * {@code 255}. Where this method would parse {@code 0256.0256.0256.0256} (octal) and + * produce {@code 174.174.174.174} (decimal) in four dotted quad notation, + * {@link Inet4Address#ofLiteral Inet4Address.ofLiteral} will throw + * {@code IllegalArgumentException}. + * + * @param posixIPAddressLiteral a textual representation of an IPv4 address. + * @return an {@link Inet4Address} object with no hostname set, and constructed + * from the provided IPv4 address literal. + * @throws IllegalArgumentException if the {@code posixIPAddressLiteral} cannot be + * parsed as an IPv4 address literal. + * @throws NullPointerException if the {@code posixIPAddressLiteral} is {@code null}. + * @since 23 + */ + public static Inet4Address ofPosixLiteral(String posixIPAddressLiteral) { + Objects.requireNonNull(posixIPAddressLiteral); + return parseAddressStringPosix(posixIPAddressLiteral); + } + /** * Parses the given string as an IPv4 address literal. * If the given {@code addressLiteral} string cannot be parsed as an IPv4 address literal @@ -212,6 +288,45 @@ static Inet4Address parseAddressString(String addressLiteral, boolean throwIAE) return new Inet4Address(null, addrBytes); } + /** + * Parses the given string as an IPv4 address literal in + * {@linkplain Inet4Address##format-posix POSIX form.} + * + *

If the given {@code addressLiteral} string cannot be parsed as an IPv4 address literal + * in POSIX form and {@code throwIAE} is {@code false}, {@code null} is returned. + * If the given {@code addressLiteral} string cannot be parsed as an IPv4 address literal + * and {@code throwIAE} is {@code true}, an {@code IllegalArgumentException} + * is thrown. + * + * @apiNote + * This method produces different results compared to {@linkplain Inet4Address#parseAddressString} + * when {@code addressLiteral} parameter contains address segments with leading + * zeroes. An address segment with a leading zero is always parsed as an octal + * number by this method, therefore {@code 0255} (octal) will be parsed as + * {@code 173} (decimal). On the other hand, {@link Inet4Address#parseAddressString} + * ignores leading zeros, parses all numbers as decimal and produces {@code 255}. + * Where this method would parse {@code 0256.0256.0256.0256} (octal) and produce + * {@code 174.174.174.174} (decimal) in four dotted quad notation, {@linkplain + * Inet4Address#parseAddressString} will either throw {@code IllegalArgumentException} + * or return {@code null}, depending on the value of {@code throwIAE}. + * + * @param addressLiteral IPv4 address literal to parse + * @param throwIAE whether to throw {@code IllegalArgumentException} if the + * given {@code addressLiteral} string cannot be parsed as + * an IPv4 address literal. + * @return {@code Inet4Address} object constructed from the address literal; + * or {@code null} if the literal cannot be parsed as an IPv4 address + * @throws IllegalArgumentException if the given {@code addressLiteral} string + * cannot be parsed as an IPv4 address literal and {@code throwIAE} is {@code true}. + */ + private static Inet4Address parseAddressStringPosix(String addressLiteral) { + byte [] parsedBytes = IPAddressUtil.parseBsdLiteralV4(addressLiteral); + if (parsedBytes == null) { + throw IPAddressUtil.invalidIpAddressLiteral(addressLiteral); + } + return new Inet4Address(null, parsedBytes); + } + /** * Replaces the object to be serialized with an InetAddress object. * diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index 534553a99f3..7e0c39f9111 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -1722,6 +1722,7 @@ static InetAddress[] getAllByName0 (String host, boolean check) * @throws NullPointerException if the {@code ipAddressLiteral} is {@code null}. * @see Inet4Address#ofLiteral(String) * @see Inet6Address#ofLiteral(String) + * @see Inet4Address#ofPosixLiteral(String) * @since 22 */ public static InetAddress ofLiteral(String ipAddressLiteral) { diff --git a/src/java.base/share/classes/sun/net/util/IPAddressUtil.java b/src/java.base/share/classes/sun/net/util/IPAddressUtil.java index e81b6543393..ecd60a9ffc4 100644 --- a/src/java.base/share/classes/sun/net/util/IPAddressUtil.java +++ b/src/java.base/share/classes/sun/net/util/IPAddressUtil.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 @@ -666,40 +666,81 @@ public static int digit(char ch, int radix) { * {@code false} otherwise. */ public static boolean isBsdParsableV4(String input) { + return parseBsdLiteralV4(input) != null; + } + + /** + * Parse String as IPv4 address literal by following + * POSIX-style formatting rules. + * + * @param input a String representing an IPv4 address in POSIX format + * @return a byte array representing the IPv4 numeric address + * if input string is a parsable POSIX formatted IPv4 address literal, + * {@code null} otherwise. + */ + public static byte[] parseBsdLiteralV4(String input) { + + byte[] res = new byte[]{0,0,0,0}; + + int len = input.length(); + if (len == 0) { + return null; + } char firstSymbol = input.charAt(0); // Check if first digit is not a decimal digit if (parseAsciiDigit(firstSymbol, DECIMAL) == -1) { - return false; + return null; } // Last character is dot OR is not a supported digit: [0-9,A-F,a-f] - char lastSymbol = input.charAt(input.length() - 1); + char lastSymbol = input.charAt(len - 1); if (lastSymbol == '.' || parseAsciiHexDigit(lastSymbol) == -1) { - return false; + return null; } // Parse IP address fields CharBuffer charBuffer = CharBuffer.wrap(input); int fieldNumber = 0; + long fieldValue = -1L; while (charBuffer.hasRemaining()) { - long fieldValue = -1L; + fieldValue = -1L; // Try to parse fields in all supported radixes for (int radix : SUPPORTED_RADIXES) { fieldValue = parseV4FieldBsd(radix, charBuffer, fieldNumber); if (fieldValue >= 0) { + if (fieldValue < 256) { + // Store the parsed field in the byte buffer. + // If the field value is greater than 255, it can only be the last field. + // If it is not the last one, parseV4FieldBsd enforces this limit + // and returns TERMINAL_PARSE_ERROR. + res[fieldNumber] = (byte) fieldValue; + } fieldNumber++; break; } else if (fieldValue == TERMINAL_PARSE_ERROR) { - return false; + return null; } } // If field can't be parsed as one of supported radixes stop // parsing if (fieldValue < 0) { - return false; + return null; } } - return true; + // The last field value must be non-negative + if (fieldValue < 0) { + return null; + } + // If the last fieldValue is greater than 255 (fieldNumber < 4), + // it is written to the last (4 - (fieldNumber - 1)) octets + // in the network order + if (fieldNumber < 4) { + for (int i = 3; i >= fieldNumber - 1; --i) { + res[i] = (byte) (fieldValue & 255); + fieldValue >>= 8; + } + } + return res; } /** diff --git a/test/jdk/java/net/InetAddress/OfLiteralTest.java b/test/jdk/java/net/InetAddress/OfLiteralTest.java index 90148a786af..090523a9ee9 100644 --- a/test/jdk/java/net/InetAddress/OfLiteralTest.java +++ b/test/jdk/java/net/InetAddress/OfLiteralTest.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 @@ -22,8 +22,8 @@ */ /* @test - * @bug 8272215 - * @summary Test for ofLiteral API in InetAddress classes + * @bug 8272215 8315767 + * @summary Test for ofLiteral, ofPosixLiteral APIs in InetAddress classes * @run junit/othervm -Djdk.net.hosts.file=nonExistingHostsFile.txt * OfLiteralTest * @run junit/othervm -Djdk.net.hosts.file=nonExistingHostsFile.txt @@ -67,11 +67,15 @@ public void validLiteral(InetAddressClass inetAddressClass, InetAddress ofLiteralResult = switch (inetAddressClass) { case INET_ADDRESS -> InetAddress.ofLiteral(addressLiteral); case INET4_ADDRESS -> Inet4Address.ofLiteral(addressLiteral); + case INET4_ADDRESS_POSIX -> Inet4Address.ofPosixLiteral(addressLiteral); case INET6_ADDRESS -> Inet6Address.ofLiteral(addressLiteral); }; - InetAddress getByNameResult = InetAddress.getByName(addressLiteral); Assert.assertArrayEquals(expectedAddressBytes, ofLiteralResult.getAddress()); - Assert.assertEquals(getByNameResult, ofLiteralResult); + // POSIX literals are not compatible with InetAddress.getByName() + if (inetAddressClass != InetAddressClass.INET4_ADDRESS_POSIX) { + InetAddress getByNameResult = InetAddress.getByName(addressLiteral); + Assert.assertEquals(getByNameResult, ofLiteralResult); + } } private static Stream validLiteralArguments() throws Exception { @@ -101,6 +105,33 @@ private static Stream validLiteralArguments() throws Exception { byte[] ipv6Ipv4MappedAddressExpBytes = new byte[]{ (byte) 129, (byte) 144, 52, 38}; + // 87.0.0.1 address bytes + byte[] ipv4_87_0_0_1 = new byte[]{87, 0, 0, 1}; + + // 127.0.0.1 address bytes + byte[] ipv4_127_0_0_1 = new byte[]{127, 0, 0, 1}; + + // 17.99.141.27 address bytes + byte[] ipv4_17_99_141_27 = new byte[]{17, 99, (byte)141, 27}; + + // 127.8.0.1 address bytes + byte[] ipv4_127_8_0_1 = new byte[]{127, 8, 0, 1}; + + // 0.0.0.42 address bytes + byte[] ipv4_0_0_0_42 = new byte[]{0, 0, 0, 42}; + + // 0.0.0.34 address bytes + byte[] ipv4_0_0_0_34 = new byte[]{0, 0, 0, 34}; + + // 127.0.1.2 address bytes + byte[] ipv4_127_0_1_2 = new byte[]{127, 0, 1, 2}; + + // 127.1.2.3 address bytes + byte[] ipv4_127_1_2_3 = new byte[]{127, 1, 2, 3}; + + // 255.255.255.255 address bytes + byte[] ipv4_255_255_255_255 = new byte[]{(byte)255, (byte)255, (byte)255, (byte)255}; + Stream validLiterals = Stream.of( // IPv6 address literals are parsable by Inet6Address.ofLiteral // and InetAddress.ofLiteral methods @@ -170,7 +201,87 @@ private static Stream validLiteralArguments() throws Exception { // with leading 0 that is discarded and address // parsed as decimal Arguments.of(InetAddressClass.INET_ADDRESS, - "03735928559", ipv4ExpBytes) + "03735928559", ipv4ExpBytes), + // form:'x.x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0127.0.0.1", ipv4_87_0_0_1), + // form:'x.x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0177.0.0.1", ipv4_127_0_0_1), + // form:'x.x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0s treated as octal segment prefixes + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0177.0000.0000.0001", ipv4_127_0_0_1), + // form:'x.x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "127.010.0.1", ipv4_127_8_0_1), + // form:'x.x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0377.0377.0377.0377", ipv4_255_255_255_255), + // form:'x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0s treated as octal segment prefixes + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0177.0.0402", ipv4_127_0_1_2), + // form:'x.x.x' method:InetAddress.ofPosixLiteral - + // with leading 0x treated as hexadecimal segment prefixes + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0x7F.0.0x102", ipv4_127_0_1_2), + // form:'x.x' method:InetAddress.ofPosixLiteral - + // with leading 0s treated as octal segment prefixes + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0177.0201003", ipv4_127_1_2_3), + // form:'x.x' method:InetAddress.ofPosixLiteral - + // with leading 0x treated as hexadecimal prefixes + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0x7F.0x10203", ipv4_127_1_2_3), + // form:'x.x' method:InetAddress.ofPosixLiteral - + // without prefixes treated as decimal + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "127.66051", ipv4_127_1_2_3), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "017700000001", ipv4_127_0_0_1), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "02130706433", ipv4_17_99_141_27), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "037777777777", ipv4_255_255_255_255), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0x treated as hex prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0x1020304", oneToFourAddressExpBytes), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0x treated as hex prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0xFFFFFFFF", ipv4_255_255_255_255), + // form:'x' method:InetAddress.ofPosixLiteral - + // without leading 0 treated as decimal + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "2130706433", ipv4_127_0_0_1), + // form:'x' method:InetAddress.ofPosixLiteral - + // without leading 0 treated as decimal + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "42", ipv4_0_0_0_42), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "0100401404", oneToFourAddressExpBytes), + // form:'x' method:InetAddress.ofPosixLiteral - + // without prefixes treated as decimal + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "16909060", oneToFourAddressExpBytes), + // form:'x' method:InetAddress.ofPosixLiteral - + // with leading 0 treated as octal segment prefix + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, + "042", ipv4_0_0_0_34) ); // Generate addresses for loopback and wildcard address test cases @@ -251,7 +362,18 @@ private static Stream invalidLiteralArguments() { Arguments.of(InetAddressClass.INET_ADDRESS, "0x1.2.3.4"), Arguments.of(InetAddressClass.INET4_ADDRESS, "1.2.0x3.4"), Arguments.of(InetAddressClass.INET_ADDRESS, "0xFFFFFFFF"), - Arguments.of(InetAddressClass.INET4_ADDRESS, "0xFFFFFFFF") + Arguments.of(InetAddressClass.INET4_ADDRESS, "0xFFFFFFFF"), + + // invalid IPv4 literals in POSIX/BSD form + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "0x100.1.2.3"), // 0x100 is too large + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "1.2.3.0x100"), + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "127.08.9.1"), // 8, 9 are invalid octals + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "127.8.09.1"), + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "048"), + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, ""), // empty + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "0x1FFFFFFFF"), // 2^33 - 1 is too large + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "0x100000000"), // 2^32 is too large + Arguments.of(InetAddressClass.INET4_ADDRESS_POSIX, "040000000000") ); // Construct arguments for a test case with IPv6-scoped address with scope-id // specified as a string with non-existing network interface name @@ -297,6 +419,7 @@ private static Executable constructExecutable(InetAddressClass inetAddressClass, return switch (inetAddressClass) { case INET_ADDRESS -> () -> InetAddress.ofLiteral(input); case INET4_ADDRESS -> () -> Inet4Address.ofLiteral(input); + case INET4_ADDRESS_POSIX -> () -> Inet4Address.ofPosixLiteral(input); case INET6_ADDRESS -> () -> Inet6Address.ofLiteral(input); }; } @@ -304,6 +427,7 @@ private static Executable constructExecutable(InetAddressClass inetAddressClass, enum InetAddressClass { INET_ADDRESS, INET4_ADDRESS, + INET4_ADDRESS_POSIX, INET6_ADDRESS } } From 1e5a2780d9cc8e73ce65bdccb98c1808aadd0784 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 23 May 2024 07:00:10 +0000 Subject: [PATCH 04/99] 8332676: Remove unused BarrierSetAssembler::incr_allocated_bytes Reviewed-by: tschatzl, kbarrett --- .../gc/shared/barrierSetAssembler_aarch64.cpp | 15 ------- .../gc/shared/barrierSetAssembler_aarch64.hpp | 5 --- .../arm/gc/shared/barrierSetAssembler_arm.cpp | 40 ------------------- .../arm/gc/shared/barrierSetAssembler_arm.hpp | 6 --- src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp | 2 +- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 3 -- src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 1 - .../gc/shared/barrierSetAssembler_riscv.cpp | 15 ------- .../gc/shared/barrierSetAssembler_riscv.hpp | 5 --- .../cpu/s390/c1_MacroAssembler_s390.cpp | 2 +- .../x86/gc/shared/barrierSetAssembler_x86.cpp | 30 -------------- .../x86/gc/shared/barrierSetAssembler_x86.hpp | 6 --- src/hotspot/share/runtime/thread.hpp | 2 - 13 files changed, 2 insertions(+), 130 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp index 6c2b12fc7a8..073d9922355 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.cpp @@ -269,21 +269,6 @@ void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj, // verify_tlab(); } -void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, - Register var_size_in_bytes, - int con_size_in_bytes, - Register t1) { - assert(t1->is_valid(), "need temp reg"); - - __ ldr(t1, Address(rthread, in_bytes(JavaThread::allocated_bytes_offset()))); - if (var_size_in_bytes->is_valid()) { - __ add(t1, t1, var_size_in_bytes); - } else { - __ add(t1, t1, con_size_in_bytes); - } - __ str(t1, Address(rthread, in_bytes(JavaThread::allocated_bytes_offset()))); -} - static volatile uint32_t _patching_epoch = 0; address BarrierSetAssembler::patching_epoch_addr() { diff --git a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp index 8dc475e0597..d0e2aa95888 100644 --- a/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetAssembler_aarch64.hpp @@ -44,11 +44,6 @@ enum class NMethodPatchingType { }; class BarrierSetAssembler: public CHeapObj { -private: - void incr_allocated_bytes(MacroAssembler* masm, - Register var_size_in_bytes, int con_size_in_bytes, - Register t1 = noreg); - public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, Register src, Register dst, Register count, RegSet saved_regs) {} diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp index a4e7f35ec81..ea19730673c 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp @@ -159,46 +159,6 @@ void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj, Regi __ str(obj_end, Address(Rthread, JavaThread::tlab_top_offset())); } -void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, RegisterOrConstant size_in_bytes, Register tmp) { - // Bump total bytes allocated by this thread - Label done; - - // Borrow the Rthread for alloc counter - Register Ralloc = Rthread; - __ add(Ralloc, Ralloc, in_bytes(JavaThread::allocated_bytes_offset())); - __ ldr(tmp, Address(Ralloc)); - __ adds(tmp, tmp, size_in_bytes); - __ str(tmp, Address(Ralloc), cc); - __ b(done, cc); - - // Increment the high word and store single-copy atomically (that is an unlikely scenario on typical embedded systems as it means >4GB has been allocated) - // To do so ldrd/strd instructions used which require an even-odd pair of registers. Such a request could be difficult to satisfy by - // allocating those registers on a higher level, therefore the routine is ready to allocate a pair itself. - Register low, high; - // Select ether R0/R1 or R2/R3 - - if (size_in_bytes.is_register() && (size_in_bytes.as_register() == R0 || size_in_bytes.as_register() == R1)) { - low = R2; - high = R3; - } else { - low = R0; - high = R1; - } - __ push(RegisterSet(low, high)); - - __ ldrd(low, Address(Ralloc)); - __ adds(low, low, size_in_bytes); - __ adc(high, high, 0); - __ strd(low, Address(Ralloc)); - - __ pop(RegisterSet(low, high)); - - __ bind(done); - - // Unborrow the Rthread - __ sub(Rthread, Ralloc, in_bytes(JavaThread::allocated_bytes_offset())); -} - void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); diff --git a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp index ae51a054540..60021390ea2 100644 --- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp @@ -40,12 +40,6 @@ enum class NMethodPatchingType { }; class BarrierSetAssembler: public CHeapObj { -private: - void incr_allocated_bytes(MacroAssembler* masm, - RegisterOrConstant size_in_bytes, - Register tmp -); - public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, Register addr, Register count, int callee_saved_regs) {} diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index 219aeaf316d..9da5a2c6580 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -183,7 +183,7 @@ void C1_MacroAssembler::try_allocate( Register obj, // result: pointer to object after successful allocation Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise int con_size_in_bytes, // object size in bytes if known at compile time - Register t1, // temp register, must be global register for incr_allocated_bytes + Register t1, // temp register Register t2, // temp register Label& slow_case // continuation point if fast allocation fails ) { diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 701cd5cf637..000d4510c07 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2209,9 +2209,6 @@ void MacroAssembler::tlab_allocate( std(new_top, in_bytes(JavaThread::tlab_top_offset()), R16_thread); //verify_tlab(); not implemented } -void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register t1, Register t2) { - unimplemented("incr_allocated_bytes"); -} address MacroAssembler::emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc) { diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 92db8a86b42..5a628674da1 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -626,7 +626,6 @@ class MacroAssembler: public Assembler { Register t1, // temp register Label& slow_case // continuation point if fast allocation fails ); - void incr_allocated_bytes(RegisterOrConstant size_in_bytes, Register t1, Register t2); enum { trampoline_stub_size = 6 * 4 }; address emit_trampoline_stub(int destination_toc_offset, int insts_call_instruction_offset, Register Rtoc = noreg); diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index cbf8de7341d..0f385080977 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -211,21 +211,6 @@ void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj, } } -void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, - Register var_size_in_bytes, - int con_size_in_bytes, - Register tmp1) { - assert(tmp1->is_valid(), "need temp reg"); - - __ ld(tmp1, Address(xthread, in_bytes(JavaThread::allocated_bytes_offset()))); - if (var_size_in_bytes->is_valid()) { - __ add(tmp1, tmp1, var_size_in_bytes); - } else { - __ add(tmp1, tmp1, con_size_in_bytes); - } - __ sd(tmp1, Address(xthread, in_bytes(JavaThread::allocated_bytes_offset()))); -} - static volatile uint32_t _patching_epoch = 0; address BarrierSetAssembler::patching_epoch_addr() { diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp index eb0801d237f..c1f51d768df 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp @@ -45,11 +45,6 @@ enum class NMethodPatchingType { }; class BarrierSetAssembler: public CHeapObj { -private: - void incr_allocated_bytes(MacroAssembler* masm, - Register var_size_in_bytes, int con_size_in_bytes, - Register t1 = noreg); - public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, Register src, Register dst, Register count, RegSet saved_regs) {} diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index 604a8336ff9..c35b0923297 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -164,7 +164,7 @@ void C1_MacroAssembler::try_allocate( Register obj, // result: Pointer to object after successful allocation. Register var_size_in_bytes, // Object size in bytes if unknown at compile time; invalid otherwise. int con_size_in_bytes, // Object size in bytes if known at compile time. - Register t1, // Temp register: Must be global register for incr_allocated_bytes. + Register t1, // Temp register. Label& slow_case // Continuation point if fast allocation fails. ) { if (UseTLAB) { diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp index a6801f594bd..b71b5a2ab47 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -352,36 +352,6 @@ void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, __ verify_tlab(); } -void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, Register thread, - Register var_size_in_bytes, - int con_size_in_bytes, - Register t1) { - if (!thread->is_valid()) { -#ifdef _LP64 - thread = r15_thread; -#else - assert(t1->is_valid(), "need temp reg"); - thread = t1; - __ get_thread(thread); -#endif - } - -#ifdef _LP64 - if (var_size_in_bytes->is_valid()) { - __ addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes); - } else { - __ addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes); - } -#else - if (var_size_in_bytes->is_valid()) { - __ addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes); - } else { - __ addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes); - } - __ adcl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())+4), 0); -#endif -} - #ifdef _LP64 void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slow_path, Label* continuation) { BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp index a74d5cc7676..81797907aed 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp @@ -37,12 +37,6 @@ class Node; class InterpreterMacroAssembler; class BarrierSetAssembler: public CHeapObj { -private: - void incr_allocated_bytes(MacroAssembler* masm, Register thread, - Register var_size_in_bytes, - int con_size_in_bytes, - Register t1); - public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count) {} diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index d0749b8101d..44c845986f3 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -593,8 +593,6 @@ class Thread: public ThreadShadow { static ByteSize tlab_top_offset() { return byte_offset_of(Thread, _tlab) + ThreadLocalAllocBuffer::top_offset(); } static ByteSize tlab_pf_top_offset() { return byte_offset_of(Thread, _tlab) + ThreadLocalAllocBuffer::pf_top_offset(); } - static ByteSize allocated_bytes_offset() { return byte_offset_of(Thread, _allocated_bytes); } - JFR_ONLY(DEFINE_THREAD_LOCAL_OFFSET_JFR;) public: From 94af3c23ea09ef2869cdc666d8170a655a0b3602 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 23 May 2024 07:13:57 +0000 Subject: [PATCH 05/99] 8329203: Parallel: Investigate Mark-Compact for Full GC to decrease memory usage Reviewed-by: rkennke, gli --- .../share/gc/parallel/parMarkBitMap.cpp | 176 +--- .../share/gc/parallel/parMarkBitMap.hpp | 77 +- .../gc/parallel/parMarkBitMap.inline.hpp | 69 +- .../share/gc/parallel/psCompactionManager.cpp | 33 +- .../share/gc/parallel/psCompactionManager.hpp | 37 +- .../parallel/psCompactionManager.inline.hpp | 7 - .../share/gc/parallel/psParallelCompact.cpp | 972 ++++++++---------- .../share/gc/parallel/psParallelCompact.hpp | 248 +---- .../gc/parallel/psParallelCompact.inline.hpp | 33 +- 9 files changed, 517 insertions(+), 1135 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp index deffcc019c9..6452f03b5cb 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.cpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.cpp @@ -37,9 +37,6 @@ bool ParMarkBitMap::initialize(MemRegion covered_region) { const idx_t bits = bits_required(covered_region); - // The bits will be divided evenly between two bitmaps; each of them should be - // an integral number of words. - assert(is_aligned(bits, (BitsPerWord * 2)), "region size unaligned"); const size_t words = bits / BitsPerWord; const size_t raw_bytes = words * sizeof(idx_t); @@ -61,8 +58,7 @@ ParMarkBitMap::initialize(MemRegion covered_region) _region_start = covered_region.start(); _region_size = covered_region.word_size(); BitMap::bm_word_t* map = (BitMap::bm_word_t*)_virtual_space->reserved_low_addr(); - _beg_bits = BitMapView(map, bits / 2); - _end_bits = BitMapView(map + words / 2, bits / 2); + _beg_bits = BitMapView(map, bits); return true; } @@ -77,176 +73,6 @@ ParMarkBitMap::initialize(MemRegion covered_region) return false; } -bool -ParMarkBitMap::mark_obj(HeapWord* addr, size_t size) -{ - const idx_t beg_bit = addr_to_bit(addr); - if (_beg_bits.par_set_bit(beg_bit)) { - const idx_t end_bit = addr_to_bit(addr + size - 1); - bool end_bit_ok = _end_bits.par_set_bit(end_bit); - assert(end_bit_ok, "concurrency problem"); - return true; - } - return false; -} - -inline bool -ParMarkBitMap::is_live_words_in_range_in_cache(ParCompactionManager* cm, HeapWord* beg_addr) const { - return cm->last_query_begin() == beg_addr; -} - -inline void -ParMarkBitMap::update_live_words_in_range_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj, size_t result) const { - cm->set_last_query_begin(beg_addr); - cm->set_last_query_object(end_obj); - cm->set_last_query_return(result); -} - -size_t -ParMarkBitMap::live_words_in_range_helper(HeapWord* beg_addr, oop end_obj) const -{ - assert(beg_addr <= cast_from_oop(end_obj), "bad range"); - assert(is_marked(end_obj), "end_obj must be live"); - - idx_t live_bits = 0; - - // The bitmap routines require the right boundary to be word-aligned. - const idx_t end_bit = addr_to_bit(cast_from_oop(end_obj)); - const idx_t range_end = align_range_end(end_bit); - - idx_t beg_bit = find_obj_beg(addr_to_bit(beg_addr), range_end); - while (beg_bit < end_bit) { - idx_t tmp_end = find_obj_end(beg_bit, range_end); - assert(tmp_end < end_bit, "missing end bit"); - live_bits += tmp_end - beg_bit + 1; - beg_bit = find_obj_beg(tmp_end + 1, range_end); - } - return bits_to_words(live_bits); -} - -size_t -ParMarkBitMap::live_words_in_range_use_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_oop) const -{ - HeapWord* last_beg = cm->last_query_begin(); - HeapWord* last_obj = cast_from_oop(cm->last_query_object()); - HeapWord* end_obj = cast_from_oop(end_oop); - - size_t last_ret = cm->last_query_return(); - if (end_obj > last_obj) { - last_ret = last_ret + live_words_in_range_helper(last_obj, end_oop); - last_obj = end_obj; - } else if (end_obj < last_obj) { - // The cached value is for an object that is to the left (lower address) of the current - // end_obj. Calculate back from that cached value. - if (pointer_delta(end_obj, beg_addr) > pointer_delta(last_obj, end_obj)) { - last_ret = last_ret - live_words_in_range_helper(end_obj, cast_to_oop(last_obj)); - } else { - last_ret = live_words_in_range_helper(beg_addr, end_oop); - } - last_obj = end_obj; - } - - update_live_words_in_range_cache(cm, last_beg, cast_to_oop(last_obj), last_ret); - return last_ret; -} - -size_t -ParMarkBitMap::live_words_in_range(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj) const -{ - // Try to reuse result from ParCompactionManager cache first. - if (is_live_words_in_range_in_cache(cm, beg_addr)) { - return live_words_in_range_use_cache(cm, beg_addr, end_obj); - } - size_t ret = live_words_in_range_helper(beg_addr, end_obj); - update_live_words_in_range_cache(cm, beg_addr, end_obj, ret); - return ret; -} - -ParMarkBitMap::IterationStatus -ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure, - idx_t range_beg, idx_t range_end) const -{ - DEBUG_ONLY(verify_bit(range_beg);) - DEBUG_ONLY(verify_bit(range_end);) - assert(range_beg <= range_end, "live range invalid"); - - // The bitmap routines require the right boundary to be word-aligned. - const idx_t search_end = align_range_end(range_end); - - idx_t cur_beg = range_beg; - while (true) { - cur_beg = find_obj_beg(cur_beg, search_end); - if (cur_beg >= range_end) { - break; - } - - const size_t size = obj_size(cur_beg); - IterationStatus status = live_closure->do_addr(bit_to_addr(cur_beg), size); - if (status != incomplete) { - assert(status == would_overflow || status == full, "sanity"); - return status; - } - - cur_beg += words_to_bits(size); - if (cur_beg >= range_end) { - break; - } - } - - return complete; -} - -ParMarkBitMap::IterationStatus -ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure, - ParMarkBitMapClosure* dead_closure, - idx_t range_beg, idx_t range_end, - idx_t dead_range_end) const -{ - DEBUG_ONLY(verify_bit(range_beg);) - DEBUG_ONLY(verify_bit(range_end);) - DEBUG_ONLY(verify_bit(dead_range_end);) - assert(range_beg <= range_end, "live range invalid"); - assert(range_end <= dead_range_end, "dead range invalid"); - - // The bitmap routines require the right boundary to be word-aligned. - const idx_t dead_search_end = align_range_end(dead_range_end); - - idx_t cur_beg = range_beg; - if (range_beg < range_end && is_unmarked(range_beg)) { - // The range starts with dead space. Look for the next object, then fill. - // This must be the beginning of old/eden/from/to-space, so it's must be - // large enough for a filler. - cur_beg = find_obj_beg(range_beg + 1, dead_search_end); - const idx_t dead_space_end = cur_beg - 1; - const size_t size = obj_size(range_beg, dead_space_end); - dead_closure->do_addr(bit_to_addr(range_beg), size); - } - - while (cur_beg < range_end) { - const size_t size = obj_size(cur_beg); - IterationStatus status = live_closure->do_addr(bit_to_addr(cur_beg), size); - if (status != incomplete) { - assert(status == would_overflow || status == full, "sanity"); - return status; - } - - const idx_t dead_space_beg = cur_beg + words_to_bits(size); - if (dead_space_beg >= dead_search_end) { - break; - } - // Look for the start of the next object. - cur_beg = find_obj_beg(dead_space_beg, dead_search_end); - if (cur_beg > dead_space_beg) { - // Found dead space; compute the size and invoke the dead closure. - const idx_t dead_space_end = cur_beg - 1; - dead_closure->do_addr(bit_to_addr(dead_space_beg), - obj_size(dead_space_beg, dead_space_end)); - } - } - - return complete; -} - #ifdef ASSERT void ParMarkBitMap::verify_clear() const { diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp index ad0e51fdcdf..1975f1e3221 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp @@ -39,18 +39,14 @@ class ParMarkBitMap: public CHeapObj typedef BitMap::idx_t idx_t; // Values returned by the iterate() methods. - enum IterationStatus { incomplete, complete, full, would_overflow }; + enum IterationStatus { incomplete, complete, full }; inline ParMarkBitMap(); bool initialize(MemRegion covered_region); // Atomically mark an object as live. - bool mark_obj(HeapWord* addr, size_t size); - inline bool mark_obj(oop obj, size_t size); - - // Return whether the specified begin or end bit is set. - inline bool is_obj_beg(idx_t bit) const; - inline bool is_obj_end(idx_t bit) const; + inline bool mark_obj(HeapWord* addr); + inline bool mark_obj(oop obj); // Traditional interface for testing whether an object is marked or not (these // test only the begin bits). @@ -68,61 +64,6 @@ class ParMarkBitMap: public CHeapObj inline static size_t bits_to_words(idx_t bits); inline static idx_t words_to_bits(size_t words); - // Return the size in words of an object given a begin bit and an end bit, or - // the equivalent beg_addr and end_addr. - inline size_t obj_size(idx_t beg_bit, idx_t end_bit) const; - inline size_t obj_size(HeapWord* beg_addr, HeapWord* end_addr) const; - - // Return the size in words of the object (a search is done for the end bit). - inline size_t obj_size(idx_t beg_bit) const; - inline size_t obj_size(HeapWord* addr) const; - - // Apply live_closure to each live object that lies completely within the - // range [live_range_beg, live_range_end). This is used to iterate over the - // compacted region of the heap. Return values: - // - // complete The iteration is complete. All objects in the range - // were processed and the closure is not full; - // closure->source() is set one past the end of the range. - // - // full The closure is full; closure->source() is set to one - // past the end of the last object processed. - // - // would_overflow The next object in the range would overflow the closure; - // closure->source() is set to the start of that object. - IterationStatus iterate(ParMarkBitMapClosure* live_closure, - idx_t range_beg, idx_t range_end) const; - inline IterationStatus iterate(ParMarkBitMapClosure* live_closure, - HeapWord* range_beg, - HeapWord* range_end) const; - - // Apply live closure as above and additionally apply dead_closure to all dead - // space in the range [range_beg, dead_range_end). Note that dead_range_end - // must be >= range_end. This is used to iterate over the dense prefix. - // - // This method assumes that if the first bit in the range (range_beg) is not - // marked, then dead space begins at that point and the dead_closure is - // applied. Thus callers must ensure that range_beg is not in the middle of a - // live object. - IterationStatus iterate(ParMarkBitMapClosure* live_closure, - ParMarkBitMapClosure* dead_closure, - idx_t range_beg, idx_t range_end, - idx_t dead_range_end) const; - inline IterationStatus iterate(ParMarkBitMapClosure* live_closure, - ParMarkBitMapClosure* dead_closure, - HeapWord* range_beg, - HeapWord* range_end, - HeapWord* dead_range_end) const; - - // Return the number of live words in the range [beg_addr, end_obj) due to - // objects that start in the range. If a live object extends onto the range, - // the caller must detect and account for any live words due to that object. - // If a live object extends beyond the end of the range, only the words within - // the range are included in the result. The end of the range must be a live object, - // which is the case when updating pointers. This allows a branch to be removed - // from inside the loop. - size_t live_words_in_range(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj) const; - inline HeapWord* region_start() const; inline HeapWord* region_end() const; inline size_t region_size() const; @@ -141,11 +82,12 @@ class ParMarkBitMap: public CHeapObj // respectively) in the range [beg, end). If no object is found, return end. // end must be word-aligned. inline idx_t find_obj_beg(idx_t beg, idx_t end) const; - inline idx_t find_obj_end(idx_t beg, idx_t end) const; inline HeapWord* find_obj_beg(HeapWord* beg, HeapWord* end) const; - inline HeapWord* find_obj_end(HeapWord* beg, HeapWord* end) const; + // Return the address of the last obj-start in the range [beg, end). If no + // object is found, return end. + inline HeapWord* find_obj_beg_reverse(HeapWord* beg, HeapWord* end) const; // Clear a range of bits or the entire bitmap (both begin and end bits are // cleared). inline void clear_range(idx_t beg, idx_t end); @@ -158,7 +100,6 @@ class ParMarkBitMap: public CHeapObj void print_on_error(outputStream* st) const { st->print_cr("Marking Bits: (ParMarkBitMap*) " PTR_FORMAT, p2i(this)); _beg_bits.print_on_error(st, " Begin Bits: "); - _end_bits.print_on_error(st, " End Bits: "); } #ifdef ASSERT @@ -168,11 +109,6 @@ class ParMarkBitMap: public CHeapObj #endif // #ifdef ASSERT private: - size_t live_words_in_range_helper(HeapWord* beg_addr, oop end_obj) const; - - bool is_live_words_in_range_in_cache(ParCompactionManager* cm, HeapWord* beg_addr) const; - size_t live_words_in_range_use_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj) const; - void update_live_words_in_range_cache(ParCompactionManager* cm, HeapWord* beg_addr, oop end_obj, size_t result) const; // Each bit in the bitmap represents one unit of 'object granularity.' Objects // are double-word aligned in 32-bit VMs, but not in 64-bit VMs, so the 32-bit @@ -183,7 +119,6 @@ class ParMarkBitMap: public CHeapObj HeapWord* _region_start; size_t _region_size; BitMapView _beg_bits; - BitMapView _end_bits; PSVirtualSpace* _virtual_space; size_t _reserved_byte_size; }; diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp index f1dabaf3580..98c2fcc1981 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp @@ -31,18 +31,15 @@ #include "utilities/bitMap.inline.hpp" inline ParMarkBitMap::ParMarkBitMap(): - _region_start(nullptr), _region_size(0), _beg_bits(), _end_bits(), _virtual_space(nullptr), _reserved_byte_size(0) + _region_start(nullptr), _region_size(0), _beg_bits(), _virtual_space(nullptr), _reserved_byte_size(0) { } inline void ParMarkBitMap::clear_range(idx_t beg, idx_t end) { _beg_bits.clear_range(beg, end); - _end_bits.clear_range(beg, end); } inline ParMarkBitMap::idx_t ParMarkBitMap::bits_required(size_t words) { - // Need two bits (one begin bit, one end bit) for each unit of 'object - // granularity' in the heap. - return words_to_bits(words * 2); + return words_to_bits(words); } inline ParMarkBitMap::idx_t ParMarkBitMap::bits_required(MemRegion covered_region) { @@ -65,16 +62,8 @@ inline size_t ParMarkBitMap::size() const { return _beg_bits.size(); } -inline bool ParMarkBitMap::is_obj_beg(idx_t bit) const { - return _beg_bits.at(bit); -} - -inline bool ParMarkBitMap::is_obj_end(idx_t bit) const { - return _end_bits.at(bit); -} - inline bool ParMarkBitMap::is_marked(idx_t bit) const { - return is_obj_beg(bit); + return _beg_bits.at(bit); } inline bool ParMarkBitMap::is_marked(HeapWord* addr) const { @@ -105,47 +94,12 @@ inline ParMarkBitMap::idx_t ParMarkBitMap::words_to_bits(size_t words) { return words >> obj_granularity_shift(); } -inline size_t ParMarkBitMap::obj_size(idx_t beg_bit, idx_t end_bit) const { - DEBUG_ONLY(verify_bit(beg_bit);) - DEBUG_ONLY(verify_bit(end_bit);) - return bits_to_words(end_bit - beg_bit + 1); -} - -inline size_t ParMarkBitMap::obj_size(HeapWord* beg_addr, HeapWord* end_addr) const { - DEBUG_ONLY(verify_addr(beg_addr);) - DEBUG_ONLY(verify_addr(end_addr);) - return pointer_delta(end_addr, beg_addr) + obj_granularity(); -} - -inline size_t ParMarkBitMap::obj_size(idx_t beg_bit) const { - const idx_t end_bit = _end_bits.find_first_set_bit(beg_bit, size()); - assert(is_marked(beg_bit), "obj not marked"); - assert(end_bit < size(), "end bit missing"); - return obj_size(beg_bit, end_bit); +inline bool ParMarkBitMap::mark_obj(HeapWord* addr) { + return _beg_bits.par_set_bit(addr_to_bit(addr)); } -inline size_t ParMarkBitMap::obj_size(HeapWord* addr) const { - return obj_size(addr_to_bit(addr)); -} - -inline ParMarkBitMap::IterationStatus ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure, - HeapWord* range_beg, - HeapWord* range_end) const { - return iterate(live_closure, addr_to_bit(range_beg), addr_to_bit(range_end)); -} - -inline ParMarkBitMap::IterationStatus ParMarkBitMap::iterate(ParMarkBitMapClosure* live_closure, - ParMarkBitMapClosure* dead_closure, - HeapWord* range_beg, - HeapWord* range_end, - HeapWord* dead_range_end) const { - return iterate(live_closure, dead_closure, - addr_to_bit(range_beg), addr_to_bit(range_end), - addr_to_bit(dead_range_end)); -} - -inline bool ParMarkBitMap::mark_obj(oop obj, size_t size) { - return mark_obj(cast_from_oop(obj), size); +inline bool ParMarkBitMap::mark_obj(oop obj) { + return mark_obj(cast_from_oop(obj)); } inline ParMarkBitMap::idx_t ParMarkBitMap::addr_to_bit(HeapWord* addr) const { @@ -168,10 +122,6 @@ inline ParMarkBitMap::idx_t ParMarkBitMap::find_obj_beg(idx_t beg, idx_t end) co return _beg_bits.find_first_set_bit_aligned_right(beg, end); } -inline ParMarkBitMap::idx_t ParMarkBitMap::find_obj_end(idx_t beg, idx_t end) const { - return _end_bits.find_first_set_bit_aligned_right(beg, end); -} - inline HeapWord* ParMarkBitMap::find_obj_beg(HeapWord* beg, HeapWord* end) const { const idx_t beg_bit = addr_to_bit(beg); const idx_t end_bit = addr_to_bit(end); @@ -180,11 +130,10 @@ inline HeapWord* ParMarkBitMap::find_obj_beg(HeapWord* beg, HeapWord* end) const return bit_to_addr(res_bit); } -inline HeapWord* ParMarkBitMap::find_obj_end(HeapWord* beg, HeapWord* end) const { +inline HeapWord* ParMarkBitMap::find_obj_beg_reverse(HeapWord* beg, HeapWord* end) const { const idx_t beg_bit = addr_to_bit(beg); const idx_t end_bit = addr_to_bit(end); - const idx_t search_end = align_range_end(end_bit); - const idx_t res_bit = MIN2(find_obj_end(beg_bit, search_end), end_bit); + const idx_t res_bit = _beg_bits.find_last_set_bit_aligned_left(beg_bit, end_bit); return bit_to_addr(res_bit); } diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.cpp b/src/hotspot/share/gc/parallel/psCompactionManager.cpp index fe9bcbff703..b95c7c619af 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.cpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.cpp @@ -29,6 +29,7 @@ #include "gc/parallel/psCompactionManager.inline.hpp" #include "gc/parallel/psOldGen.hpp" #include "gc/parallel/psParallelCompact.inline.hpp" +#include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "logging/log.hpp" #include "memory/iterator.inline.hpp" @@ -51,16 +52,16 @@ ParMarkBitMap* ParCompactionManager::_mark_bitmap = nullptr; GrowableArray* ParCompactionManager::_shadow_region_array = nullptr; Monitor* ParCompactionManager::_shadow_region_monitor = nullptr; -ParCompactionManager::ParCompactionManager() { +PreservedMarksSet* ParCompactionManager::_preserved_marks_set = nullptr; + +ParCompactionManager::ParCompactionManager(PreservedMarks* preserved_marks) { ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); _old_gen = heap->old_gen(); _start_array = old_gen()->start_array(); - reset_bitmap_query_cache(); - - _deferred_obj_array = new (mtGC) GrowableArray(10, mtGC); + _preserved_marks = preserved_marks; _marking_stats_cache = nullptr; } @@ -79,9 +80,12 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { _objarray_task_queues = new ObjArrayTaskQueueSet(parallel_gc_threads); _region_task_queues = new RegionTaskQueueSet(parallel_gc_threads); + _preserved_marks_set = new PreservedMarksSet(true); + _preserved_marks_set->init(parallel_gc_threads); + // Create and register the ParCompactionManager(s) for the worker threads. for(uint i=0; iget(i)); oop_task_queues()->register_queue(i, _manager_array[i]->oop_stack()); _objarray_task_queues->register_queue(i, &_manager_array[i]->_objarray_stack); region_task_queues()->register_queue(i, _manager_array[i]->region_stack()); @@ -93,13 +97,7 @@ void ParCompactionManager::initialize(ParMarkBitMap* mbm) { _shadow_region_array = new (mtGC) GrowableArray(10, mtGC); _shadow_region_monitor = new Monitor(Mutex::nosafepoint, "CompactionManager_lock"); -} -void ParCompactionManager::reset_all_bitmap_query_caches() { - uint parallel_gc_threads = ParallelScavengeHeap::heap()->workers().max_workers(); - for (uint i=0; ireset_bitmap_query_cache(); - } } void ParCompactionManager::flush_all_string_dedup_requests() { @@ -168,15 +166,6 @@ void ParCompactionManager::drain_region_stacks() { } while (!region_stack()->is_empty()); } -void ParCompactionManager::drain_deferred_objects() { - while (!_deferred_obj_array->is_empty()) { - HeapWord* addr = _deferred_obj_array->pop(); - assert(addr != nullptr, "expected a deferred object"); - PSParallelCompact::update_deferred_object(this, addr); - } - _deferred_obj_array->clear_and_deallocate(); -} - size_t ParCompactionManager::pop_shadow_region_mt_safe(PSParallelCompact::RegionData* region_ptr) { MonitorLocker ml(_shadow_region_monitor, Mutex::_no_safepoint_check_flag); while (true) { @@ -207,10 +196,6 @@ void ParCompactionManager::remove_all_shadow_regions() { _shadow_region_array->clear(); } -void ParCompactionManager::push_deferred_object(HeapWord* addr) { - _deferred_obj_array->push(addr); -} - #ifdef ASSERT void ParCompactionManager::verify_all_marking_stack_empty() { uint parallel_gc_threads = ParallelGCThreads; diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.hpp index b33ad06ee3e..0dd68d2e2f7 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_PARALLEL_PSCOMPACTIONMANAGER_HPP #include "gc/parallel/psParallelCompact.hpp" +#include "gc/shared/preservedMarks.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.hpp" #include "gc/shared/taskTerminator.hpp" @@ -45,7 +46,7 @@ class ParCompactionManager : public CHeapObj { friend class ParallelScavengeRefProcProxyTask; friend class ParMarkBitMap; friend class PSParallelCompact; - friend class UpdateDensePrefixAndCompactionTask; + friend class FillDensePrefixAndCompactionTask; private: typedef OverflowTaskQueue OopTaskQueue; @@ -75,7 +76,8 @@ class ParCompactionManager : public CHeapObj { // type of TaskQueue. RegionTaskQueue _region_stack; - GrowableArray* _deferred_obj_array; + static PreservedMarksSet* _preserved_marks_set; + PreservedMarks* _preserved_marks; static ParMarkBitMap* _mark_bitmap; @@ -87,10 +89,6 @@ class ParCompactionManager : public CHeapObj { // See pop/push_shadow_region_mt_safe() below static Monitor* _shadow_region_monitor; - HeapWord* _last_query_beg; - oop _last_query_obj; - size_t _last_query_ret; - StringDedup::Requests _string_dedup_requests; static PSOldGen* old_gen() { return _old_gen; } @@ -106,7 +104,7 @@ class ParCompactionManager : public CHeapObj { // objArray stack, otherwise returns false and the task is invalid. bool publish_or_pop_objarray_tasks(ObjArrayTask& task); - ParCompactionManager(); + ParCompactionManager(PreservedMarks* preserved_marks); // Array of task queues. Needed by the task terminator. static RegionTaskQueueSet* region_task_queues() { return _region_task_queues; } OopTaskQueue* oop_stack() { return &_oop_stack; } @@ -153,29 +151,10 @@ class ParCompactionManager : public CHeapObj { return next_shadow_region(); } - void push_deferred_object(HeapWord* addr); - - void reset_bitmap_query_cache() { - _last_query_beg = nullptr; - _last_query_obj = nullptr; - _last_query_ret = 0; - } - void flush_string_dedup_requests() { _string_dedup_requests.flush(); } - // Bitmap query support, cache last query and result - HeapWord* last_query_begin() { return _last_query_beg; } - oop last_query_object() { return _last_query_obj; } - size_t last_query_return() { return _last_query_ret; } - - void set_last_query_begin(HeapWord *new_beg) { _last_query_beg = new_beg; } - void set_last_query_object(oop new_obj) { _last_query_obj = new_obj; } - void set_last_query_return(size_t new_ret) { _last_query_ret = new_ret; } - - static void reset_all_bitmap_query_caches(); - static void flush_all_string_dedup_requests(); RegionTaskQueue* region_stack() { return &_region_stack; } @@ -184,6 +163,9 @@ class ParCompactionManager : public CHeapObj { // Simply use the first compaction manager here. static ParCompactionManager* get_vmthread_cm() { return _manager_array[0]; } + PreservedMarks* preserved_marks() const { + return _preserved_marks; + } ParMarkBitMap* mark_bitmap() { return _mark_bitmap; } @@ -208,13 +190,10 @@ class ParCompactionManager : public CHeapObj { // Process tasks remaining on any stack void drain_region_stacks(); - void drain_deferred_objects(); void follow_contents(oop obj); void follow_array(objArrayOop array, int index); - void update_contents(oop obj); - class FollowStackClosure: public VoidClosure { private: ParCompactionManager* _compaction_manager; diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp index ae2e449e0b6..64b0da58fda 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp @@ -157,13 +157,6 @@ inline void ParCompactionManager::follow_array(objArrayOop obj, int index) { } } -inline void ParCompactionManager::update_contents(oop obj) { - if (!obj->klass()->is_typeArray_klass()) { - PCAdjustPointerClosure apc(this); - obj->oop_iterate(&apc); - } -} - inline void ParCompactionManager::follow_contents(oop obj) { assert(PSParallelCompact::mark_bitmap()->is_marked(obj), "should be marked"); PCIterateMarkAndPushClosure cl(this, PSParallelCompact::ref_processor()); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 994bdc847cf..e72fa42e6f6 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -30,6 +30,7 @@ #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "compiler/oopMap.hpp" +#include "gc/parallel/objectStartArray.inline.hpp" #include "gc/parallel/parallelArguments.hpp" #include "gc/parallel/parallelScavengeHeap.inline.hpp" #include "gc/parallel/parMarkBitMap.inline.hpp" @@ -54,6 +55,7 @@ #include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageSet.inline.hpp" #include "gc/shared/oopStorageSetParState.inline.hpp" +#include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" @@ -98,24 +100,13 @@ // All sizes are in HeapWords. const size_t ParallelCompactData::Log2RegionSize = 16; // 64K words const size_t ParallelCompactData::RegionSize = (size_t)1 << Log2RegionSize; +static_assert(ParallelCompactData::RegionSize >= BitsPerWord, "region-start bit word-aligned"); const size_t ParallelCompactData::RegionSizeBytes = RegionSize << LogHeapWordSize; const size_t ParallelCompactData::RegionSizeOffsetMask = RegionSize - 1; const size_t ParallelCompactData::RegionAddrOffsetMask = RegionSizeBytes - 1; const size_t ParallelCompactData::RegionAddrMask = ~RegionAddrOffsetMask; -const size_t ParallelCompactData::Log2BlockSize = 7; // 128 words -const size_t ParallelCompactData::BlockSize = (size_t)1 << Log2BlockSize; -const size_t ParallelCompactData::BlockSizeBytes = - BlockSize << LogHeapWordSize; -const size_t ParallelCompactData::BlockSizeOffsetMask = BlockSize - 1; -const size_t ParallelCompactData::BlockAddrOffsetMask = BlockSizeBytes - 1; -const size_t ParallelCompactData::BlockAddrMask = ~BlockAddrOffsetMask; - -const size_t ParallelCompactData::BlocksPerRegion = RegionSize / BlockSize; -const size_t ParallelCompactData::Log2BlocksPerRegion = - Log2RegionSize - Log2BlockSize; - const ParallelCompactData::RegionData::region_sz_t ParallelCompactData::RegionData::dc_shift = 27; @@ -412,10 +403,7 @@ ParallelCompactData::ParallelCompactData() : _region_vspace(nullptr), _reserved_byte_size(0), _region_data(nullptr), - _region_count(0), - _block_vspace(nullptr), - _block_data(nullptr), - _block_count(0) {} + _region_count(0) {} bool ParallelCompactData::initialize(MemRegion reserved_heap) { @@ -426,8 +414,7 @@ bool ParallelCompactData::initialize(MemRegion reserved_heap) assert(region_align_down(_heap_start) == _heap_start, "region start not aligned"); - bool result = initialize_region_data(heap_size) && initialize_block_data(); - return result; + return initialize_region_data(heap_size); } PSVirtualSpace* @@ -473,44 +460,12 @@ bool ParallelCompactData::initialize_region_data(size_t heap_size) return false; } -bool ParallelCompactData::initialize_block_data() -{ - assert(_region_count != 0, "region data must be initialized first"); - const size_t count = _region_count << Log2BlocksPerRegion; - _block_vspace = create_vspace(count, sizeof(BlockData)); - if (_block_vspace != 0) { - _block_data = (BlockData*)_block_vspace->reserved_low_addr(); - _block_count = count; - return true; - } - return false; -} - void ParallelCompactData::clear_range(size_t beg_region, size_t end_region) { assert(beg_region <= _region_count, "beg_region out of range"); assert(end_region <= _region_count, "end_region out of range"); - assert(RegionSize % BlockSize == 0, "RegionSize not a multiple of BlockSize"); const size_t region_cnt = end_region - beg_region; memset(_region_data + beg_region, 0, region_cnt * sizeof(RegionData)); - - const size_t beg_block = beg_region * BlocksPerRegion; - const size_t block_cnt = region_cnt * BlocksPerRegion; - memset(_block_data + beg_block, 0, block_cnt * sizeof(BlockData)); -} - -HeapWord* ParallelCompactData::partial_obj_end(size_t region_idx) const -{ - const RegionData* cur_cp = region(region_idx); - const RegionData* const end_cp = region(region_count() - 1); - - HeapWord* result = region_to_addr(region_idx); - if (cur_cp < end_cp) { - do { - result += cur_cp->partial_obj_size(); - } while (cur_cp->partial_obj_size() == RegionSize && ++cur_cp < end_cp); - } - return result; } void @@ -761,49 +716,6 @@ bool ParallelCompactData::summarize(SplitInfo& split_info, return true; } -HeapWord* ParallelCompactData::calc_new_pointer(HeapWord* addr, ParCompactionManager* cm) const { - assert(addr != nullptr, "Should detect null oop earlier"); - assert(ParallelScavengeHeap::heap()->is_in(addr), "not in heap"); - assert(PSParallelCompact::mark_bitmap()->is_marked(addr), "not marked"); - - // Region covering the object. - RegionData* const region_ptr = addr_to_region_ptr(addr); - HeapWord* result = region_ptr->destination(); - - // If the entire Region is live, the new location is region->destination + the - // offset of the object within in the Region. - - // Run some performance tests to determine if this special case pays off. It - // is worth it for pointers into the dense prefix. If the optimization to - // avoid pointer updates in regions that only point to the dense prefix is - // ever implemented, this should be revisited. - if (region_ptr->data_size() == RegionSize) { - result += region_offset(addr); - return result; - } - - // Otherwise, the new location is region->destination + block offset + the - // number of live words in the Block that are (a) to the left of addr and (b) - // due to objects that start in the Block. - - // Fill in the block table if necessary. This is unsynchronized, so multiple - // threads may fill the block table for a region (harmless, since it is - // idempotent). - if (!region_ptr->blocks_filled()) { - PSParallelCompact::fill_blocks(addr_to_region_idx(addr)); - region_ptr->set_blocks_filled(); - } - - HeapWord* const search_start = block_align_down(addr); - const size_t block_offset = addr_to_block_ptr(addr)->offset(); - - const ParMarkBitMap* bitmap = PSParallelCompact::mark_bitmap(); - const size_t live = bitmap->live_words_in_range(cm, search_start, cast_to_oop(addr)); - result += block_offset + live; - DEBUG_ONLY(PSParallelCompact::check_new_location(addr, result)); - return result; -} - #ifdef ASSERT void ParallelCompactData::verify_clear(const PSVirtualSpace* vspace) { @@ -817,7 +729,6 @@ void ParallelCompactData::verify_clear(const PSVirtualSpace* vspace) void ParallelCompactData::verify_clear() { verify_clear(_region_vspace); - verify_clear(_block_vspace); } #endif // #ifdef ASSERT @@ -831,6 +742,19 @@ ParallelCompactData PSParallelCompact::_summary_data; PSParallelCompact::IsAliveClosure PSParallelCompact::_is_alive_closure; +class PCAdjustPointerClosure: public BasicOopIterateClosure { + template + void do_oop_work(T* p) { PSParallelCompact::adjust_pointer(p); } + +public: + virtual void do_oop(oop* p) { do_oop_work(p); } + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + + virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; } +}; + +static PCAdjustPointerClosure pc_adjust_pointer_closure; + bool PSParallelCompact::IsAliveClosure::do_object_b(oop p) { return mark_bitmap()->is_marked(p); } void PSParallelCompact::post_initialize() { @@ -947,8 +871,6 @@ void PSParallelCompact::pre_compact() DEBUG_ONLY(mark_bitmap()->verify_clear();) DEBUG_ONLY(summary_data().verify_clear();) - - ParCompactionManager::reset_all_bitmap_query_caches(); } void PSParallelCompact::post_compact() @@ -1082,18 +1004,20 @@ void PSParallelCompact::fill_dense_prefix_end(SpaceId id) { idx_t const dense_prefix_bit = _mark_bitmap.addr_to_bit(dense_prefix_end); if (region_after_dense_prefix->partial_obj_size() != 0 || - _mark_bitmap.is_obj_beg(dense_prefix_bit)) { + _mark_bitmap.is_marked(dense_prefix_bit)) { // The region after the dense prefix starts with live bytes. return; } - if (_mark_bitmap.is_obj_end(dense_prefix_bit - 2)) { + HeapWord* block_start = start_array(id)->block_start_reaching_into_card(dense_prefix_end); + if (block_start == dense_prefix_end - 1) { + assert(!_mark_bitmap.is_marked(block_start), "inv"); // There is exactly one heap word gap right before the dense prefix end, so we need a filler object. - // The filler object will extend into the region after the last dense prefix region. + // The filler object will extend into region_after_dense_prefix. const size_t obj_len = 2; // min-fill-size HeapWord* const obj_beg = dense_prefix_end - 1; CollectedHeap::fill_with_object(obj_beg, obj_len); - _mark_bitmap.mark_obj(obj_beg, obj_len); + _mark_bitmap.mark_obj(obj_beg); _summary_data.addr_to_region_ptr(obj_beg)->add_live_obj(1); region_after_dense_prefix->set_partial_obj_size(1); region_after_dense_prefix->set_partial_obj_addr(obj_beg); @@ -1359,12 +1283,14 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { DerivedPointerTable::set_active(false); #endif - // adjust_roots() updates Universe::_intArrayKlass which is - // needed by the compaction for filling holes in the dense prefix. - adjust_roots(); + forward_to_new_addr(); + + adjust_pointers(); compact(); + ParCompactionManager::_preserved_marks_set->restore(&ParallelScavengeHeap::heap()->workers()); + ParCompactionManager::verify_all_region_stack_empty(); // Reset the mark bitmap, summary data, and do other bookkeeping. Must be @@ -1685,11 +1611,90 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) { #endif } +template +void PSParallelCompact::adjust_in_space_helper(SpaceId id, volatile uint* claim_counter, Func&& on_stripe) { + MutableSpace* sp = PSParallelCompact::space(id); + HeapWord* const bottom = sp->bottom(); + HeapWord* const top = sp->top(); + if (bottom == top) { + return; + } + + const uint num_regions_per_stripe = 2; + const size_t region_size = ParallelCompactData::RegionSize; + const size_t stripe_size = num_regions_per_stripe * region_size; + + while (true) { + uint counter = Atomic::fetch_then_add(claim_counter, num_regions_per_stripe); + HeapWord* cur_stripe = bottom + counter * region_size; + if (cur_stripe >= top) { + break; + } + HeapWord* stripe_end = MIN2(cur_stripe + stripe_size, top); + on_stripe(cur_stripe, stripe_end); + } +} + +void PSParallelCompact::adjust_in_old_space(volatile uint* claim_counter) { + // Regions in old-space shouldn't be split. + assert(!_space_info[old_space_id].split_info().is_valid(), "inv"); + + auto scan_obj_with_limit = [&] (HeapWord* obj_start, HeapWord* left, HeapWord* right) { + assert(mark_bitmap()->is_marked(obj_start), "inv"); + oop obj = cast_to_oop(obj_start); + return obj->oop_iterate_size(&pc_adjust_pointer_closure, MemRegion(left, right)); + }; + + adjust_in_space_helper(old_space_id, claim_counter, [&] (HeapWord* stripe_start, HeapWord* stripe_end) { + assert(_summary_data.is_region_aligned(stripe_start), "inv"); + RegionData* cur_region = _summary_data.addr_to_region_ptr(stripe_start); + HeapWord* obj_start; + if (cur_region->partial_obj_size() != 0) { + obj_start = cur_region->partial_obj_addr(); + obj_start += scan_obj_with_limit(obj_start, stripe_start, stripe_end); + } else { + obj_start = stripe_start; + } + + while (obj_start < stripe_end) { + obj_start = mark_bitmap()->find_obj_beg(obj_start, stripe_end); + if (obj_start >= stripe_end) { + break; + } + obj_start += scan_obj_with_limit(obj_start, stripe_start, stripe_end); + } + }); +} + +void PSParallelCompact::adjust_in_young_space(SpaceId id, volatile uint* claim_counter) { + adjust_in_space_helper(id, claim_counter, [](HeapWord* stripe_start, HeapWord* stripe_end) { + HeapWord* obj_start = stripe_start; + while (obj_start < stripe_end) { + obj_start = mark_bitmap()->find_obj_beg(obj_start, stripe_end); + if (obj_start >= stripe_end) { + break; + } + oop obj = cast_to_oop(obj_start); + obj_start += obj->oop_iterate_size(&pc_adjust_pointer_closure); + } + }); +} + +void PSParallelCompact::adjust_pointers_in_spaces(uint worker_id, volatile uint* claim_counters) { + auto start_time = Ticks::now(); + adjust_in_old_space(&claim_counters[0]); + for (uint id = eden_space_id; id < last_space_id; ++id) { + adjust_in_young_space(SpaceId(id), &claim_counters[id]); + } + log_trace(gc, phases)("adjust_pointers_in_spaces worker %u: %.3f ms", worker_id, (Ticks::now() - start_time).seconds() * 1000); +} + class PSAdjustTask final : public WorkerTask { SubTasksDone _sub_tasks; WeakProcessor::Task _weak_proc_task; OopStorageSetStrongParState _oop_storage_iter; uint _nworkers; + volatile uint _claim_counters[PSParallelCompact::last_space_id] = {}; enum PSAdjustSubTask { PSAdjustSubTask_code_cache, @@ -1716,36 +1721,165 @@ class PSAdjustTask final : public WorkerTask { void work(uint worker_id) { ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); - PCAdjustPointerClosure adjust(cm); + cm->preserved_marks()->adjust_during_full_gc(); + { + // adjust pointers in all spaces + PSParallelCompact::adjust_pointers_in_spaces(worker_id, _claim_counters); + } { ResourceMark rm; - Threads::possibly_parallel_oops_do(_nworkers > 1, &adjust, nullptr); + Threads::possibly_parallel_oops_do(_nworkers > 1, &pc_adjust_pointer_closure, nullptr); } - _oop_storage_iter.oops_do(&adjust); + _oop_storage_iter.oops_do(&pc_adjust_pointer_closure); { - CLDToOopClosure cld_closure(&adjust, ClassLoaderData::_claim_stw_fullgc_adjust); + CLDToOopClosure cld_closure(&pc_adjust_pointer_closure, ClassLoaderData::_claim_stw_fullgc_adjust); ClassLoaderDataGraph::cld_do(&cld_closure); } { AlwaysTrueClosure always_alive; - _weak_proc_task.work(worker_id, &always_alive, &adjust); + _weak_proc_task.work(worker_id, &always_alive, &pc_adjust_pointer_closure); } if (_sub_tasks.try_claim_task(PSAdjustSubTask_code_cache)) { - NMethodToOopClosure adjust_code(&adjust, NMethodToOopClosure::FixRelocations); + NMethodToOopClosure adjust_code(&pc_adjust_pointer_closure, NMethodToOopClosure::FixRelocations); CodeCache::nmethods_do(&adjust_code); } _sub_tasks.all_tasks_claimed(); } }; -void PSParallelCompact::adjust_roots() { +void PSParallelCompact::adjust_pointers() { // Adjust the pointers to reflect the new locations - GCTraceTime(Info, gc, phases) tm("Adjust Roots", &_gc_timer); + GCTraceTime(Info, gc, phases) tm("Adjust Pointers", &_gc_timer); uint nworkers = ParallelScavengeHeap::heap()->workers().active_workers(); PSAdjustTask task(nworkers); ParallelScavengeHeap::heap()->workers().run_task(&task); } +// Split [start, end) evenly for a number of workers and return the +// range for worker_id. +static void split_regions_for_worker(size_t start, size_t end, + uint worker_id, uint num_workers, + size_t* worker_start, size_t* worker_end) { + assert(start < end, "precondition"); + assert(num_workers > 0, "precondition"); + assert(worker_id < num_workers, "precondition"); + + size_t num_regions = end - start; + size_t num_regions_per_worker = num_regions / num_workers; + size_t remainder = num_regions % num_workers; + // The first few workers will get one extra. + *worker_start = start + worker_id * num_regions_per_worker + + MIN2(checked_cast(worker_id), remainder); + *worker_end = *worker_start + num_regions_per_worker + + (worker_id < remainder ? 1 : 0); +} + +void PSParallelCompact::forward_to_new_addr() { + GCTraceTime(Info, gc, phases) tm("Forward", &_gc_timer); + uint nworkers = ParallelScavengeHeap::heap()->workers().active_workers(); + + struct ForwardTask final : public WorkerTask { + uint _num_workers; + + explicit ForwardTask(uint num_workers) : + WorkerTask("PSForward task"), + _num_workers(num_workers) {} + + void work(uint worker_id) override { + ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); + for (uint id = old_space_id; id < last_space_id; ++id) { + MutableSpace* sp = PSParallelCompact::space(SpaceId(id)); + HeapWord* dense_prefix_addr = dense_prefix(SpaceId(id)); + HeapWord* top = sp->top(); + + if (dense_prefix_addr == top) { + continue; + } + + size_t dense_prefix_region = _summary_data.addr_to_region_idx(dense_prefix_addr); + size_t top_region = _summary_data.addr_to_region_idx(_summary_data.region_align_up(top)); + size_t start_region; + size_t end_region; + split_regions_for_worker(dense_prefix_region, top_region, + worker_id, _num_workers, + &start_region, &end_region); + for (size_t cur_region = start_region; cur_region < end_region; ++cur_region) { + RegionData* region_ptr = _summary_data.region(cur_region); + size_t live_words = region_ptr->partial_obj_size(); + + if (live_words == ParallelCompactData::RegionSize) { + // No obj-start + continue; + } + + HeapWord* region_start = _summary_data.region_to_addr(cur_region); + HeapWord* region_end = region_start + ParallelCompactData::RegionSize; + + HeapWord* cur_addr = region_start + live_words; + + HeapWord* destination = region_ptr->destination(); + while (cur_addr < region_end) { + cur_addr = mark_bitmap()->find_obj_beg(cur_addr, region_end); + if (cur_addr >= region_end) { + break; + } + assert(mark_bitmap()->is_marked(cur_addr), "inv"); + HeapWord* new_addr = destination + live_words; + oop obj = cast_to_oop(cur_addr); + if (new_addr != cur_addr) { + cm->preserved_marks()->push_if_necessary(obj, obj->mark()); + obj->forward_to(cast_to_oop(new_addr)); + } + size_t obj_size = obj->size(); + live_words += obj_size; + cur_addr += obj_size; + } + } + } + } + } task(nworkers); + + ParallelScavengeHeap::heap()->workers().run_task(&task); + debug_only(verify_forward();) +} + +#ifdef ASSERT +void PSParallelCompact::verify_forward() { + HeapWord* old_dense_prefix_addr = dense_prefix(SpaceId(old_space_id)); + RegionData* old_region = _summary_data.region(_summary_data.addr_to_region_idx(old_dense_prefix_addr)); + HeapWord* bump_ptr = old_region->partial_obj_size() != 0 + ? old_dense_prefix_addr + old_region->partial_obj_size() + : old_dense_prefix_addr; + SpaceId bump_ptr_space = old_space_id; + + for (uint id = old_space_id; id < last_space_id; ++id) { + MutableSpace* sp = PSParallelCompact::space(SpaceId(id)); + HeapWord* dense_prefix_addr = dense_prefix(SpaceId(id)); + HeapWord* top = sp->top(); + HeapWord* cur_addr = dense_prefix_addr; + + while (cur_addr < top) { + cur_addr = mark_bitmap()->find_obj_beg(cur_addr, top); + if (cur_addr >= top) { + break; + } + assert(mark_bitmap()->is_marked(cur_addr), "inv"); + // Move to the space containing cur_addr + if (bump_ptr == _space_info[bump_ptr_space].new_top()) { + bump_ptr = space(space_id(cur_addr))->bottom(); + bump_ptr_space = space_id(bump_ptr); + } + oop obj = cast_to_oop(cur_addr); + if (cur_addr != bump_ptr) { + assert(obj->forwardee() == cast_to_oop(bump_ptr), "inv"); + } + bump_ptr += obj->size(); + cur_addr += obj->size(); + } + } +} +#endif + // Helper class to print 8 region numbers per line and then print the total at the end. class FillableRegionLogger : public StackObj { private: @@ -1826,160 +1960,6 @@ void PSParallelCompact::prepare_region_draining_tasks(uint parallel_gc_threads) } } -class TaskQueue : StackObj { - volatile uint _counter; - uint _size; - uint _insert_index; - PSParallelCompact::UpdateDensePrefixTask* _backing_array; -public: - explicit TaskQueue(uint size) : _counter(0), _size(size), _insert_index(0), _backing_array(nullptr) { - _backing_array = NEW_C_HEAP_ARRAY(PSParallelCompact::UpdateDensePrefixTask, _size, mtGC); - } - ~TaskQueue() { - assert(_counter >= _insert_index, "not all queue elements were claimed"); - FREE_C_HEAP_ARRAY(T, _backing_array); - } - - void push(const PSParallelCompact::UpdateDensePrefixTask& value) { - assert(_insert_index < _size, "too small backing array"); - _backing_array[_insert_index++] = value; - } - - bool try_claim(PSParallelCompact::UpdateDensePrefixTask& reference) { - uint claimed = Atomic::fetch_then_add(&_counter, 1u); - if (claimed < _insert_index) { - reference = _backing_array[claimed]; - return true; - } else { - return false; - } - } -}; - -#define PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING 4 - -void PSParallelCompact::enqueue_dense_prefix_tasks(TaskQueue& task_queue, - uint parallel_gc_threads) { - GCTraceTime(Trace, gc, phases) tm("Dense Prefix Task Setup", &_gc_timer); - - ParallelCompactData& sd = PSParallelCompact::summary_data(); - - // Iterate over all the spaces adding tasks for updating - // regions in the dense prefix. Assume that 1 gc thread - // will work on opening the gaps and the remaining gc threads - // will work on the dense prefix. - unsigned int space_id; - for (space_id = old_space_id; space_id < last_space_id; ++ space_id) { - HeapWord* const dense_prefix_end = _space_info[space_id].dense_prefix(); - const MutableSpace* const space = _space_info[space_id].space(); - - if (dense_prefix_end == space->bottom()) { - // There is no dense prefix for this space. - continue; - } - - // The dense prefix is before this region. - size_t region_index_end_dense_prefix = - sd.addr_to_region_idx(dense_prefix_end); - RegionData* const dense_prefix_cp = - sd.region(region_index_end_dense_prefix); - assert(dense_prefix_end == space->end() || - dense_prefix_cp->available() || - dense_prefix_cp->claimed(), - "The region after the dense prefix should always be ready to fill"); - - size_t region_index_start = sd.addr_to_region_idx(space->bottom()); - - // Is there dense prefix work? - size_t total_dense_prefix_regions = - region_index_end_dense_prefix - region_index_start; - // How many regions of the dense prefix should be given to - // each thread? - if (total_dense_prefix_regions > 0) { - uint tasks_for_dense_prefix = 1; - if (total_dense_prefix_regions <= - (parallel_gc_threads * PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING)) { - // Don't over partition. This assumes that - // PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING is a small integer value - // so there are not many regions to process. - tasks_for_dense_prefix = parallel_gc_threads; - } else { - // Over partition - tasks_for_dense_prefix = parallel_gc_threads * - PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING; - } - size_t regions_per_thread = total_dense_prefix_regions / - tasks_for_dense_prefix; - // Give each thread at least 1 region. - if (regions_per_thread == 0) { - regions_per_thread = 1; - } - - for (uint k = 0; k < tasks_for_dense_prefix; k++) { - if (region_index_start >= region_index_end_dense_prefix) { - break; - } - // region_index_end is not processed - size_t region_index_end = MIN2(region_index_start + regions_per_thread, - region_index_end_dense_prefix); - task_queue.push(UpdateDensePrefixTask(SpaceId(space_id), - region_index_start, - region_index_end)); - region_index_start = region_index_end; - } - } - // This gets any part of the dense prefix that did not - // fit evenly. - if (region_index_start < region_index_end_dense_prefix) { - task_queue.push(UpdateDensePrefixTask(SpaceId(space_id), - region_index_start, - region_index_end_dense_prefix)); - } - } -} - -#ifdef ASSERT -// Write a histogram of the number of times the block table was filled for a -// region. -void PSParallelCompact::write_block_fill_histogram() -{ - if (!log_develop_is_enabled(Trace, gc, compaction)) { - return; - } - - Log(gc, compaction) log; - ResourceMark rm; - LogStream ls(log.trace()); - outputStream* out = &ls; - - typedef ParallelCompactData::RegionData rd_t; - ParallelCompactData& sd = summary_data(); - - for (unsigned int id = old_space_id; id < last_space_id; ++id) { - MutableSpace* const spc = _space_info[id].space(); - if (spc->bottom() != spc->top()) { - const rd_t* const beg = sd.addr_to_region_ptr(spc->bottom()); - HeapWord* const top_aligned_up = sd.region_align_up(spc->top()); - const rd_t* const end = sd.addr_to_region_ptr(top_aligned_up); - - size_t histo[5] = { 0, 0, 0, 0, 0 }; - const size_t histo_len = sizeof(histo) / sizeof(size_t); - const size_t region_cnt = pointer_delta(end, beg, sizeof(rd_t)); - - for (const rd_t* cur = beg; cur < end; ++cur) { - ++histo[MIN2(cur->blocks_filled_count(), histo_len - 1)]; - } - out->print("Block fill histogram: %u %-4s" SIZE_FORMAT_W(5), id, space_names[id], region_cnt); - for (size_t i = 0; i < histo_len; ++i) { - out->print(" " SIZE_FORMAT_W(5) " %5.1f%%", - histo[i], 100.0 * histo[i] / region_cnt); - } - out->cr(); - } - } -} -#endif // #ifdef ASSERT - static void compaction_with_stealing_work(TaskTerminator* terminator, uint worker_id) { assert(ParallelScavengeHeap::heap()->is_stw_gc_active(), "called outside gc"); @@ -2012,72 +1992,146 @@ static void compaction_with_stealing_work(TaskTerminator* terminator, uint worke } } -class UpdateDensePrefixAndCompactionTask: public WorkerTask { - TaskQueue& _tq; +class FillDensePrefixAndCompactionTask: public WorkerTask { + uint _num_workers; TaskTerminator _terminator; public: - UpdateDensePrefixAndCompactionTask(TaskQueue& tq, uint active_workers) : - WorkerTask("UpdateDensePrefixAndCompactionTask"), - _tq(tq), + FillDensePrefixAndCompactionTask(uint active_workers) : + WorkerTask("FillDensePrefixAndCompactionTask"), + _num_workers(active_workers), _terminator(active_workers, ParCompactionManager::region_task_queues()) { } + virtual void work(uint worker_id) { - ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(worker_id); + { + auto start = Ticks::now(); + PSParallelCompact::fill_dead_objs_in_dense_prefix(worker_id, _num_workers); + log_trace(gc, phases)("Fill dense prefix by worker %u: %.3f ms", worker_id, (Ticks::now() - start).seconds() * 1000); + } + compaction_with_stealing_work(&_terminator, worker_id); + } +}; - for (PSParallelCompact::UpdateDensePrefixTask task; _tq.try_claim(task); /* empty */) { - PSParallelCompact::update_and_deadwood_in_dense_prefix(cm, - task._space_id, - task._region_index_start, - task._region_index_end); +void PSParallelCompact::fill_range_in_dense_prefix(HeapWord* start, HeapWord* end) { +#ifdef ASSERT + { + assert(start < end, "precondition"); + assert(mark_bitmap()->find_obj_beg(start, end) == end, "precondition"); + HeapWord* bottom = _space_info[old_space_id].space()->bottom(); + if (start != bottom) { + HeapWord* obj_start = mark_bitmap()->find_obj_beg_reverse(bottom, start); + HeapWord* after_obj = obj_start + cast_to_oop(obj_start)->size(); + assert(after_obj == start, "precondition"); } + } +#endif - // Once a thread has drained it's stack, it should try to steal regions from - // other threads. - compaction_with_stealing_work(&_terminator, worker_id); + CollectedHeap::fill_with_objects(start, pointer_delta(end, start)); + HeapWord* addr = start; + do { + size_t size = cast_to_oop(addr)->size(); + start_array(old_space_id)->update_for_block(addr, addr + size); + addr += size; + } while (addr < end); +} + +void PSParallelCompact::fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers) { + ParMarkBitMap* bitmap = mark_bitmap(); + + HeapWord* const bottom = _space_info[old_space_id].space()->bottom(); + HeapWord* const prefix_end = dense_prefix(old_space_id); - // At this point all regions have been compacted, so it's now safe - // to update the deferred objects that cross region boundaries. - cm->drain_deferred_objects(); + if (bottom == prefix_end) { + return; } -}; + + size_t bottom_region = _summary_data.addr_to_region_idx(bottom); + size_t prefix_end_region = _summary_data.addr_to_region_idx(prefix_end); + + size_t start_region; + size_t end_region; + split_regions_for_worker(bottom_region, prefix_end_region, + worker_id, num_workers, + &start_region, &end_region); + + if (start_region == end_region) { + return; + } + + HeapWord* const start_addr = _summary_data.region_to_addr(start_region); + HeapWord* const end_addr = _summary_data.region_to_addr(end_region); + + // Skip live partial obj (if any) from previous region. + HeapWord* cur_addr; + RegionData* start_region_ptr = _summary_data.region(start_region); + if (start_region_ptr->partial_obj_size() != 0) { + HeapWord* partial_obj_start = start_region_ptr->partial_obj_addr(); + assert(bitmap->is_marked(partial_obj_start), "inv"); + cur_addr = partial_obj_start + cast_to_oop(partial_obj_start)->size(); + } else { + cur_addr = start_addr; + } + + // end_addr is inclusive to handle regions starting with dead space. + while (cur_addr <= end_addr) { + // Use prefix_end to handle trailing obj in each worker region-chunk. + HeapWord* live_start = bitmap->find_obj_beg(cur_addr, prefix_end); + if (cur_addr != live_start) { + // Only worker 0 handles proceeding dead space. + if (cur_addr != start_addr || worker_id == 0) { + fill_range_in_dense_prefix(cur_addr, live_start); + } + } + if (live_start >= end_addr) { + break; + } + assert(bitmap->is_marked(live_start), "inv"); + cur_addr = live_start + cast_to_oop(live_start)->size(); + } +} void PSParallelCompact::compact() { GCTraceTime(Info, gc, phases) tm("Compaction Phase", &_gc_timer); - ParallelScavengeHeap* heap = ParallelScavengeHeap::heap(); - PSOldGen* old_gen = heap->old_gen(); uint active_gc_threads = ParallelScavengeHeap::heap()->workers().active_workers(); - // for [0..last_space_id) - // for [0..active_gc_threads * PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING) - // push - // push - // - // max push count is thus: last_space_id * (active_gc_threads * PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING + 1) - TaskQueue task_queue(last_space_id * (active_gc_threads * PAR_OLD_DENSE_PREFIX_OVER_PARTITIONING + 1)); initialize_shadow_regions(active_gc_threads); prepare_region_draining_tasks(active_gc_threads); - enqueue_dense_prefix_tasks(task_queue, active_gc_threads); { GCTraceTime(Trace, gc, phases) tm("Par Compact", &_gc_timer); - UpdateDensePrefixAndCompactionTask task(task_queue, active_gc_threads); + FillDensePrefixAndCompactionTask task(active_gc_threads); ParallelScavengeHeap::heap()->workers().run_task(&task); #ifdef ASSERT + verify_filler_in_dense_prefix(); + // Verify that all regions have been processed. for (unsigned int id = old_space_id; id < last_space_id; ++id) { verify_complete(SpaceId(id)); } #endif } - - DEBUG_ONLY(write_block_fill_histogram()); } #ifdef ASSERT +void PSParallelCompact::verify_filler_in_dense_prefix() { + HeapWord* bottom = _space_info[old_space_id].space()->bottom(); + HeapWord* dense_prefix_end = dense_prefix(old_space_id); + HeapWord* cur_addr = bottom; + while (cur_addr < dense_prefix_end) { + oop obj = cast_to_oop(cur_addr); + oopDesc::verify(obj); + if (!mark_bitmap()->is_marked(cur_addr)) { + Klass* k = cast_to_oop(cur_addr)->klass_without_asserts(); + assert(k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(), "inv"); + } + cur_addr += obj->size(); + } +} + void PSParallelCompact::verify_complete(SpaceId space_id) { // All Regions between space bottom() to new_top() should be marked as filled // and all Regions between new_top() and top() should be available (i.e., @@ -2117,72 +2171,6 @@ void PSParallelCompact::verify_complete(SpaceId space_id) { } #endif // #ifdef ASSERT -inline void UpdateOnlyClosure::do_addr(HeapWord* addr) { - compaction_manager()->update_contents(cast_to_oop(addr)); -} - -// Update interior oops in the ranges of regions [beg_region, end_region). -void -PSParallelCompact::update_and_deadwood_in_dense_prefix(ParCompactionManager* cm, - SpaceId space_id, - size_t beg_region, - size_t end_region) { - ParallelCompactData& sd = summary_data(); - ParMarkBitMap* const mbm = mark_bitmap(); - - HeapWord* beg_addr = sd.region_to_addr(beg_region); - HeapWord* const end_addr = sd.region_to_addr(end_region); - assert(beg_region <= end_region, "bad region range"); - assert(end_addr <= dense_prefix(space_id), "not in the dense prefix"); - -#ifdef ASSERT - // Claim the regions to avoid triggering an assert when they are marked as - // filled. - for (size_t claim_region = beg_region; claim_region < end_region; ++claim_region) { - assert(sd.region(claim_region)->claim_unsafe(), "claim() failed"); - } -#endif // #ifdef ASSERT - HeapWord* const space_bottom = space(space_id)->bottom(); - - // Check if it's the first region in this space. - if (beg_addr != space_bottom) { - // Find the first live object or block of dead space that *starts* in this - // range of regions. If a partial object crosses onto the region, skip it; - // it will be marked for 'deferred update' when the object head is - // processed. If dead space crosses onto the region, it is also skipped; it - // will be filled when the prior region is processed. If neither of those - // apply, the first word in the region is the start of a live object or dead - // space. - assert(beg_addr > space(space_id)->bottom(), "sanity"); - const RegionData* const cp = sd.region(beg_region); - if (cp->partial_obj_size() != 0) { - beg_addr = sd.partial_obj_end(beg_region); - } else { - idx_t beg_bit = mbm->addr_to_bit(beg_addr); - if (!mbm->is_obj_beg(beg_bit) && !mbm->is_obj_end(beg_bit - 1)) { - beg_addr = mbm->find_obj_beg(beg_addr, end_addr); - } - } - } - - if (beg_addr < end_addr) { - // A live object or block of dead space starts in this range of Regions. - HeapWord* const dense_prefix_end = dense_prefix(space_id); - - // Create closures and iterate. - UpdateOnlyClosure update_closure(mbm, cm, space_id); - FillClosure fill_closure(cm, space_id); - mbm->iterate(&update_closure, &fill_closure, beg_addr, end_addr, dense_prefix_end); - } - - // Mark the regions as filled. - RegionData* const beg_cp = sd.region(beg_region); - RegionData* const end_cp = sd.region(end_region); - for (RegionData* cp = beg_cp; cp < end_cp; ++cp) { - cp->set_completed(); - } -} - // Return the SpaceId for the space containing addr. If addr is not in the // heap, last_space_id is returned. In debug mode it expects the address to be // in the heap and asserts such. @@ -2199,24 +2187,6 @@ PSParallelCompact::SpaceId PSParallelCompact::space_id(HeapWord* addr) { return last_space_id; } -void PSParallelCompact::update_deferred_object(ParCompactionManager* cm, HeapWord *addr) { -#ifdef ASSERT - ParallelCompactData& sd = summary_data(); - size_t region_idx = sd.addr_to_region_idx(addr); - assert(sd.region(region_idx)->completed(), "first region must be completed before deferred updates"); - assert(sd.region(region_idx + 1)->completed(), "second region must be completed before deferred updates"); -#endif - - const SpaceInfo* const space_info = _space_info + space_id(addr); - ObjectStartArray* const start_array = space_info->start_array(); - if (start_array != nullptr) { - start_array->update_for_block(addr, addr + cast_to_oop(addr)->size()); - } - - cm->update_contents(cast_to_oop(addr)); - assert(oopDesc::is_oop(cast_to_oop(addr)), "Expected an oop at " PTR_FORMAT, p2i(cast_to_oop(addr))); -} - // Skip over count live words starting from beg, and return the address of the // next live word. Unless marked, the word corresponding to beg is assumed to // be dead. Callers must either ensure beg does not correspond to the middle of @@ -2228,26 +2198,18 @@ PSParallelCompact::skip_live_words(HeapWord* beg, HeapWord* end, size_t count) assert(count > 0, "sanity"); ParMarkBitMap* m = mark_bitmap(); - idx_t bits_to_skip = m->words_to_bits(count); - idx_t cur_beg = m->addr_to_bit(beg); - const idx_t search_end = m->align_range_end(m->addr_to_bit(end)); - - do { - cur_beg = m->find_obj_beg(cur_beg, search_end); - idx_t cur_end = m->find_obj_end(cur_beg, search_end); - const size_t obj_bits = cur_end - cur_beg + 1; - if (obj_bits > bits_to_skip) { - return m->bit_to_addr(cur_beg + bits_to_skip); + HeapWord* cur_addr = beg; + while (true) { + cur_addr = m->find_obj_beg(cur_addr, end); + assert(cur_addr < end, "inv"); + size_t obj_size = cast_to_oop(cur_addr)->size(); + // Strictly greater-than + if (obj_size > count) { + return cur_addr + count; } - bits_to_skip -= obj_bits; - cur_beg = cur_end + 1; - } while (bits_to_skip > 0); - - // Skipping the desired number of words landed just past the end of an object. - // Find the start of the next object. - cur_beg = m->find_obj_beg(cur_beg, search_end); - assert(cur_beg < m->addr_to_bit(end), "not enough live words to skip"); - return m->bit_to_addr(cur_beg); + count -= obj_size; + cur_addr += obj_size; + } } HeapWord* PSParallelCompact::first_src_addr(HeapWord* const dest_addr, @@ -2431,9 +2393,31 @@ size_t PSParallelCompact::next_src_region(MoveAndUpdateClosure& closure, return 0; } +HeapWord* PSParallelCompact::partial_obj_end(HeapWord* region_start_addr) { + ParallelCompactData& sd = summary_data(); + assert(sd.is_region_aligned(region_start_addr), "precondition"); + + // Use per-region partial_obj_size to locate the end of the obj, that extends to region_start_addr. + SplitInfo& split_info = _space_info[space_id(region_start_addr)].split_info(); + size_t start_region_idx = sd.addr_to_region_idx(region_start_addr); + size_t end_region_idx = sd.region_count(); + size_t accumulated_size = 0; + for (size_t region_idx = start_region_idx; region_idx < end_region_idx; ++region_idx) { + if (split_info.is_split(region_idx)) { + accumulated_size += split_info.partial_obj_size(); + break; + } + size_t cur_partial_obj_size = sd.region(region_idx)->partial_obj_size(); + accumulated_size += cur_partial_obj_size; + if (cur_partial_obj_size != ParallelCompactData::RegionSize) { + break; + } + } + return region_start_addr + accumulated_size; +} + void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosure& closure, size_t region_idx) { - typedef ParMarkBitMap::IterationStatus IterationStatus; ParMarkBitMap* const bitmap = mark_bitmap(); ParallelCompactData& sd = summary_data(); RegionData* const region_ptr = sd.region(region_idx); @@ -2457,7 +2441,30 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosu // of the object or as much as will fit. The fact that pointer updates were // deferred will be noted when the object header is processed. HeapWord* const old_src_addr = closure.source(); - closure.copy_partial_obj(); + { + HeapWord* region_start = sd.region_align_down(closure.source()); + HeapWord* obj_start = bitmap->find_obj_beg_reverse(region_start, closure.source()); + HeapWord* obj_end; + if (bitmap->is_marked(obj_start)) { + HeapWord* next_region_start = region_start + ParallelCompactData::RegionSize; + HeapWord* partial_obj_start = (next_region_start >= src_space_top) + ? nullptr + : sd.addr_to_region_ptr(next_region_start)->partial_obj_addr(); + if (partial_obj_start == obj_start) { + // This obj extends to next region. + obj_end = partial_obj_end(next_region_start); + } else { + // Completely contained in this region; safe to use size(). + obj_end = obj_start + cast_to_oop(obj_start)->size(); + } + } else { + // This obj extends to current region. + obj_end = partial_obj_end(region_start); + } + size_t partial_obj_size = pointer_delta(obj_end, closure.source()); + closure.copy_partial_obj(partial_obj_size); + } + if (closure.is_full()) { decrement_destination_counts(cm, src_space_id, src_region_idx, closure.source()); @@ -2478,24 +2485,30 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosu } do { - HeapWord* const cur_addr = closure.source(); + HeapWord* cur_addr = closure.source(); HeapWord* const end_addr = MIN2(sd.region_align_up(cur_addr + 1), src_space_top); - IterationStatus status = bitmap->iterate(&closure, cur_addr, end_addr); - - if (status == ParMarkBitMap::would_overflow) { - // The last object did not fit. Note that interior oop updates were - // deferred, then copy enough of the object to fill the region. - cm->push_deferred_object(closure.destination()); - status = closure.copy_until_full(); // copies from closure.source() - - decrement_destination_counts(cm, src_space_id, src_region_idx, - closure.source()); - closure.complete_region(cm, dest_addr, region_ptr); - return; - } + HeapWord* partial_obj_start = (end_addr == src_space_top) + ? nullptr + : sd.addr_to_region_ptr(end_addr)->partial_obj_addr(); + // apply closure on objs inside [cur_addr, end_addr) + do { + cur_addr = bitmap->find_obj_beg(cur_addr, end_addr); + if (cur_addr == end_addr) { + break; + } + size_t obj_size; + if (partial_obj_start == cur_addr) { + obj_size = pointer_delta(partial_obj_end(end_addr), cur_addr); + } else { + // This obj doesn't extend into next region; size() is safe to use. + obj_size = cast_to_oop(cur_addr)->size(); + } + closure.do_addr(cur_addr, obj_size); + cur_addr += obj_size; + } while (cur_addr < end_addr && !closure.is_full()); - if (status == ParMarkBitMap::full) { + if (closure.is_full()) { decrement_destination_counts(cm, src_space_id, src_region_idx, closure.source()); closure.complete_region(cm, dest_addr, region_ptr); @@ -2595,77 +2608,9 @@ void PSParallelCompact::initialize_shadow_regions(uint parallel_gc_threads) } } -void PSParallelCompact::fill_blocks(size_t region_idx) +void MoveAndUpdateClosure::copy_partial_obj(size_t partial_obj_size) { - // Fill in the block table elements for the specified region. Each block - // table element holds the number of live words in the region that are to the - // left of the first object that starts in the block. Thus only blocks in - // which an object starts need to be filled. - // - // The algorithm scans the section of the bitmap that corresponds to the - // region, keeping a running total of the live words. When an object start is - // found, if it's the first to start in the block that contains it, the - // current total is written to the block table element. - const size_t Log2BlockSize = ParallelCompactData::Log2BlockSize; - const size_t Log2RegionSize = ParallelCompactData::Log2RegionSize; - const size_t RegionSize = ParallelCompactData::RegionSize; - - ParallelCompactData& sd = summary_data(); - const size_t partial_obj_size = sd.region(region_idx)->partial_obj_size(); - if (partial_obj_size >= RegionSize) { - return; // No objects start in this region. - } - - // Ensure the first loop iteration decides that the block has changed. - size_t cur_block = sd.block_count(); - - const ParMarkBitMap* const bitmap = mark_bitmap(); - - const size_t Log2BitsPerBlock = Log2BlockSize - LogMinObjAlignment; - assert((size_t)1 << Log2BitsPerBlock == - bitmap->words_to_bits(ParallelCompactData::BlockSize), "sanity"); - - size_t beg_bit = bitmap->words_to_bits(region_idx << Log2RegionSize); - const size_t range_end = beg_bit + bitmap->words_to_bits(RegionSize); - size_t live_bits = bitmap->words_to_bits(partial_obj_size); - beg_bit = bitmap->find_obj_beg(beg_bit + live_bits, range_end); - while (beg_bit < range_end) { - const size_t new_block = beg_bit >> Log2BitsPerBlock; - if (new_block != cur_block) { - cur_block = new_block; - sd.block(cur_block)->set_offset(bitmap->bits_to_words(live_bits)); - } - - const size_t end_bit = bitmap->find_obj_end(beg_bit, range_end); - if (end_bit < range_end - 1) { - live_bits += end_bit - beg_bit + 1; - beg_bit = bitmap->find_obj_beg(end_bit + 1, range_end); - } else { - return; - } - } -} - -ParMarkBitMap::IterationStatus MoveAndUpdateClosure::copy_until_full() -{ - if (source() != copy_destination()) { - DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());) - Copy::aligned_conjoint_words(source(), copy_destination(), words_remaining()); - } - update_state(words_remaining()); - assert(is_full(), "sanity"); - return ParMarkBitMap::full; -} - -void MoveAndUpdateClosure::copy_partial_obj() -{ - size_t words = words_remaining(); - - HeapWord* const range_end = MIN2(source() + words, bitmap()->region_end()); - HeapWord* const end_addr = bitmap()->find_obj_end(source(), range_end); - if (end_addr < range_end) { - words = bitmap()->obj_size(source(), end_addr); - } + size_t words = MIN2(partial_obj_size, words_remaining()); // This test is necessary; if omitted, the pointer updates to a partial object // that crosses the dense prefix boundary could be overwritten. @@ -2685,32 +2630,27 @@ void MoveAndUpdateClosure::complete_region(ParCompactionManager *cm, HeapWord *d ParMarkBitMapClosure::IterationStatus MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) { assert(destination() != nullptr, "sanity"); - assert(bitmap()->obj_size(addr) == words, "bad size"); - _source = addr; - assert(PSParallelCompact::summary_data().calc_new_pointer(source(), compaction_manager()) == - destination(), "wrong destination"); - - if (words > words_remaining()) { - return ParMarkBitMap::would_overflow; - } // The start_array must be updated even if the object is not moving. if (_start_array != nullptr) { _start_array->update_for_block(destination(), destination() + words); } + // Avoid overflow + words = MIN2(words, words_remaining()); + assert(words > 0, "inv"); + if (copy_destination() != source()) { DEBUG_ONLY(PSParallelCompact::check_new_location(source(), destination());) + assert(source() != destination(), "inv"); + assert(cast_to_oop(source())->is_forwarded(), "inv"); + assert(cast_to_oop(source())->forwardee() == cast_to_oop(destination()), "inv"); Copy::aligned_conjoint_words(source(), copy_destination(), words); + cast_to_oop(copy_destination())->init_mark(); } - oop moved_oop = cast_to_oop(copy_destination()); - compaction_manager()->update_contents(moved_oop); - assert(oopDesc::is_oop_or_null(moved_oop), "Expected an oop or null at " PTR_FORMAT, p2i(moved_oop)); - update_state(words); - assert(copy_destination() == cast_from_oop(moved_oop) + moved_oop->size(), "sanity"); return is_full() ? ParMarkBitMap::full : ParMarkBitMap::incomplete; } @@ -2733,37 +2673,3 @@ void MoveAndUpdateShadowClosure::complete_region(ParCompactionManager *cm, HeapW } } -UpdateOnlyClosure::UpdateOnlyClosure(ParMarkBitMap* mbm, - ParCompactionManager* cm, - PSParallelCompact::SpaceId space_id) : - ParMarkBitMapClosure(mbm, cm), - _start_array(PSParallelCompact::start_array(space_id)) -{ -} - -// Updates the references in the object to their new values. -ParMarkBitMapClosure::IterationStatus -UpdateOnlyClosure::do_addr(HeapWord* addr, size_t words) { - do_addr(addr); - return ParMarkBitMap::incomplete; -} - -FillClosure::FillClosure(ParCompactionManager* cm, PSParallelCompact::SpaceId space_id) : - ParMarkBitMapClosure(PSParallelCompact::mark_bitmap(), cm), - _start_array(PSParallelCompact::start_array(space_id)) -{ - assert(space_id == PSParallelCompact::old_space_id, - "cannot use FillClosure in the young gen"); -} - -ParMarkBitMapClosure::IterationStatus -FillClosure::do_addr(HeapWord* addr, size_t size) { - CollectedHeap::fill_with_objects(addr, size); - HeapWord* const end = addr + size; - do { - size_t size = cast_to_oop(addr)->size(); - _start_array->update_for_block(addr, addr + size); - addr += size; - } while (addr < end); - return ParMarkBitMap::incomplete; -} diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index a36acc72a9b..67346d7eee5 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -215,17 +215,6 @@ class ParallelCompactData // Mask for the bits in a pointer to get the address of the start of a region. static const size_t RegionAddrMask; - static const size_t Log2BlockSize; - static const size_t BlockSize; - static const size_t BlockSizeBytes; - - static const size_t BlockSizeOffsetMask; - static const size_t BlockAddrOffsetMask; - static const size_t BlockAddrMask; - - static const size_t BlocksPerRegion; - static const size_t Log2BlocksPerRegion; - class RegionData { public: @@ -274,12 +263,6 @@ class ParallelCompactData inline uint destination_count() const; inline uint destination_count_raw() const; - // Whether the block table for this region has been filled. - inline bool blocks_filled() const; - - // Number of times the block table was filled. - DEBUG_ONLY(inline size_t blocks_filled_count() const;) - // Whether this region is available to be claimed, has been claimed, or has // been completed. // @@ -298,7 +281,6 @@ class ParallelCompactData void set_partial_obj_size(size_t words) { _partial_obj_size = (region_sz_t) words; } - inline void set_blocks_filled(); inline void set_destination_count(uint count); inline void set_live_obj_size(size_t words); @@ -356,13 +338,8 @@ class ParallelCompactData HeapWord* _partial_obj_addr; region_sz_t _partial_obj_size; region_sz_t volatile _dc_and_los; - bool volatile _blocks_filled; int volatile _shadow_state; -#ifdef ASSERT - size_t _blocks_filled_count; // Number of block table fills. -#endif // #ifdef ASSERT - #ifdef ASSERT public: uint _pushed; // 0 until region is pushed onto a stack @@ -370,21 +347,6 @@ class ParallelCompactData #endif }; - // "Blocks" allow shorter sections of the bitmap to be searched. Each Block - // holds an offset, which is the amount of live data in the Region to the left - // of the first live object that starts in the Block. - class BlockData - { - public: - typedef unsigned short int blk_ofs_t; - - blk_ofs_t offset() const { return _offset; } - void set_offset(size_t val) { _offset = (blk_ofs_t)val; } - - private: - blk_ofs_t _offset; - }; - public: ParallelCompactData(); bool initialize(MemRegion reserved_heap); @@ -396,9 +358,6 @@ class ParallelCompactData inline RegionData* region(size_t region_idx) const; inline size_t region(const RegionData* const region_ptr) const; - size_t block_count() const { return _block_count; } - inline BlockData* block(size_t block_idx) const; - // Fill in the regions covering [beg, end) so that no data moves; i.e., the // destination of region n is simply the start of region n. Both arguments // beg and end must be region-aligned. @@ -436,28 +395,12 @@ class ParallelCompactData inline HeapWord* region_align_up(HeapWord* addr) const; inline bool is_region_aligned(HeapWord* addr) const; - size_t addr_to_block_idx(const HeapWord* addr) const; - inline BlockData* addr_to_block_ptr(const HeapWord* addr) const; - - inline HeapWord* block_align_down(HeapWord* addr) const; - - // Return the address one past the end of the partial object. - HeapWord* partial_obj_end(size_t region_idx) const; - - // Return the location of the object after compaction. - HeapWord* calc_new_pointer(HeapWord* addr, ParCompactionManager* cm) const; - - HeapWord* calc_new_pointer(oop p, ParCompactionManager* cm) const { - return calc_new_pointer(cast_from_oop(p), cm); - } - #ifdef ASSERT void verify_clear(const PSVirtualSpace* vspace); void verify_clear(); #endif // #ifdef ASSERT private: - bool initialize_block_data(); bool initialize_region_data(size_t heap_size); PSVirtualSpace* create_vspace(size_t count, size_t element_size); @@ -470,10 +413,6 @@ class ParallelCompactData size_t _reserved_byte_size; RegionData* _region_data; size_t _region_count; - - PSVirtualSpace* _block_vspace; - BlockData* _block_data; - size_t _block_count; }; inline uint @@ -488,31 +427,6 @@ ParallelCompactData::RegionData::destination_count() const return destination_count_raw() >> dc_shift; } -inline bool -ParallelCompactData::RegionData::blocks_filled() const -{ - bool result = _blocks_filled; - OrderAccess::acquire(); - return result; -} - -#ifdef ASSERT -inline size_t -ParallelCompactData::RegionData::blocks_filled_count() const -{ - return _blocks_filled_count; -} -#endif // #ifdef ASSERT - -inline void -ParallelCompactData::RegionData::set_blocks_filled() -{ - OrderAccess::release(); - _blocks_filled = true; - // Debug builds count the number of times the table was filled. - DEBUG_ONLY(Atomic::inc(&_blocks_filled_count)); -} - inline void ParallelCompactData::RegionData::set_destination_count(uint count) { @@ -602,12 +516,6 @@ ParallelCompactData::region(const RegionData* const region_ptr) const return pointer_delta(region_ptr, _region_data, sizeof(RegionData)); } -inline ParallelCompactData::BlockData* -ParallelCompactData::block(size_t n) const { - assert(n < block_count(), "bad arg"); - return _block_data + n; -} - inline size_t ParallelCompactData::region_offset(const HeapWord* addr) const { @@ -667,28 +575,6 @@ ParallelCompactData::is_region_aligned(HeapWord* addr) const return (size_t(addr) & RegionAddrOffsetMask) == 0; } -inline size_t -ParallelCompactData::addr_to_block_idx(const HeapWord* addr) const -{ - assert(addr >= _heap_start, "bad addr"); - assert(addr <= _heap_end, "bad addr"); - return pointer_delta(addr, _heap_start) >> Log2BlockSize; -} - -inline ParallelCompactData::BlockData* -ParallelCompactData::addr_to_block_ptr(const HeapWord* addr) const -{ - return block(addr_to_block_idx(addr)); -} - -inline HeapWord* -ParallelCompactData::block_align_down(HeapWord* addr) const -{ - assert(addr >= _heap_start, "bad addr"); - assert(addr < _heap_end + RegionSize, "bad addr"); - return (HeapWord*)(size_t(addr) & BlockAddrMask); -} - // Abstract closure for use with ParMarkBitMap::iterate(), which will invoke the // do_addr() method. // @@ -774,25 +660,24 @@ inline void ParMarkBitMapClosure::decrement_words_remaining(size_t words) { // does parts of the collection using parallel threads. The collection includes // the tenured generation and the young generation. // -// There are four phases of the collection. +// A collection consists of the following phases. // // - marking phase -// - summary phase +// - summary phase (single-threaded) +// - forward (to new address) phase +// - adjust pointers phase // - compacting phase // - clean up phase // // Roughly speaking these phases correspond, respectively, to +// // - mark all the live objects +// - calculating destination-region for each region for better parallellism in following phases // - calculate the destination of each object at the end of the collection +// - adjust pointers to reflect new destination of objects // - move the objects to their destination // - update some references and reinitialize some variables // -// These three phases are invoked in PSParallelCompact::invoke_no_policy(). The -// marking phase is implemented in PSParallelCompact::marking_phase() and does a -// complete marking of the heap. The summary phase is implemented in -// PSParallelCompact::summary_phase(). The move and update phase is implemented -// in PSParallelCompact::compact(). -// // A space that is being collected is divided into regions and with each region // is associated an object of type ParallelCompactData. Each region is of a // fixed size and typically will contain more than 1 object and may have parts @@ -828,17 +713,12 @@ inline void ParMarkBitMapClosure::decrement_words_remaining(size_t words) { // dense prefix do need to have their object references updated. See method // summarize_dense_prefix(). // -// The summary phase is done using 1 GC thread. +// The forward (to new address) phase calculates the new address of each +// objects and records old-addr-to-new-addr asssociation. // -// The compaction phase moves objects to their new location and updates all -// references in the object. +// The adjust pointers phase remap all pointers to reflect the new address of each object. // -// A current exception is that objects that cross a region boundary are moved -// but do not have their references updated. References are not updated because -// it cannot easily be determined if the klass pointer KKK for the object AAA -// has been updated. KKK likely resides in a region to the left of the region -// containing AAA. These AAA's have their references updated at the end in a -// clean up phase. See the method PSParallelCompact::update_deferred_object(). +// The compaction phase moves objects to their new location. // // Compaction is done on a region basis. A region that is ready to be filled is // put on a ready list and GC threads take region off the list and fill them. A @@ -869,39 +749,18 @@ inline void ParMarkBitMapClosure::decrement_words_remaining(size_t words) { // Environments (VEE 2019). ACM, New York, NY, USA, 108-121. DOI: // https://doi.org/10.1145/3313808.3313820 -class TaskQueue; - class PSParallelCompact : AllStatic { public: // Convenient access to type names. typedef ParMarkBitMap::idx_t idx_t; typedef ParallelCompactData::RegionData RegionData; - typedef ParallelCompactData::BlockData BlockData; typedef enum { old_space_id, eden_space_id, from_space_id, to_space_id, last_space_id } SpaceId; - struct UpdateDensePrefixTask : public CHeapObj { - SpaceId _space_id; - size_t _region_index_start; - size_t _region_index_end; - - UpdateDensePrefixTask() : - _space_id(SpaceId(0)), - _region_index_start(0), - _region_index_end(0) {} - - UpdateDensePrefixTask(SpaceId space_id, - size_t region_index_start, - size_t region_index_end) : - _space_id(space_id), - _region_index_start(region_index_start), - _region_index_end(region_index_end) {} - }; - - public: +public: // Inline closure decls // class IsAliveClosure: public BoolObjectClosure { @@ -909,7 +768,6 @@ class PSParallelCompact : AllStatic { virtual bool do_object_b(oop p); }; - friend class RefProcTaskProxy; friend class PSParallelCompactTest; private: @@ -958,10 +816,11 @@ class PSParallelCompact : AllStatic { static void summary_phase(bool maximum_compaction); - // Adjust addresses in roots. Does not adjust addresses in heap. - static void adjust_roots(); + static void adjust_pointers(); + static void forward_to_new_addr(); - DEBUG_ONLY(static void write_block_fill_histogram();) + static void verify_forward() NOT_DEBUG_RETURN; + static void verify_filler_in_dense_prefix() NOT_DEBUG_RETURN; // Move objects to new locations. static void compact(); @@ -969,10 +828,6 @@ class PSParallelCompact : AllStatic { // Add available regions to the stack and draining tasks to the task queue. static void prepare_region_draining_tasks(uint parallel_gc_threads); - // Add dense prefix update tasks to the task queue. - static void enqueue_dense_prefix_tasks(TaskQueue& task_queue, - uint parallel_gc_threads); - #ifndef PRODUCT // Print generic summary data static void print_generic_summary_data(ParallelCompactData& summary_data, @@ -980,10 +835,23 @@ class PSParallelCompact : AllStatic { HeapWord* const end_addr); #endif // #ifndef PRODUCT + static void fill_range_in_dense_prefix(HeapWord* start, HeapWord* end); + public: + static void fill_dead_objs_in_dense_prefix(uint worker_id, uint num_workers); + static bool invoke(bool maximum_heap_compaction); static bool invoke_no_policy(bool maximum_heap_compaction); + template + static void adjust_in_space_helper(SpaceId id, volatile uint* claim_counter, Func&& on_stripe); + + static void adjust_in_old_space(volatile uint* claim_counter); + + static void adjust_in_young_space(SpaceId id, volatile uint* claim_counter); + + static void adjust_pointers_in_spaces(uint worker_id, volatile uint* claim_counter); + static void post_initialize(); // Perform initialization for PSParallelCompact that requires // allocations. This should be called during the VM initialization @@ -1003,7 +871,7 @@ class PSParallelCompact : AllStatic { static inline bool mark_obj(oop obj); static inline bool is_marked(oop obj); - template static inline void adjust_pointer(T* p, ParCompactionManager* cm); + template static inline void adjust_pointer(T* p); // Compaction support. // Return true if p is in the range [beg_addr, end_addr). @@ -1016,19 +884,6 @@ class PSParallelCompact : AllStatic { static inline HeapWord* dense_prefix(SpaceId space_id); static inline ObjectStartArray* start_array(SpaceId space_id); - // Update a region in the dense prefix. For each live object - // in the region, update it's interior references. For each - // dead object, fill it with deadwood. Dead space at the end - // of a region range will be filled to the start of the next - // live object regardless of the region_index_end. None of the - // objects in the dense prefix move and dead space is dead - // (holds only dead objects that don't need any processing), so - // dead space can be filled in any order. - static void update_and_deadwood_in_dense_prefix(ParCompactionManager* cm, - SpaceId space_id, - size_t region_index_start, - size_t region_index_end); - // Return the address of the count + 1st live word in the range [beg, end). static HeapWord* skip_live_words(HeapWord* beg, HeapWord* end, size_t count); @@ -1056,6 +911,8 @@ class PSParallelCompact : AllStatic { size_t beg_region, HeapWord* end_addr); + static HeapWord* partial_obj_end(HeapWord* region_start_addr); + static void fill_region(ParCompactionManager* cm, MoveAndUpdateClosure& closure, size_t region); static void fill_and_update_region(ParCompactionManager* cm, size_t region); @@ -1067,12 +924,6 @@ class PSParallelCompact : AllStatic { // _next_shadow_region filed for each compact manager static void initialize_shadow_regions(uint parallel_gc_threads); - // Fill in the block table for the specified region. - static void fill_blocks(size_t region_idx); - - // Update a single deferred object. - static void update_deferred_object(ParCompactionManager* cm, HeapWord* addr); - static ParMarkBitMap* mark_bitmap() { return &_mark_bitmap; } static ParallelCompactData& summary_data() { return _summary_data; } @@ -1120,14 +971,10 @@ class MoveAndUpdateClosure: public ParMarkBitMapClosure { // return would_overflow. IterationStatus do_addr(HeapWord* addr, size_t size); - // Copy enough words to fill this closure, starting at source(). Interior - // oops and the start array are not updated. Return full. - IterationStatus copy_until_full(); - // Copy enough words to fill this closure or to the end of an object, - // whichever is smaller, starting at source(). Interior oops and the start - // array are not updated. - void copy_partial_obj(); + // whichever is smaller, starting at source(). The start array is not + // updated. + void copy_partial_obj(size_t partial_obj_size); virtual void complete_region(ParCompactionManager* cm, HeapWord* dest_addr, PSParallelCompact::RegionData* region_ptr); @@ -1198,31 +1045,6 @@ MoveAndUpdateShadowClosure::MoveAndUpdateShadowClosure(ParMarkBitMap *bitmap, _offset = calculate_shadow_offset(region, shadow); } -class UpdateOnlyClosure: public ParMarkBitMapClosure { - private: - ObjectStartArray* const _start_array; - - public: - UpdateOnlyClosure(ParMarkBitMap* mbm, - ParCompactionManager* cm, - PSParallelCompact::SpaceId space_id); - - // Update the object. - virtual IterationStatus do_addr(HeapWord* addr, size_t words); - - inline void do_addr(HeapWord* addr); -}; - -class FillClosure: public ParMarkBitMapClosure { - public: - FillClosure(ParCompactionManager* cm, PSParallelCompact::SpaceId space_id); - - virtual IterationStatus do_addr(HeapWord* addr, size_t size); - - private: - ObjectStartArray* const _start_array; -}; - void steal_marking_work(TaskTerminator& terminator, uint worker_id); #endif // SHARE_GC_PARALLEL_PSPARALLELCOMPACT_HPP diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp index a4a5060ffd5..75a092e2dd1 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp @@ -78,8 +78,7 @@ inline void PSParallelCompact::check_new_location(HeapWord* old_addr, HeapWord* #endif // ASSERT inline bool PSParallelCompact::mark_obj(oop obj) { - const size_t obj_size = obj->size(); - if (mark_bitmap()->mark_obj(obj, obj_size)) { + if (mark_bitmap()->mark_obj(obj)) { ContinuationGCSupport::transform_stack_chunk(obj); return true; } else { @@ -88,34 +87,22 @@ inline bool PSParallelCompact::mark_obj(oop obj) { } template -inline void PSParallelCompact::adjust_pointer(T* p, ParCompactionManager* cm) { +inline void PSParallelCompact::adjust_pointer(T* p) { T heap_oop = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(heap_oop)) { oop obj = CompressedOops::decode_not_null(heap_oop); assert(ParallelScavengeHeap::heap()->is_in(obj), "should be in heap"); - oop new_obj = cast_to_oop(summary_data().calc_new_pointer(obj, cm)); - assert(new_obj != nullptr, "non-null address for live objects"); - // Is it actually relocated at all? - if (new_obj != obj) { - assert(ParallelScavengeHeap::heap()->is_in_reserved(new_obj), - "should be in object space"); - RawAccess::oop_store(p, new_obj); + if (!obj->is_forwarded()) { + return; } + oop new_obj = obj->forwardee(); + assert(new_obj != nullptr, "non-null address for live objects"); + assert(new_obj != obj, "inv"); + assert(ParallelScavengeHeap::heap()->is_in_reserved(new_obj), + "should be in object space"); + RawAccess::oop_store(p, new_obj); } } -class PCAdjustPointerClosure: public BasicOopIterateClosure { -public: - PCAdjustPointerClosure(ParCompactionManager* cm) : _cm(cm) { - } - template void do_oop_work(T* p) { PSParallelCompact::adjust_pointer(p, _cm); } - virtual void do_oop(oop* p) { do_oop_work(p); } - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - - virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; } -private: - ParCompactionManager* _cm; -}; - #endif // SHARE_GC_PARALLEL_PSPARALLELCOMPACT_INLINE_HPP From 1ea76d338b99900089277b7a2da82c24382a6ce1 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 23 May 2024 07:28:28 +0000 Subject: [PATCH 06/99] 8332675: test/hotspot/jtreg/gc/testlibrary/Helpers.java compileClass javadoc does not match after 8321812 Reviewed-by: mdoerr, ayang --- test/hotspot/jtreg/gc/testlibrary/Helpers.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/gc/testlibrary/Helpers.java b/test/hotspot/jtreg/gc/testlibrary/Helpers.java index 03d67e44455..a0c28ff25f7 100644 --- a/test/hotspot/jtreg/gc/testlibrary/Helpers.java +++ b/test/hotspot/jtreg/gc/testlibrary/Helpers.java @@ -88,7 +88,7 @@ public static int detectByteArrayAllocationOverhead() { * @param className class name * @param root root directory - where .java and .class files will be put * @param source class source - * @throws IOException if cannot write file to specified directory + * @throws Exception if cannot write file to specified directory */ public static void compileClass(String className, Path root, String source) throws Exception { Path sourceFile = root.resolve(className + ".java"); From 612ae9289a130b8701f74253fe5499358a2e2b5b Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 23 May 2024 08:11:22 +0000 Subject: [PATCH 07/99] 8332735: [JVMCI] Add extra JVMCI events for exception translation Reviewed-by: never --- src/hotspot/share/jvmci/jvmciEnv.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 3d942d83225..624b25b9e2c 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -514,6 +514,7 @@ class HotSpotToSharedLibraryExceptionTranslation : public ExceptionTranslation { } void decode(JavaThread* THREAD, DecodeFormat format, jlong buffer) { + JVMCI_event_1("decoding exception from JVM heap (format: %d, buffer[%d]) ", format, buffer == 0L ? -1 : *((u4*) buffer)); JNIAccessMark jni(_to_env, THREAD); jni()->CallStaticVoidMethod(JNIJVMCI::VMSupport::clazz(), JNIJVMCI::VMSupport::decodeAndThrowThrowable_method(), @@ -545,6 +546,7 @@ class SharedLibraryToHotSpotExceptionTranslation : public ExceptionTranslation { } void decode(JavaThread* THREAD, DecodeFormat format, jlong buffer) { + JVMCI_event_1("decoding exception to JVM heap (format: %d, buffer[%d]) ", format, buffer == 0L ? -1 : *((u4*) buffer)); Klass* vmSupport = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_vm_VMSupport(), true, CHECK); JavaCallArguments jargs; jargs.push_int(format); From 4e6d851f3f061b4a9c2b5d2e3fba6a0277ac1f34 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 23 May 2024 09:43:29 +0000 Subject: [PATCH 08/99] 8325324: Implement JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview) Reviewed-by: asotona, vromero, mcimadamore --- .../jdk/internal/javac/PreviewFeature.java | 4 +- .../com/sun/tools/javac/code/Symtab.java | 2 + .../com/sun/tools/javac/comp/TypeEnter.java | 26 +- .../javac/ImplicitClass/ImplicitImports.java | 285 ++++++++++++++++++ .../processing/model/TestSymtabItems.java | 4 + 5 files changed, 316 insertions(+), 5 deletions(-) create mode 100644 test/langtools/tools/javac/ImplicitClass/ImplicitImports.java diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index 43dcf25c263..f95ffd0e402 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -69,9 +69,7 @@ public enum Feature { FOREIGN, @JEP(number=459, title="String Templates", status="Second Preview") STRING_TEMPLATES, - @JEP(number=445, title="Unnamed Classes and Instance Main Methods", status="Deprecated") - UNNAMED_CLASSES, - @JEP(number=463, title="Implicitly Declared Classes and Instance Main Methods", status="Preview") + @JEP(number=477, title="Implicitly Declared Classes and Instance Main Methods", status="Third Preview") IMPLICIT_CLASSES, @JEP(number=464, title="Scoped Values", status="Second Preview") SCOPED_VALUES, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java index 89de932ab72..17173e480f1 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java @@ -230,6 +230,7 @@ public static Symtab instance(Context context) { public final Type valueBasedInternalType; public final Type classDescType; public final Type enumDescType; + public final Type ioType; // For serialization lint checking public final Type objectStreamFieldType; @@ -616,6 +617,7 @@ public R accept(ElementVisitor v, P p) { valueBasedInternalType = enterSyntheticAnnotation("jdk.internal.ValueBased+Annotation"); classDescType = enterClass("java.lang.constant.ClassDesc"); enumDescType = enterClass("java.lang.Enum$EnumDesc"); + ioType = enterClass("java.io.IO"); // For serialization lint checking objectStreamFieldType = enterClass("java.io.ObjectStreamField"); objectInputStreamType = enterClass("java.io.ObjectInputStream"); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java index f36f425283a..72943e09f0f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java @@ -323,7 +323,7 @@ protected void runPhase(Env env) { sym.owner.complete(); } - private void importJavaLang(JCCompilationUnit tree, Env env, ImportFilter typeImportFilter) { + private void implicitImports(JCCompilationUnit tree, Env env) { // Import-on-demand java.lang. PackageSymbol javaLang = syms.enterPackage(syms.java_base, names.java_lang); if (javaLang.members().isEmpty() && !javaLang.exists()) { @@ -332,6 +332,28 @@ private void importJavaLang(JCCompilationUnit tree, Env env, Import } importAll(make.at(tree.pos()).Import(make.Select(make.QualIdent(javaLang.owner), javaLang), false), javaLang, env); + + List defs = tree.getTypeDecls(); + boolean isImplicitClass = !defs.isEmpty() && + defs.head instanceof JCClassDecl cls && + (cls.mods.flags & IMPLICIT_CLASS) != 0; + if (isImplicitClass) { + doModuleImport(make.ModuleImport(make.QualIdent(syms.java_base))); + if (peekTypeExists(syms.ioType.tsym)) { + doImport(make.Import(make.Select(make.QualIdent(syms.ioType.tsym), + names.asterisk), true)); + } + } + } + + private boolean peekTypeExists(TypeSymbol type) { + try { + type.complete(); + return !type.type.isErroneous(); + } catch (CompletionFailure cf) { + //does not exist + return false; + } } private void resolveImports(JCCompilationUnit tree, Env env) { @@ -356,7 +378,7 @@ private void resolveImports(JCCompilationUnit tree, Env env) { (origin, sym) -> sym.kind == TYP && chk.importAccessible(sym, packge); - importJavaLang(tree, env, typeImportFilter); + implicitImports(tree, env); JCModuleDecl decl = tree.getModuleDecl(); diff --git a/test/langtools/tools/javac/ImplicitClass/ImplicitImports.java b/test/langtools/tools/javac/ImplicitClass/ImplicitImports.java new file mode 100644 index 00000000000..1362864d8fe --- /dev/null +++ b/test/langtools/tools/javac/ImplicitClass/ImplicitImports.java @@ -0,0 +1,285 @@ +/* + * 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 8325324 + * @summary Verify behavior w.r.t. implicit imports + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @run main ImplicitImports +*/ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Objects; + +import toolbox.TestRunner; +import toolbox.JavacTask; +import toolbox.JavaTask; +import toolbox.Task; +import toolbox.Task.OutputKind; +import toolbox.ToolBox; + +public class ImplicitImports extends TestRunner { + + private static final String SOURCE_VERSION = System.getProperty("java.specification.version"); + private ToolBox tb; + + public static void main(String... args) throws Exception { + new ImplicitImports().runTests(); + } + + ImplicitImports() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testImplicitJavaBaseImport(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeFile(src.resolve("Test.java"), + """ + public static void main(String... args) { + List l = new ArrayList<>(); + System.out.println(l.getClass().getName()); + } + """); + + Files.createDirectories(classes); + + {//with --release: + new JavacTask(tb) + .options("--enable-preview", "--release", SOURCE_VERSION) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + var out = new JavaTask(tb) + .classpath(classes.toString()) + .className("Test") + .vmOptions("--enable-preview") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + var expectedOut = List.of("java.util.ArrayList"); + + if (!Objects.equals(expectedOut, out)) { + throw new AssertionError("Incorrect Output, expected: " + expectedOut + + ", actual: " + out); + + } + } + + {//with --source: + new JavacTask(tb) + .options("--enable-preview", "--source", SOURCE_VERSION) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + var out = new JavaTask(tb) + .classpath(classes.toString()) + .className("Test") + .vmOptions("--enable-preview") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + var expectedOut = List.of("java.util.ArrayList"); + + if (!Objects.equals(expectedOut, out)) { + throw new AssertionError("Incorrect Output, expected: " + expectedOut + + ", actual: " + out); + + } + } + } + + @Test + public void testImplicitSimpleIOImport(Path base) throws Exception { + Path current = base.resolve("."); + + Path patchClasses = prepareIOPatch(current); + + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeFile(src.resolve("Test.java"), + """ + public static void main(String... args) { + println("Hello, World!"); + } + """); + + Files.createDirectories(classes); + + new JavacTask(tb) + .options("--enable-preview", "--release", SOURCE_VERSION, + "--patch-module", "java.base=" + patchClasses) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + var out = new JavaTask(tb) + .classpath(classes.toString()) + .className("Test") + .vmOptions("--enable-preview", + "--patch-module", "java.base=" + patchClasses) + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + var expectedOut = List.of("Hello, World!"); + + if (!Objects.equals(expectedOut, out)) { + throw new AssertionError("Incorrect Output, expected: " + expectedOut + + ", actual: " + out); + + } + } + + @Test + public void testNoImplicitImportsForOrdinaryClasses(Path base) throws Exception { + Path current = base.resolve("."); + + Path patchClasses = prepareIOPatch(current); + + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeFile(src.resolve("Test.java"), + """ + public class Test { + public static void main(String... args) { + List l = new ArrayList<>(); + println("Hello, World!"); + } + } + """); + + Files.createDirectories(classes); + + var log = new JavacTask(tb) + .options("--enable-preview", "--release", SOURCE_VERSION, + "--patch-module", "java.base=" + patchClasses, + "-XDrawDiagnostics") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + var expectedLog = List.of( + "Test.java:3:9: compiler.err.cant.resolve.location: kindname.class, List, , , (compiler.misc.location: kindname.class, Test, null)", + "Test.java:3:30: compiler.err.cant.resolve.location: kindname.class, ArrayList, , , (compiler.misc.location: kindname.class, Test, null)", + "Test.java:4:9: compiler.err.cant.resolve.location.args: kindname.method, println, , java.lang.String, (compiler.misc.location: kindname.class, Test, null)", + "3 errors" + ); + + if (!Objects.equals(expectedLog, log)) { + throw new AssertionError("Incorrect Output, expected: " + expectedLog + + ", actual: " + log); + + } + } + + private Path prepareIOPatch(Path base) throws IOException { + Path patchSrc = base.resolve("patch-src"); + Path patchClasses = base.resolve("patch-classes"); + tb.writeJavaFiles(patchSrc, + """ + package java.io; + public class IO { + public static void println(Object o) { + System.out.println(o); + } + } + """); + + Files.createDirectories(patchClasses); + + new JavacTask(tb) + .options("--patch-module", "java.base=" + patchSrc) + .outdir(patchClasses) + .files(tb.findJavaFiles(patchSrc)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + return patchClasses; + } + + @Test + public void testWithExplicitImport(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeFile(src.resolve("Test.java"), + """ + import java.lang.*; + public static void main(String... args) { + List l = new ArrayList<>(); + System.out.println(l.getClass().getName()); + } + """); + + Files.createDirectories(classes); + + new JavacTask(tb) + .options("--enable-preview", "--release", SOURCE_VERSION) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + var out = new JavaTask(tb) + .classpath(classes.toString()) + .className("Test") + .vmOptions("--enable-preview") + .run() + .writeAll() + .getOutputLines(Task.OutputKind.STDOUT); + + var expectedOut = List.of("java.util.ArrayList"); + + if (!Objects.equals(expectedOut, out)) { + throw new AssertionError("Incorrect Output, expected: " + expectedOut + + ", actual: " + out); + + } + } +} diff --git a/test/langtools/tools/javac/processing/model/TestSymtabItems.java b/test/langtools/tools/javac/processing/model/TestSymtabItems.java index ce20063b9b9..ba9bb20230b 100644 --- a/test/langtools/tools/javac/processing/model/TestSymtabItems.java +++ b/test/langtools/tools/javac/processing/model/TestSymtabItems.java @@ -85,6 +85,10 @@ void run() throws Exception { if (f.getName().toLowerCase().contains("methodhandle")) continue; + // Temporarily ignore java.io.IO: + if (f.getName().equals("ioType")) + continue; + //both noModule and unnamedModule claim the unnamed package, ignore noModule for now: if (f.getName().equals("noModule")) continue; From b890336e111ea8473ae49e9992bc2fd61e716792 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Thu, 23 May 2024 12:07:17 +0000 Subject: [PATCH 09/99] 8328083: degrade virtual thread support for GetObjectMonitorUsage Reviewed-by: cjplummer, alanb --- src/hotspot/share/prims/jvmti.xml | 23 ++++-- src/hotspot/share/prims/jvmtiEnvBase.cpp | 32 ++++++-- src/hotspot/share/runtime/threads.cpp | 13 ++-- src/hotspot/share/runtime/threads.hpp | 3 +- src/java.se/share/data/jdwp/jdwp.spec | 15 ++-- .../classes/com/sun/jdi/ObjectReference.java | 17 +++-- .../ObjectMonitorUsage.java | 75 +++++++++++++++---- .../entryCount/entrycount002.java | 5 +- .../owningThread/owningthread002.java | 9 +++ .../waitingThreads/waitingthreads002.java | 7 +- .../GetObjectMonitorUsage/objmonusage001.java | 26 +++++-- .../GetObjectMonitorUsage/objmonusage004.java | 18 ++++- 12 files changed, 186 insertions(+), 57 deletions(-) diff --git a/src/hotspot/share/prims/jvmti.xml b/src/hotspot/share/prims/jvmti.xml index add7d43ad3e..3bcf15466d7 100644 --- a/src/hotspot/share/prims/jvmti.xml +++ b/src/hotspot/share/prims/jvmti.xml @@ -8249,37 +8249,42 @@ class C2 extends C1 implements I2 { - The thread owning this monitor, or nullptr if unused + The platform thread owning this monitor, or nullptr if owned + by a virtual thread or not owned - The number of times the owning thread has entered the monitor + The number of times the platform thread owning this monitor has entered it, + or 0 if owned by a virtual thread or not owned - The number of threads waiting to own this monitor + The number of platform threads waiting to own this monitor, or 0 + if only virtual threads are waiting or no threads are waiting - The waiter_count waiting threads + The waiter_count waiting platform threads - The number of threads waiting to be notified by this monitor + The number of platform threads waiting to own this monitor, or 0 + if only virtual threads are waiting to be notified or no threads are waiting + to be notified - The notify_waiter_count threads waiting to be notified + The notify_waiter_count platform threads waiting to be notified @@ -8287,6 +8292,12 @@ class C2 extends C1 implements I2 { Get information about the object's monitor. The fields of the structure are filled in with information about usage of the monitor. +

+ This function does not support getting information about an object's monitor + when it is owned by a virtual thread. It also does not support returning a + reference to virtual threads that are waiting to own a monitor or waiting to + be notified. + Decide and then clarify suspend requirements. diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 1615e3c349c..de3d3f76528 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -1482,14 +1482,19 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec // first derive the object's owner and entry_count (if any) owning_thread = ObjectSynchronizer::get_lock_owner(tlh.list(), hobj); if (owning_thread != nullptr) { - Handle th(current_thread, get_vthread_or_thread_oop(owning_thread)); + oop thread_oop = get_vthread_or_thread_oop(owning_thread); + bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); + if (is_virtual) { + thread_oop = nullptr; + } + Handle th(current_thread, thread_oop); ret.owner = (jthread)jni_reference(calling_thread, th); // The recursions field of a monitor does not reflect recursions // as lightweight locks before inflating the monitor are not included. // We have to count the number of recursive monitor entries the hard way. // We pass a handle to survive any GCs along the way. - ret.entry_count = count_locked_objects(owning_thread, hobj); + ret.entry_count = is_virtual ? 0 : count_locked_objects(owning_thread, hobj); } // implied else: entry_count == 0 @@ -1513,6 +1518,7 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec // this object has a lightweight monitor } + jint skipped = 0; if (mon != nullptr) { // Robustness: the actual waiting list can be smaller. // The nWait count we got from the mon->waiters() may include the re-entering @@ -1522,11 +1528,16 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec for (ObjectWaiter* waiter = mon->first_waiter(); waiter != nullptr && (nWait == 0 || waiter != mon->first_waiter()); waiter = mon->next_waiter(waiter)) { + JavaThread *w = mon->thread_of_waiter(waiter); + oop thread_oop = get_vthread_or_thread_oop(w); + if (java_lang_VirtualThread::is_instance(thread_oop)) { + skipped++; + } nWait++; } } ret.waiter_count = nWant; - ret.notify_waiter_count = nWait; + ret.notify_waiter_count = nWait - skipped; // Allocate memory for heavyweight and lightweight monitor. jvmtiError err; @@ -1561,13 +1572,20 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec } if (ret.notify_waiter_count > 0) { // we have threads waiting to be notified in Object.wait() ObjectWaiter *waiter = mon->first_waiter(); + jint skipped = 0; for (int i = 0; i < nWait; i++) { JavaThread *w = mon->thread_of_waiter(waiter); + oop thread_oop = get_vthread_or_thread_oop(w); + bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); assert(w != nullptr, "sanity check"); - // If the thread was found on the ObjectWaiter list, then - // it has not been notified. - Handle th(current_thread, get_vthread_or_thread_oop(w)); - ret.notify_waiters[i] = (jthread)jni_reference(calling_thread, th); + if (java_lang_VirtualThread::is_instance(thread_oop)) { + skipped++; + } else { + // If the thread was found on the ObjectWaiter list, then + // it has not been notified. + Handle th(current_thread, get_vthread_or_thread_oop(w)); + ret.notify_waiters[i - skipped] = (jthread)jni_reference(calling_thread, th); + } waiter = mon->next_waiter(waiter); } } diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index b92e5a90c55..0e2edb7906b 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1183,7 +1183,8 @@ void Threads::metadata_handles_do(void f(Metadata*)) { } #if INCLUDE_JVMTI -// Get count of Java threads that are waiting to enter or re-enter the specified monitor. +// Get Java threads that are waiting to enter or re-enter the specified monitor. +// Java threads that are executing mounted virtual threads are not included. GrowableArray* Threads::get_pending_threads(ThreadsList * t_list, int count, address monitor) { @@ -1194,14 +1195,16 @@ GrowableArray* Threads::get_pending_threads(ThreadsList * t_list, for (JavaThread* p : *t_list) { if (!p->can_call_java()) continue; + oop thread_oop = JvmtiEnvBase::get_vthread_or_thread_oop(p); + if (java_lang_VirtualThread::is_instance(thread_oop)) { + continue; + } // The first stage of async deflation does not affect any field // used by this comparison so the ObjectMonitor* is usable here. address pending = (address)p->current_pending_monitor(); address waiting = (address)p->current_waiting_monitor(); - oop thread_oop = JvmtiEnvBase::get_vthread_or_thread_oop(p); - bool is_virtual = java_lang_VirtualThread::is_instance(thread_oop); - jint state = is_virtual ? JvmtiEnvBase::get_vthread_state(thread_oop, p) - : JvmtiEnvBase::get_thread_state(thread_oop, p); + // do not include virtual threads to the list + jint state = JvmtiEnvBase::get_thread_state(thread_oop, p); if (pending == monitor || (waiting == monitor && (state & JVMTI_THREAD_STATE_BLOCKED_ON_MONITOR_ENTER)) ) { // found a match diff --git a/src/hotspot/share/runtime/threads.hpp b/src/hotspot/share/runtime/threads.hpp index 6c4573827d9..39e307122c8 100644 --- a/src/hotspot/share/runtime/threads.hpp +++ b/src/hotspot/share/runtime/threads.hpp @@ -129,7 +129,8 @@ class Threads: AllStatic { // Print threads busy compiling, and returns the number of printed threads. static unsigned print_threads_compiling(outputStream* st, char* buf, int buflen, bool short_form = false); - // Get count of Java threads that are waiting to enter or re-enter the specified monitor. + // Get Java threads that are waiting to enter or re-enter the specified monitor. + // Java threads that are executing mounted virtual threads are not included. static GrowableArray* get_pending_threads(ThreadsList * t_list, int count, address monitor); diff --git a/src/java.se/share/data/jdwp/jdwp.spec b/src/java.se/share/data/jdwp/jdwp.spec index df23a602b13..5206a0c6ae9 100644 --- a/src/java.se/share/data/jdwp/jdwp.spec +++ b/src/java.se/share/data/jdwp/jdwp.spec @@ -1617,11 +1617,14 @@ JDWP "Java(tm) Debug Wire Protocol" (object object "The object ID") ) (Reply - (threadObject owner "The monitor owner, or null if it is not currently owned.") - (int entryCount "The number of times the monitor has been entered.") - (Repeat waiters "The total number of threads that are waiting to enter or re-enter " - "the monitor, or waiting to be notified by the monitor." - (threadObject thread "A thread waiting for this monitor.") + (threadObject owner "The platform thread owning this monitor, or null " + "if owned by a virtual thread or not owned.") + (int entryCount "The number of times the owning platform thread has entered the monitor, " + "or 0 if owned by a virtual thread or not owned.") + (Repeat waiters "The total number of platform threads that are waiting to enter or re-enter " + "the monitor, or waiting to be notified by the monitor, or 0 if " + "only virtual threads are waiting or no threads are waiting." + (threadObject thread "A platform thread waiting for this monitor.") ) ) (ErrorSet @@ -2871,7 +2874,7 @@ JDWP "Java(tm) Debug Wire Protocol" "if not explicitly requested." (int requestID - "Request that generated event (or 0 if this " + "Request that generated event, or 0 if this " "event is automatically generated.") (threadObject thread "Initial thread") ) diff --git a/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java b/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java index dbcf77d3e39..f53b8acbb8b 100644 --- a/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java +++ b/src/jdk.jdi/share/classes/com/sun/jdi/ObjectReference.java @@ -345,7 +345,7 @@ Value invokeMethod(ThreadReference thread, Method method, /** * Returns a List containing a {@link ThreadReference} for - * each thread currently waiting for this object's monitor. + * each platform thread currently waiting for this object's monitor. * See {@link ThreadReference#currentContendedMonitor} for * information about when a thread is considered to be waiting * for a monitor. @@ -355,7 +355,8 @@ Value invokeMethod(ThreadReference thread, Method method, * operation is supported. * * @return a List of {@link ThreadReference} objects. The list - * has zero length if no threads are waiting for the monitor. + * has zero length if no threads are waiting for the monitor, + * or only virtual threads are waiting for the monitor. * @throws java.lang.UnsupportedOperationException if the * target VM does not support this operation. * @throws IncompatibleThreadStateException if any @@ -366,7 +367,7 @@ List waitingThreads() throws IncompatibleThreadStateException; /** - * Returns an {@link ThreadReference} for the thread, if any, + * Returns a {@link ThreadReference} for the platform thread, if any, * which currently owns this object's monitor. * See {@link ThreadReference#ownedMonitors} for a definition * of ownership. @@ -375,8 +376,9 @@ List waitingThreads() * {@link VirtualMachine#canGetMonitorInfo} to determine if the * operation is supported. * - * @return the {@link ThreadReference} which currently owns the - * monitor, or null if it is unowned. + * @return the {@link ThreadReference} of the platform thread which + * currently owns the monitor, or null if the monitor is owned + * by a virtual thread or not owned. * * @throws java.lang.UnsupportedOperationException if the * target VM does not support this operation. @@ -386,8 +388,9 @@ List waitingThreads() ThreadReference owningThread() throws IncompatibleThreadStateException; /** - * Returns the number times this object's monitor has been - * entered by the current owning thread. + * Returns the number of times this object's monitor has been entered by + * the current owning thread if the owning thread is platform thread; + * Returns 0 if not owned by a platform thread. * See {@link ThreadReference#ownedMonitors} for a definition * of ownership. *

diff --git a/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java index bc9a0c5cabc..0d136cadef7 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java +++ b/test/hotspot/jtreg/serviceability/jvmti/ObjectMonitorUsage/ObjectMonitorUsage.java @@ -114,6 +114,13 @@ static void joinThreads(Thread[] threads) { throw new Error("Unexpected " + e); } } + static Thread expOwnerThread() { + return Thread.currentThread().isVirtual() ? null : Thread.currentThread(); + } + + static int expEntryCount() { + return Thread.currentThread().isVirtual() ? 0 : 1; + } /* Scenario #0: * - owning: 0 @@ -127,14 +134,18 @@ static void test0(boolean isVirtual) { setTestedMonitor(lockCheck); Thread[] wThreads = startWaitingThreads(isVirtual); + final int expWaitingCount = isVirtual ? 0 : NUMBER_OF_WAITING_THREADS; + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 0 // count of threads waiting to enter: 0 // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS check(lockCheck, null, 0, // no owner thread 0, // count of threads waiting to enter: 0 - NUMBER_OF_WAITING_THREADS); + expWaitingCount); synchronized (lockCheck) { lockCheck.notifyAll(); @@ -158,20 +169,30 @@ static void test1(boolean isVirtual) { Thread[] eThreads = null; synchronized (lockCheck) { + // Virtual threads are not supported by GetObjectMonitorUsage. + // Correct the expected values for the virtual thread case. + int expEnteringCount = isVirtual ? 0 : NUMBER_OF_ENTERING_THREADS; + + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: 0 // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: 0 - check(lockCheck, Thread.currentThread(), 1, 0, 0); + check(lockCheck, expOwnerThread(), expEntryCount(), 0, 0); eThreads = startEnteringThreads(isVirtual); + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: 0 - check(lockCheck, Thread.currentThread(), 1, - NUMBER_OF_ENTERING_THREADS, + check(lockCheck, expOwnerThread(), expEntryCount(), + expEnteringCount, 0 /* count of threads waiting to be notified: 0 */); } @@ -195,15 +216,23 @@ static void test2(boolean isVirtual) throws Error { Thread[] eThreads = null; synchronized (lockCheck) { + // Virtual threads are not supported by the GetObjectMonitorUsage. + // Correct the expected values for the virtual thread case. + int expEnteringCount = isVirtual ? 0 : NUMBER_OF_ENTERING_THREADS; + int expWaitingCount = isVirtual ? 0 : NUMBER_OF_WAITING_THREADS; + eThreads = startEnteringThreads(isVirtual); + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS - check(lockCheck, Thread.currentThread(), 1, - NUMBER_OF_ENTERING_THREADS, - NUMBER_OF_WAITING_THREADS); + check(lockCheck, expOwnerThread(), expEntryCount(), + expEnteringCount, + expWaitingCount); lockCheck.notifyAll(); } @@ -234,35 +263,51 @@ static void test3(boolean isVirtual) throws Error { Thread[] eThreads = null; synchronized (lockCheck) { + // Virtual threads are not supported by GetObjectMonitorUsage. + // Correct the expected values for the virtual thread case. + int expEnteringCount = isVirtual ? 0 : NUMBER_OF_ENTERING_THREADS; + int expWaitingCount = isVirtual ? 0 : NUMBER_OF_WAITING_THREADS; + + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: 0 // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS - check(lockCheck, Thread.currentThread(), 1, + check(lockCheck, expOwnerThread(), expEntryCount(), 0, // number of threads waiting to enter or re-enter - NUMBER_OF_WAITING_THREADS); + expWaitingCount); eThreads = startEnteringThreads(isVirtual); + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS // count of threads waiting to re-enter: 0 // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS - check(lockCheck, Thread.currentThread(), 1, - NUMBER_OF_ENTERING_THREADS, - NUMBER_OF_WAITING_THREADS); + check(lockCheck, expOwnerThread(), expEntryCount(), + expEnteringCount, + expWaitingCount); for (int i = 0; i < NUMBER_OF_WAITING_THREADS; i++) { + expEnteringCount = isVirtual ? 0 : NUMBER_OF_ENTERING_THREADS + i + 1; + expWaitingCount = isVirtual ? 0 : NUMBER_OF_WAITING_THREADS - i - 1; lockCheck.notify(); // notify waiting threads one by one // now the notified WaitingTask has to be blocked on the lockCheck re-enter + // The numbers below describe the testing scenario, not the expected results. + // The expected numbers are different for virtual threads because + // they are not supported by JVMTI GetObjectMonitorUsage. // entry count: 1 // count of threads waiting to enter: NUMBER_OF_ENTERING_THREADS // count of threads waiting to re-enter: i + 1 // count of threads waiting to be notified: NUMBER_OF_WAITING_THREADS - i - 1 - check(lockCheck, Thread.currentThread(), 1, - NUMBER_OF_ENTERING_THREADS + i + 1, - NUMBER_OF_WAITING_THREADS - i - 1); + check(lockCheck, expOwnerThread(), expEntryCount(), + expEnteringCount, + expWaitingCount); } } joinThreads(wThreads); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/entryCount/entrycount002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/entryCount/entrycount002.java index 7736eae1d2b..e5e8f4e8d80 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/entryCount/entrycount002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/entryCount/entrycount002.java @@ -197,8 +197,11 @@ private void execTest() { display("Checking entryCount for iteration : " + i); try { + // The lockRef.entryCount() is expected to return 0 if the owner thread is virtual. + int expEntryCount = mainThread.isVirtual() ? 0 : i; int entryCount = lockRef.entryCount(); - if (entryCount != i) { + + if (entryCount != expEntryCount) { exitCode = Consts.TEST_FAILED; complain("entry count method returned unexpected value : " + entryCount + "\n\t expected one : " + i); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/owningThread/owningthread002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/owningThread/owningthread002.java index 89d1b703310..83e0bbb8c05 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/owningThread/owningthread002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/owningThread/owningthread002.java @@ -200,6 +200,15 @@ private void execTest() { try { ThreadReference thread = lockRef.owningThread(); + // The lockRef.owningThread() is expected to return null if tested threads are virtual. + if (eventThread.isVirtual()) { + if (thread == null) { + display("expected null is returned` by owningThread method on virtual thread: " + eventThread.name()); + } else { + complain("owningThread returned ThreadReference of virtual thread instead of null: " + thread.name()); + } + continue; + } if (thread.name().indexOf(owningthread002a.threadNamePrefix) < 0) { exitCode = Consts.TEST_FAILED; complain("owningThread returned ThreadReference with unexpected name: " + thread.name()); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads002.java index 356f78876aa..74bc41a34eb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/waitingThreads/waitingthreads002.java @@ -122,6 +122,9 @@ private static void execTest() { if (thread.name().indexOf(waitingthreads002a.threadNamePrefix) >= 0 && thread.status() == ThreadReference.THREAD_STATUS_MONITOR ) { waitingCount++; + // Virtual threads are not present in result returned by objRef.waitingThreads(). + if (!thread.isVirtual()) { + } } } } @@ -159,7 +162,9 @@ private static void execTest() { objRef = (ObjectReference) debuggeeClass.getValue(debuggeeClass.fieldByName(fieldName)); try { List waitingThreads = objRef.waitingThreads(); - if (waitingThreads.size() != waitingthreads002a.threadCount) { + final boolean vthreadMode = "Virtual".equals(System.getProperty("test.thread.factory")); + final int expWaitingCount = vthreadMode ? 0 : waitingthreads002a.threadCount; + if (waitingThreads.size() != expWaitingCount) { exitStatus = Consts.TEST_FAILED; complain("waitingThreads method returned list with unexpected size for " + fieldName + "\n\t expected value : " + waitingthreads002a.threadCount + "; got one : " + waitingThreads.size()); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java index 1ae3bf79e1c..c3c3cb31ebd 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage001.java @@ -61,8 +61,16 @@ public static int run(String argv[], PrintStream out) { syncObject[i] = new Object(); runn[i] = new objmonusage001a(mainThread, i, syncObject[i]); } + // Virtual threads are not supported by GetObjectMonitorUsage. + // Correct the expected values if the test is executed with + // JTREG_TEST_THREAD_FACTORY=Virtual. + Thread expOwner = mainThread.isVirtual() ? null : mainThread; + int expEntryCount = mainThread.isVirtual() ? 0 : 1; for (int i = 0; i < NUMBER_OF_THREADS; i++) { + Thread expNotifyWaiter = runn[i].isVirtual() ? null : runn[i]; + int expNotifyWaitingCount = runn[i].isVirtual() ? 0 : 1; + synchronized (syncObject[i]) { runn[i].start(); try { @@ -92,8 +100,8 @@ public static int run(String argv[], PrintStream out) { // This is a stable verification point because the worker thread is in wait() // and is not notified and the main thread is doing the verification. // - check(NUMBER_OF_THREADS + i, syncObject[i], mainThread, 1, - null, 0, runn[i], 1); + check(NUMBER_OF_THREADS + i, syncObject[i], expOwner, expEntryCount, + null, 0, expNotifyWaiter, expNotifyWaitingCount); } // Check #3: @@ -117,7 +125,7 @@ public static int run(String argv[], PrintStream out) { // and is not notified and the main thread is doing the verification. // check((NUMBER_OF_THREADS * 2) + i, syncObject[i], null, 0, - null, 0, runn[i], 1); + null, 0, expNotifyWaiter, expNotifyWaitingCount); } for (int i = 0; i < NUMBER_OF_THREADS; i++) { @@ -147,6 +155,14 @@ public objmonusage001a(Thread mt, int i, Object s) { } public void run() { + // Virtual threads are not supported by GetObjectMonitorUsage. + // Correct the expected values if the test is executed with + // JTREG_TEST_THREAD_FACTORY=Virtual. + Thread expOwner = this.isVirtual() ? null : this; + Thread expNotifyWaiter = mainThread.isVirtual() ? null : mainThread; + int expEntryCount = this.isVirtual() ? 0 : 1; + int expNotifyWaitingCount = mainThread.isVirtual() ? 0 : 1; + synchronized (syncObject) { // Check #1: // - owner == this_thread: @@ -166,8 +182,8 @@ public void run() { // This is a stable verification point because the main thread is in wait() // and is not notified and this worker thread is doing the verification. // - objmonusage001.check(index, syncObject, this, 1, - null, 0, mainThread, 1); + objmonusage001.check(index, syncObject, expOwner, expEntryCount, + null, 0, expNotifyWaiter, expNotifyWaitingCount); syncObject.notify(); try { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java index 37addef82d6..8d79a6011f5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetObjectMonitorUsage/objmonusage004.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 @@ -60,11 +60,23 @@ public static int run(String args[], PrintStream out) { Thread currThread = Thread.currentThread(); ContendThread thr[] = new ContendThread[NUMBER_OF_THREADS]; synchronized (lockCheck) { + // Virtual threads are not supported by GetObjectMonitorUsage. + // Correct the expected values if the test is executed with + // JTREG_TEST_THREAD_FACTORY=Virtual. + Thread expOwner = currThread.isVirtual() ? null : currThread; + int expEntryCount = currThread.isVirtual() ? 0 : 2; + synchronized (lockCheck) { - check(lockCheck, currThread, 2, 0); + check(lockCheck, expOwner, expEntryCount, 0); } + expEntryCount = currThread.isVirtual() ? 0 : 1; + int expWaiterCount = 0; + for (int i = 0; i < NUMBER_OF_THREADS; i++) { thr[i] = new ContendThread(); + if (!thr[i].isVirtual()) { + expWaiterCount++; + } synchronized (lockStart) { thr[i].start(); try { @@ -74,7 +86,7 @@ public static int run(String args[], PrintStream out) { throw new Error("Unexpected " + e); } } - check(lockCheck, currThread, 1, i + 1); + check(lockCheck, expOwner, expEntryCount, expWaiterCount); } } From 2581935b47afaf661a94c8a8e50ce08065d632f6 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 23 May 2024 12:26:19 +0000 Subject: [PATCH 10/99] 8332528: Generate code in SwitchBootstraps.generateTypeSwitch that require fewer adaptations Reviewed-by: liach, jlahoda --- .../build/tools/classlist/HelloClasslist.java | 11 +++ .../java/lang/runtime/SwitchBootstraps.java | 86 ++++++++++--------- .../constant/ReferenceClassDescImpl.java | 11 +++ .../bench/java/lang/runtime/SwitchSanity.java | 83 ++++++++++++++++++ 4 files changed, 151 insertions(+), 40 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/lang/runtime/SwitchSanity.java diff --git a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java index 921eaeee764..1b930ca7527 100644 --- a/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java +++ b/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java @@ -151,6 +151,17 @@ public static void main(String ... args) throws Throwable { LOGGER.log(Level.FINE, "New Date: " + newDate + " - old: " + oldDate); + // Pull SwitchBootstraps and associated classes into the classlist + record A(int a) { } + record B(int b) { } + Object o = new A(4711); + int value = switch (o) { + case A a -> a.a; + case B b -> b.b; + default -> 17; + }; + LOGGER.log(Level.FINE, "Value: " + value); + // The Striped64$Cell is loaded rarely only when there's a contention among // multiple threads performing LongAdder.increment(). This results in // an inconsistency in the classlist between builds (see JDK-8295951). 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 9ec60d9a152..c564b7b69f6 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -26,6 +26,7 @@ package java.lang.runtime; import java.lang.Enum.EnumDesc; +import java.lang.classfile.ClassBuilder; import java.lang.classfile.CodeBuilder; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDesc; @@ -48,6 +49,8 @@ import java.lang.classfile.ClassFile; import java.lang.classfile.Label; import java.lang.classfile.instruction.SwitchCase; + +import jdk.internal.constant.ReferenceClassDescImpl; import jdk.internal.misc.PreviewFeatures; import jdk.internal.vm.annotation.Stable; @@ -74,28 +77,38 @@ private SwitchBootstraps() {} private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); private static final boolean previewEnabled = PreviewFeatures.isEnabled(); - private static final MethodHandle NULL_CHECK; - private static final MethodHandle IS_ZERO; - private static final MethodHandle CHECK_INDEX; - private static final MethodHandle MAPPED_ENUM_LOOKUP; + + private static final MethodType TYPES_SWITCH_TYPE = MethodType.methodType(int.class, + Object.class, + int.class, + BiPredicate.class, + List.class); private static final MethodTypeDesc TYPES_SWITCH_DESCRIPTOR = MethodTypeDesc.ofDescriptor("(Ljava/lang/Object;ILjava/util/function/BiPredicate;Ljava/util/List;)I"); - - static { - try { - NULL_CHECK = LOOKUP.findStatic(Objects.class, "isNull", - MethodType.methodType(boolean.class, Object.class)); - IS_ZERO = LOOKUP.findStatic(SwitchBootstraps.class, "isZero", - MethodType.methodType(boolean.class, int.class)); - CHECK_INDEX = LOOKUP.findStatic(Objects.class, "checkIndex", - MethodType.methodType(int.class, int.class, int.class)); - MAPPED_ENUM_LOOKUP = LOOKUP.findStatic(SwitchBootstraps.class, "mappedEnumLookup", - MethodType.methodType(int.class, Enum.class, MethodHandles.Lookup.class, - Class.class, EnumDesc[].class, EnumMap.class)); - } - catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); + private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR = + MethodTypeDesc.ofDescriptor("(II)I"); + + private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;"); + + private static class StaticHolders { + private static final MethodHandle NULL_CHECK; + private static final MethodHandle IS_ZERO; + private static final MethodHandle MAPPED_ENUM_LOOKUP; + + static { + try { + NULL_CHECK = LOOKUP.findStatic(Objects.class, "isNull", + MethodType.methodType(boolean.class, Object.class)); + IS_ZERO = LOOKUP.findStatic(SwitchBootstraps.class, "isZero", + MethodType.methodType(boolean.class, int.class)); + MAPPED_ENUM_LOOKUP = LOOKUP.findStatic(SwitchBootstraps.class, "mappedEnumLookup", + MethodType.methodType(int.class, Enum.class, MethodHandles.Lookup.class, + Class.class, EnumDesc[].class, EnumMap.class)); + } + catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } } } @@ -163,14 +176,13 @@ public static CallSite typeSwitch(MethodHandles.Lookup lookup, || (!invocationType.returnType().equals(int.class)) || !invocationType.parameterType(1).equals(int.class)) throw new IllegalArgumentException("Illegal invocation type " + invocationType); - requireNonNull(labels); - Stream.of(labels).forEach(l -> verifyLabel(l, selectorType)); + for (Object l : labels) { // implicit null-check + verifyLabel(l, selectorType); + } MethodHandle target = generateTypeSwitch(lookup, selectorType, labels); - target = withIndexCheck(target, labels.length); - return new ConstantCallSite(target); } @@ -282,18 +294,17 @@ public static CallSite enumSwitch(MethodHandles.Lookup lookup, //else if (idx == 0) return mappingArray[selector.ordinal()]; //mapping array created lazily //else return "typeSwitch(labels)" MethodHandle body = - MethodHandles.guardWithTest(MethodHandles.dropArguments(NULL_CHECK, 0, int.class), + MethodHandles.guardWithTest(MethodHandles.dropArguments(StaticHolders.NULL_CHECK, 0, int.class), MethodHandles.dropArguments(MethodHandles.constant(int.class, -1), 0, int.class, Object.class), - MethodHandles.guardWithTest(MethodHandles.dropArguments(IS_ZERO, 1, Object.class), + MethodHandles.guardWithTest(MethodHandles.dropArguments(StaticHolders.IS_ZERO, 1, Object.class), generateTypeSwitch(lookup, invocationType.parameterType(0), labels), - MethodHandles.insertArguments(MAPPED_ENUM_LOOKUP, 1, lookup, enumClass, labels, new EnumMap()))); + MethodHandles.insertArguments(StaticHolders.MAPPED_ENUM_LOOKUP, 1, lookup, enumClass, labels, new EnumMap()))); target = MethodHandles.permuteArguments(body, MethodType.methodType(int.class, Object.class, int.class), 1, 0); } else { target = generateTypeSwitch(lookup, invocationType.parameterType(0), labels); } target = target.asType(invocationType); - target = withIndexCheck(target, labels.length); return new ConstantCallSite(target); } @@ -339,12 +350,6 @@ private static > int mappedEnumLookup(T value, MethodHandles.L return enumMap.map[value.ordinal()]; } - private static MethodHandle withIndexCheck(MethodHandle target, int labelsCount) { - MethodHandle checkIndex = MethodHandles.insertArguments(CHECK_INDEX, 1, labelsCount + 1); - - return MethodHandles.filterArguments(target, 1, checkIndex); - } - private static final class ResolvedEnumLabels implements BiPredicate { private final MethodHandles.Lookup lookup; @@ -407,6 +412,11 @@ private static Consumer generateTypeSwitchSkeleton(Class selecto int EXTRA_CLASS_LABELS = 3; return cb -> { + // Objects.checkIndex(RESTART_IDX, labelConstants + 1) + cb.iload(RESTART_IDX); + cb.loadConstant(labelConstants.length + 1); + cb.invokestatic(CD_Objects, "checkIndex", CHECK_INDEX_DESCRIPTOR); + cb.pop(); cb.aload(SELECTOR_OBJ); Label nonNullLabel = cb.newLabel(); cb.if_nonnull(nonNullLabel); @@ -621,7 +631,7 @@ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Clas List> enumDescs = new ArrayList<>(); List> extraClassLabels = new ArrayList<>(); - byte[] classBytes = ClassFile.of().build(ClassDesc.of(typeSwitchClassName(caller.lookupClass())), + byte[] classBytes = ClassFile.of().build(ReferenceClassDescImpl.ofValidatedBinaryName(typeSwitchClassName(caller.lookupClass())), clb -> { clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC) .withMethodBody("typeSwitch", @@ -636,12 +646,8 @@ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Clas lookup = caller.defineHiddenClass(classBytes, true, NESTMATE, STRONG); MethodHandle typeSwitch = lookup.findStatic(lookup.lookupClass(), "typeSwitch", - MethodType.methodType(int.class, - Object.class, - int.class, - BiPredicate.class, - List.class)); - typeSwitch = MethodHandles.insertArguments(typeSwitch, 2, new ResolvedEnumLabels(caller, enumDescs.toArray(EnumDesc[]::new)), + TYPES_SWITCH_TYPE); + typeSwitch = MethodHandles.insertArguments(typeSwitch, 2, new ResolvedEnumLabels(caller, enumDescs.toArray(new EnumDesc[0])), List.copyOf(extraClassLabels)); typeSwitch = MethodHandles.explicitCastArguments(typeSwitch, MethodType.methodType(int.class, diff --git a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java index e8d73b08097..a1efc0fd10f 100644 --- a/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java +++ b/src/java.base/share/classes/jdk/internal/constant/ReferenceClassDescImpl.java @@ -69,6 +69,17 @@ public static ReferenceClassDescImpl ofValidated(String descriptor) { return new ReferenceClassDescImpl(descriptor); } + /** + * Creates a {@linkplain ClassDesc} from a pre-validated descriptor string + * for a class or interface type or an array type. + * + * @param descriptor a field descriptor string for a class or interface type + * @jvms 4.3.2 Field Descriptors + */ + public static ClassDesc ofValidatedBinaryName(String typeSwitchClassName) { + return ofValidated("L" + binaryToInternal(typeSwitchClassName) + ";"); + } + @Override public String descriptorString() { return descriptor; diff --git a/test/micro/org/openjdk/bench/java/lang/runtime/SwitchSanity.java b/test/micro/org/openjdk/bench/java/lang/runtime/SwitchSanity.java new file mode 100644 index 00000000000..7d78cb3e2e0 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/runtime/SwitchSanity.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.runtime; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +@Fork(3) +public class SwitchSanity { + + public record A(int a) { } + public record B(int b) { } + public record C(int c) { } + + public Object[] inputs = new Object[10]; + @Setup + public void setup() { + for (int i = 0; i < 10; i++) { + if (i % 2 == 0) { + inputs[i] = new A(i + 17); + } else if (i % 3 == 0) { + inputs[i] = new B(i + 4711); + } else { + inputs[i] = new C(i + 174711); + } + } + } + + @Benchmark + public int switchSum() { + int sum = 0; + for (Object o : inputs) { + sum += switch (o) { + case A a -> a.a; + case B b -> b.b; + case C c -> c.c; + default -> 17; + }; + } + return sum; + } + + public static void main(String[] args) { + SwitchSanity s = new SwitchSanity(); + s.setup(); + System.out.println(s.switchSum()); + } +} From e19a421c30534566ba0dea0fa84f812ebeecfc87 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 23 May 2024 13:22:30 +0000 Subject: [PATCH 11/99] 8332720: ubsan: instanceKlass.cpp:3550:76: runtime error: member call on null pointer of type 'struct Array' Reviewed-by: stefank, mdoerr --- src/hotspot/share/oops/instanceKlass.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 3b3a4ac10a6..dcc38360399 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -3547,11 +3547,13 @@ void InstanceKlass::print_on(outputStream* st) const { } } st->print(BULLET"method ordering: "); method_ordering()->print_value_on(st); st->cr(); - st->print(BULLET"default_methods: "); default_methods()->print_value_on(st); st->cr(); - if (Verbose && default_methods() != nullptr) { - Array* method_array = default_methods(); - for (int i = 0; i < method_array->length(); i++) { - st->print("%d : ", i); method_array->at(i)->print_value(); st->cr(); + if (default_methods() != nullptr) { + st->print(BULLET"default_methods: "); default_methods()->print_value_on(st); st->cr(); + if (Verbose) { + Array* method_array = default_methods(); + for (int i = 0; i < method_array->length(); i++) { + st->print("%d : ", i); method_array->at(i)->print_value(); st->cr(); + } } } if (default_vtable_indices() != nullptr) { From 90758f6735620776fcb60da9e0e2c91a4f53aaf1 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Thu, 23 May 2024 14:36:23 +0000 Subject: [PATCH 12/99] 8332808: Always set java.io.tmpdir to a suitable value in the build Reviewed-by: erikj --- make/InitSupport.gmk | 3 +++ make/autoconf/spec.gmk.template | 5 ++++- make/common/JavaCompilation.gmk | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk index c59e685bf4f..b6a0a8d5d6f 100644 --- a/make/InitSupport.gmk +++ b/make/InitSupport.gmk @@ -501,9 +501,12 @@ else # $(HAS_SPEC)=true # Failure logs are only supported for "parallel" main targets, not the # (trivial) sequential make targets (such as clean and reconfigure), # since the failure-logs directory creation will conflict with clean. + # We also make sure the javatmp directory exists, which is needed if a java + # process (like javac) is using java.io.tmpdir. define PrepareFailureLogs $(RM) -r $(MAKESUPPORT_OUTPUTDIR)/failure-logs 2> /dev/null && \ $(MKDIR) -p $(MAKESUPPORT_OUTPUTDIR)/failure-logs + $(MKDIR) -p $(JAVA_TMP_DIR) $(RM) $(MAKESUPPORT_OUTPUTDIR)/exit-with-error 2> /dev/null endef diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index 7ce4038f641..7ef1aee861a 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -353,6 +353,8 @@ BUNDLES_OUTPUTDIR = $(OUTPUTDIR)/bundles TESTMAKE_OUTPUTDIR = $(OUTPUTDIR)/test-make MAKESUPPORT_OUTPUTDIR = $(OUTPUTDIR)/make-support +JAVA_TMP_DIR = $(SUPPORT_OUTPUTDIR)/javatmp + # This does not get overridden in a bootcycle build CONFIGURESUPPORT_OUTPUTDIR := @CONFIGURESUPPORT_OUTPUTDIR@ BUILDJDK_OUTPUTDIR = $(OUTPUTDIR)/buildjdk @@ -634,7 +636,8 @@ STATIC_BUILD := @STATIC_BUILD@ STRIPFLAGS := @STRIPFLAGS@ -JAVA_FLAGS := @JAVA_FLAGS@ +JAVA_FLAGS_TMPDIR := -Djava.io.tmpdir=$(JAVA_TMP_DIR) +JAVA_FLAGS := @JAVA_FLAGS@ $(JAVA_FLAGS_TMPDIR) JAVA_FLAGS_BIG := @JAVA_FLAGS_BIG@ JAVA_FLAGS_SMALL := @JAVA_FLAGS_SMALL@ BUILD_JAVA_FLAGS_SMALL := @BUILD_JAVA_FLAGS_SMALL@ diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index 259c1834da3..1503c86aff1 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -197,7 +197,7 @@ define SetupJavaCompilationBody ifeq ($$($1_COMPILER), bootjdk) # Javac server is not available when using the bootjdk compiler. - $1_JAVAC_CMD := $$(JAVAC) + $1_JAVAC_CMD := $$(JAVAC) -J$$(JAVA_FLAGS_TMPDIR) ifeq ($$($1_SMALL_JAVA), true) $1_FLAGS += $$(addprefix -J, $$(JAVA_FLAGS_SMALL)) @@ -211,7 +211,7 @@ define SetupJavaCompilationBody $1_TARGET_RELEASE := $$(TARGET_RELEASE_BOOTJDK) endif else ifeq ($$($1_COMPILER), buildjdk) - $1_JAVAC_CMD := $$(BUILD_JAVAC) + $1_JAVAC_CMD := $$(BUILD_JAVAC) -J$$(JAVA_FLAGS_TMPDIR) ifeq ($$($1_TARGET_RELEASE), ) # If unspecified, default to the new jdk we're building From 303ac9f270f567d821d156f3a9d4f4c070f43f95 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 23 May 2024 15:54:11 +0000 Subject: [PATCH 13/99] 8332671: Logging for pretouching thread stacks shows wrong memory range Reviewed-by: shade --- src/hotspot/share/runtime/javaThread.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 97be5333413..e4992f36842 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -2230,8 +2230,8 @@ void JavaThread::pretouch_stack() { if (is_in_full_stack(here) && here > end) { size_t to_alloc = here - end; char* p2 = (char*) alloca(to_alloc); - log_trace(os, thread)("Pretouching thread stack from " PTR_FORMAT " to " PTR_FORMAT ".", - p2i(p2), p2i(end)); + log_trace(os, thread)("Pretouching thread stack for " UINTX_FORMAT ": " RANGEFMT ".", + (uintx) osthread()->thread_id(), RANGEFMTARGS(p2, to_alloc)); os::pretouch_memory(p2, p2 + to_alloc, NOT_AIX(os::vm_page_size()) AIX_ONLY(4096)); } From 417d174aa1b7bd3b5755e5f2352d9bbe6ce6f183 Mon Sep 17 00:00:00 2001 From: Nizar Benalla Date: Thu, 23 May 2024 16:04:40 +0000 Subject: [PATCH 14/99] 8331348: Some incremental builds deposit files in the make directory Reviewed-by: ihse, vromero --- .../share/classes/com/sun/tools/javac/main/Main.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java index df4ba222139..32496bde02d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, 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 @@ -371,9 +371,10 @@ public void put(String name, String value) { } } void printArgumentsToFile(String... params) { - Path out = Paths.get(String.format("javac.%s.args", + Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir")); + Path out = tmpDir.resolve(String.format("javac.%s.args", new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime()))); - String strOut = ""; + String strOut = "# javac crashed, this report includes the parameters passed to it in the @-file format\n"; try { try (Writer w = Files.newBufferedWriter(out)) { for (String param : params) { From 7fd9d6c760c66d3e2f4034cf1a6b1b583ff829a9 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 23 May 2024 16:04:56 +0000 Subject: [PATCH 15/99] 8332340: Add JavacBench as a test case for CDS Reviewed-by: ccheung, matsaave --- .../cds/appcds/applications/JavacBench.java | 76 ++++++ .../appcds/applications/JavacBenchApp.java | 228 +++++++++++++++++ test/lib/jdk/test/lib/StringArrayUtils.java | 63 +++++ test/lib/jdk/test/lib/cds/CDSAppTester.java | 240 ++++++++++++++++++ 4 files changed, 607 insertions(+) create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java create mode 100644 test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBenchApp.java create mode 100644 test/lib/jdk/test/lib/StringArrayUtils.java create mode 100644 test/lib/jdk/test/lib/cds/CDSAppTester.java diff --git a/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java b/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java new file mode 100644 index 00000000000..50696c8c1fc --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBench.java @@ -0,0 +1,76 @@ +/* + * 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. + * + */ + +/* + * @test id=static + * @summary Run JavacBenchApp with the classic static archive workflow + * @requires vm.cds + * @library /test/lib + * @run driver JavacBench STATIC + */ + +/* + * @test id=dynamic + * @summary Run JavacBenchApp with the classic dynamic archive workflow + * @requires vm.cds + * @library /test/lib + * @run driver JavacBench DYNAMIC + */ + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.helpers.ClassFileInstaller; + +public class JavacBench { + static String mainClass = JavacBenchApp.class.getName(); + static String appJar; + + public static void main(String args[]) throws Exception { + appJar = ClassFileInstaller.writeJar("JavacBenchApp.jar", + "JavacBenchApp", + "JavacBenchApp$ClassFile", + "JavacBenchApp$FileManager", + "JavacBenchApp$SourceFile"); + JavacBenchTester tester = new JavacBenchTester(); + tester.run(args); + } + + static class JavacBenchTester extends CDSAppTester { + public JavacBenchTester() { + super("JavacBench"); + } + + @Override + public String classpath(RunMode runMode) { + return appJar; + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { + mainClass, + "90", + }; + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBenchApp.java b/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBenchApp.java new file mode 100644 index 00000000000..a32069883af --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/applications/JavacBenchApp.java @@ -0,0 +1,228 @@ +/* + * 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.lang.invoke.MethodHandles; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +/** + * This program tries to compile a large number of classes that exercise a fair amount of + * features in javac. + */ +public class JavacBenchApp { + static class ClassFile extends SimpleJavaFileObject { + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + protected ClassFile(String name) { + super(URI.create("memo:///" + name.replace('.', '/') + Kind.CLASS.extension), Kind.CLASS); + } + @Override + public ByteArrayOutputStream openOutputStream() { + return this.baos; + } + byte[] toByteArray() { + return baos.toByteArray(); + } + } + + static class FileManager extends ForwardingJavaFileManager { + private Map classesMap = new HashMap(); + protected FileManager(JavaFileManager fileManager) { + super(fileManager); + } + @Override + public ClassFile getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject source) { + ClassFile classFile = new ClassFile(name); + classesMap.put(name, classFile); + return classFile; + } + public Map getCompiledClasses() { + Map result = new HashMap<>(); + for (Map.Entry entry : classesMap.entrySet()) { + result.put(entry.getKey(), entry.getValue().toByteArray()); + } + return result; + } + } + + static class SourceFile extends SimpleJavaFileObject { + private CharSequence sourceCode; + public SourceFile(String name, CharSequence sourceCode) { + super(URI.create("memo:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); + this.sourceCode = sourceCode; + } + @Override + public CharSequence getCharContent(boolean ignore) { + return this.sourceCode; + } + } + + public Map compile() { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + DiagnosticCollector ds = new DiagnosticCollector<>(); + Collection sourceFiles = sources; + + try (FileManager fileManager = new FileManager(compiler.getStandardFileManager(ds, null, null))) { + JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, sourceFiles); + if (task.call()) { + return fileManager.getCompiledClasses(); + } else { + for (Diagnostic d : ds.getDiagnostics()) { + System.out.format("Line: %d, %s in %s", d.getLineNumber(), d.getMessage(null), d.getSource().getName()); + } + throw new InternalError("compilation failure"); + } + } catch (IOException e) { + throw new InternalError(e); + } + } + + List sources; + + static final String imports = """ + import java.lang.*; + import java.util.*; + """; + + static final String testClassBody = """ + // Some comments + static long x; + static final long y; + static { + y = System.currentTimeMillis(); + } + /* More comments */ + @Deprecated + String func() { return "String " + this + y; } + public static void main(String args[]) { + try { + x = Long.parseLong(args[0]); + } catch (Throwable t) { + t.printStackTrace(); + } + doit(() -> { + System.out.println("Hello Lambda"); + Thread.dumpStack(); + }); + } + static List list = List.of("1", "2"); + class InnerClass1 { + static final long yy = y; + } + static void doit(Runnable r) { + for (var x : list) { + r.run(); + } + } + static String patternMatch(String arg, Object o) { + if (o instanceof String s) { + return "1234"; + } + final String b = "B"; + return switch (arg) { + case "A" -> "a"; + case b -> "b"; + default -> "c"; + }; + } + public sealed class SealedInnerClass {} + public final class Foo extends SealedInnerClass {} + enum Expression { + ADDITION, + SUBTRACTION, + MULTIPLICATION, + DIVISION + } + public record Point(int x, int y) { + public Point(int x) { + this(x, 0); + } + } + """; + + String sanitySource = """ + public class Sanity implements java.util.concurrent.Callable { + public String call() { + return "this is a test"; + } + } + """; + + void setup(int count) { + sources = new ArrayList<>(count); + for (int i = 0; i < count; i++) { + String source = imports + "public class Test" + i + " {" + testClassBody + "}"; + sources.add(new SourceFile("Test" + i, source)); + } + + sources.add(new SourceFile("Sanity", sanitySource)); + } + + @SuppressWarnings("unchecked") + static void validate(byte[] sanityClassFile) throws Throwable { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Class cls = lookup.defineClass(sanityClassFile); + Callable obj = (Callable)cls.getDeclaredConstructor().newInstance(); + String s = obj.call(); + if (!s.equals("this is a test")) { + throw new RuntimeException("Expected \"this is a test\", but got \"" + s + "\""); + } + } + + public static void main(String args[]) throws Throwable { + long started = System.currentTimeMillis(); + JavacBenchApp bench = new JavacBenchApp(); + + int count = 0; + if (args.length > 0) { + count = Integer.parseInt(args[0]); + if (count >= 0) { + bench.setup(count); + Map allClasses = bench.compile(); + validate(allClasses.get("Sanity")); + } + } + if (System.getProperty("JavacBenchApp.silent") == null) { + // Set this property when running with "perf stat", etc + long elapsed = System.currentTimeMillis() - started; + System.out.println("Generated source code for " + bench.sources.size() + " classes and compiled them in " + elapsed + " ms"); + } + } +} + diff --git a/test/lib/jdk/test/lib/StringArrayUtils.java b/test/lib/jdk/test/lib/StringArrayUtils.java new file mode 100644 index 00000000000..11124701dce --- /dev/null +++ b/test/lib/jdk/test/lib/StringArrayUtils.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package jdk.test.lib; + +import java.util.ArrayList; + +public class StringArrayUtils { + /** + * The various concat() functions in this class can be used for building + * a command-line argument array for ProcessTools.createTestJavaProcessBuilder(), + * etc. When some of the arguments are conditional, this is more convenient + * than alternatives like ArrayList. + * + * Example: + * + *

+     *     String args[] = StringArrayUtils.concat("-Xint", "-Xmx32m");
+     *     if (verbose) {
+     *         args = StringArrayUtils.concat(args, "-verbose");
+     *     }
+     *     args = StringArrayUtils.concat(args, "HelloWorld");
+     *     ProcessTools.createTestJavaProcessBuilder(args);
+     * 
+ */ + public static String[] concat(String... args) { + return args; + } + + public static String[] concat(String[] prefix, String... extra) { + String[] ret = new String[prefix.length + extra.length]; + System.arraycopy(prefix, 0, ret, 0, prefix.length); + System.arraycopy(extra, 0, ret, prefix.length, extra.length); + return ret; + } + + public static String[] concat(String prefix, String[] extra) { + String[] ret = new String[1 + extra.length]; + ret[0] = prefix; + System.arraycopy(extra, 0, ret, 1, extra.length); + return ret; + } +} diff --git a/test/lib/jdk/test/lib/cds/CDSAppTester.java b/test/lib/jdk/test/lib/cds/CDSAppTester.java new file mode 100644 index 00000000000..c39e6bb8e94 --- /dev/null +++ b/test/lib/jdk/test/lib/cds/CDSAppTester.java @@ -0,0 +1,240 @@ +/* + * 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. + */ + +package jdk.test.lib.cds; + +import java.io.File; +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.StringArrayUtils; + +/* + * This is a base class used for testing CDS functionalities with complex applications. + * You can define the application by overridding the vmArgs(), classpath() and appCommandLine() + * methods. Application-specific validation checks can be implemented with checkExecution(). +*/ +abstract public class CDSAppTester { + private final String name; + private final String classListFile; + private final String classListFileLog; + private final String staticArchiveFile; + private final String staticArchiveFileLog; + private final String dynamicArchiveFile; + private final String dynamicArchiveFileLog; + private final String productionRunLog; + + public CDSAppTester(String name) { + // Old workflow + this.name = name; + classListFile = name() + ".classlist"; + classListFileLog = classListFile + ".log"; + staticArchiveFile = name() + ".static.jsa"; + staticArchiveFileLog = staticArchiveFile + ".log"; + dynamicArchiveFile = name() + ".dynamic.jsa"; + dynamicArchiveFileLog = dynamicArchiveFile + ".log"; + productionRunLog = name() + ".production.log"; + } + + private enum Workflow { + STATIC, // classic -Xshare:dump workflow + DYNAMIC, // classic -XX:ArchiveClassesAtExit + } + + public enum RunMode { + CLASSLIST, + DUMP_STATIC, + DUMP_DYNAMIC, + PRODUCTION; + + public boolean isStaticDump() { + return this == DUMP_STATIC; + } + public boolean isProductionRun() { + return this == PRODUCTION; + } + } + + public final String name() { + return this.name; + } + + // optional + public String[] vmArgs(RunMode runMode) { + return new String[0]; + } + + // optional + public String classpath(RunMode runMode) { + return null; + } + + // must override + // main class, followed by arguments to the main class + abstract public String[] appCommandLine(RunMode runMode); + + // optional + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {} + + private Workflow workflow; + + public final boolean isStaticWorkflow() { + return workflow == Workflow.STATIC; + } + + public final boolean isDynamicWorkflow() { + return workflow == Workflow.DYNAMIC; + } + + private String logToFile(String logFile, String... logTags) { + StringBuilder sb = new StringBuilder("-Xlog:"); + String prefix = ""; + for (String tag : logTags) { + sb.append(prefix); + sb.append(tag); + prefix = ","; + } + sb.append(":file=" + logFile + "::filesize=0"); + return sb.toString(); + } + + private void listOutputFile(String file) { + File f = new File(file); + if (f.exists()) { + System.out.println("[output file: " + file + " " + f.length() + " bytes]"); + } else { + System.out.println("[output file: " + file + " does not exist]"); + } + } + + private OutputAnalyzer executeAndCheck(String[] cmdLine, RunMode runMode, String... logFiles) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(cmdLine); + Process process = pb.start(); + OutputAnalyzer output = CDSTestUtils.executeAndLog(process, runMode.toString()); + for (String logFile : logFiles) { + listOutputFile(logFile); + } + output.shouldHaveExitValue(0); + CDSTestUtils.checkCommonExecExceptions(output); + checkExecution(output, runMode); + return output; + } + + private OutputAnalyzer createClassList() throws Exception { + RunMode runMode = RunMode.CLASSLIST; + String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-Xshare:off", + "-XX:DumpLoadedClassList=" + classListFile, + "-cp", classpath(runMode), + logToFile(classListFileLog, + "class+load=debug")); + cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); + return executeAndCheck(cmdLine, runMode, classListFile, classListFileLog); + } + + private OutputAnalyzer dumpStaticArchive() throws Exception { + RunMode runMode = RunMode.DUMP_STATIC; + String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-Xlog:cds", + "-Xlog:cds+heap=error", + "-Xshare:dump", + "-XX:SharedArchiveFile=" + staticArchiveFile, + "-XX:SharedClassListFile=" + classListFile, + "-cp", classpath(runMode), + logToFile(staticArchiveFileLog, + "cds=debug", + "cds+class=debug", + "cds+heap=warning", + "cds+resolve=debug")); + return executeAndCheck(cmdLine, runMode, staticArchiveFile, staticArchiveFileLog); + } + + private OutputAnalyzer dumpDynamicArchive() throws Exception { + RunMode runMode = RunMode.DUMP_DYNAMIC; + String[] cmdLine = new String[0]; + if (isDynamicWorkflow()) { + // "classic" dynamic archive + cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-Xlog:cds", + "-XX:ArchiveClassesAtExit=" + dynamicArchiveFile, + "-cp", classpath(runMode), + logToFile(dynamicArchiveFileLog, + "cds=debug", + "cds+class=debug", + "cds+resolve=debug", + "class+load=debug")); + } + cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); + return executeAndCheck(cmdLine, runMode, dynamicArchiveFile, dynamicArchiveFileLog); + } + + private OutputAnalyzer productionRun() throws Exception { + RunMode runMode = RunMode.PRODUCTION; + String[] cmdLine = StringArrayUtils.concat(vmArgs(runMode), + "-cp", classpath(runMode), + logToFile(productionRunLog, "cds")); + + if (isStaticWorkflow()) { + cmdLine = StringArrayUtils.concat(cmdLine, "-XX:SharedArchiveFile=" + staticArchiveFile); + } else if (isDynamicWorkflow()) { + cmdLine = StringArrayUtils.concat(cmdLine, "-XX:SharedArchiveFile=" + dynamicArchiveFile); + } + + cmdLine = StringArrayUtils.concat(cmdLine, appCommandLine(runMode)); + return executeAndCheck(cmdLine, runMode, productionRunLog); + } + + public void run(String args[]) throws Exception { + String err = "Must have exactly one command line argument of the following: "; + String prefix = ""; + for (Workflow wf : Workflow.values()) { + err += prefix; + err += wf; + prefix = ", "; + } + if (args.length != 1) { + throw new RuntimeException(err); + } else { + if (args[0].equals("STATIC")) { + runStaticWorkflow(); + } else if (args[0].equals("DYNAMIC")) { + runDynamicWorkflow(); + } else { + throw new RuntimeException(err); + } + } + } + + private void runStaticWorkflow() throws Exception { + this.workflow = Workflow.STATIC; + createClassList(); + dumpStaticArchive(); + productionRun(); + } + + private void runDynamicWorkflow() throws Exception { + this.workflow = Workflow.DYNAMIC; + dumpDynamicArchive(); + productionRun(); + } +} From c9a7b9772d96d9a4825d9da2aacc277534282860 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 23 May 2024 16:37:01 +0000 Subject: [PATCH 16/99] 8332829: [BACKOUT] C2: crash in compiled code because of dependency on removed range check CastIIs Reviewed-by: thartmann --- src/hotspot/share/opto/castnode.cpp | 19 +- src/hotspot/share/opto/compile.cpp | 50 +- src/hotspot/share/opto/compile.hpp | 3 - src/hotspot/share/opto/node.cpp | 12 - src/hotspot/share/opto/node.hpp | 7 - ...yAccessAboveRCAfterRCCastIIEliminated.java | 474 ------------------ 6 files changed, 26 insertions(+), 539 deletions(-) delete mode 100644 test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp index 1771107c851..a93c9b382f9 100644 --- a/src/hotspot/share/opto/castnode.cpp +++ b/src/hotspot/share/opto/castnode.cpp @@ -213,7 +213,13 @@ const Type* CastIINode::Value(PhaseGVN* phase) const { // Similar to ConvI2LNode::Value() for the same reasons // see if we can remove type assertion after loop opts - res = widen_type(phase, res, T_INT); + // But here we have to pay extra attention: + // Do not narrow the type of range check dependent CastIINodes to + // avoid corruption of the graph if a CastII is replaced by TOP but + // the corresponding range check is not removed. + if (!_range_check_dependency) { + res = widen_type(phase, res, T_INT); + } return res; } @@ -233,11 +239,11 @@ Node *CastIINode::Ideal(PhaseGVN *phase, bool can_reshape) { if (progress != nullptr) { return progress; } - if (can_reshape && !phase->C->post_loop_opts_phase()) { + if (can_reshape && !_range_check_dependency && !phase->C->post_loop_opts_phase()) { // makes sure we run ::Value to potentially remove type assertion after loop opts phase->C->record_for_post_loop_opts_igvn(this); } - if (!_type->is_int()->empty()) { + if (!_range_check_dependency) { return optimize_integer_cast(phase, T_INT); } return nullptr; @@ -248,6 +254,13 @@ Node* CastIINode::Identity(PhaseGVN* phase) { if (progress != this) { return progress; } + if (_range_check_dependency) { + if (phase->C->post_loop_opts_phase()) { + return this->in(1); + } else { + phase->C->record_for_post_loop_opts_igvn(this); + } + } return this; } diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 445f22c6b80..25c7ced8aeb 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -3464,10 +3464,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f } break; } - case Op_CastII: { - remove_range_check_cast(n->as_CastII()); - } - break; #ifdef _LP64 case Op_CmpP: // Do this transformation here to preserve CmpPNode::sub() and @@ -3619,6 +3615,16 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f #endif +#ifdef ASSERT + case Op_CastII: + // Verify that all range check dependent CastII nodes were removed. + if (n->isa_CastII()->has_range_check()) { + n->dump(3); + assert(false, "Range check dependent CastII node was not removed"); + } + break; +#endif + case Op_ModI: if (UseDivMod) { // Check if a%b and a/b both exist @@ -3627,8 +3633,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f // Replace them with a fused divmod if supported if (Matcher::has_match_rule(Op_DivModI)) { DivModINode* divmod = DivModINode::make(n); - divmod->add_prec_from(n); - divmod->add_prec_from(d); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -3649,8 +3653,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f // Replace them with a fused divmod if supported if (Matcher::has_match_rule(Op_DivModL)) { DivModLNode* divmod = DivModLNode::make(n); - divmod->add_prec_from(n); - divmod->add_prec_from(d); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -3671,8 +3673,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f // Replace them with a fused unsigned divmod if supported if (Matcher::has_match_rule(Op_UDivModI)) { UDivModINode* divmod = UDivModINode::make(n); - divmod->add_prec_from(n); - divmod->add_prec_from(d); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -3693,8 +3693,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f // Replace them with a fused unsigned divmod if supported if (Matcher::has_match_rule(Op_UDivModL)) { UDivModLNode* divmod = UDivModLNode::make(n); - divmod->add_prec_from(n); - divmod->add_prec_from(d); d->subsume_by(divmod->div_proj(), this); n->subsume_by(divmod->mod_proj(), this); } else { @@ -3896,34 +3894,6 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f } } -void Compile::remove_range_check_cast(CastIINode* cast) { - if (cast->has_range_check()) { - // Range check CastII nodes feed into an address computation subgraph. Remove them to let that subgraph float freely. - // For memory access or integer divisions nodes that depend on the cast, record the dependency on the cast's control - // as a precedence edge, so they can't float above the cast in case that cast's narrowed type helped eliminate a - // range check or a null divisor check. - assert(cast->in(0) != nullptr, "All RangeCheck CastII must have a control dependency"); - ResourceMark rm; - Unique_Node_List wq; - wq.push(cast); - for (uint next = 0; next < wq.size(); ++next) { - Node* m = wq.at(next); - for (DUIterator_Fast imax, i = m->fast_outs(imax); i < imax; i++) { - Node* use = m->fast_out(i); - if (use->is_Mem() || use->is_div_or_mod(T_INT) || use->is_div_or_mod(T_LONG)) { - use->ensure_control_or_add_prec(cast->in(0)); - } else if (!use->is_CFG() && !use->is_Phi()) { - wq.push(use); - } - } - } - cast->subsume_by(cast->in(1), this); - if (cast->outcnt() == 0) { - cast->disconnect_inputs(this); - } - } -} - //------------------------------final_graph_reshaping_walk--------------------- // Replacing Opaque nodes with their input in final_graph_reshaping_impl(), // requires that the walk visits a node's inputs before visiting the node. diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 9a873b8b9cb..e1d9b61f7f8 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -53,7 +53,6 @@ class Block; class Bundle; class CallGenerator; class CallStaticJavaNode; -class CastIINode; class CloneMap; class CompilationFailureInfo; class ConnectionGraph; @@ -1315,8 +1314,6 @@ class Compile : public Phase { BasicType out_bt, BasicType in_bt); static Node* narrow_value(BasicType bt, Node* value, const Type* type, PhaseGVN* phase, bool transform_res); - - void remove_range_check_cast(CastIINode* cast); }; #endif // SHARE_OPTO_COMPILE_HPP diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index cadea46e2c9..fa85344d0da 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -2878,15 +2878,6 @@ void Node::ensure_control_or_add_prec(Node* c) { } } -void Node::add_prec_from(Node* n) { - for (uint i = n->req(); i < n->len(); i++) { - Node* prec = n->in(i); - if (prec != nullptr) { - add_prec(prec); - } - } -} - bool Node::is_dead_loop_safe() const { if (is_Phi()) { return true; @@ -2910,9 +2901,6 @@ bool Node::is_dead_loop_safe() const { return false; } -bool Node::is_div_or_mod(BasicType bt) const { return Opcode() == Op_Div(bt) || Opcode() == Op_Mod(bt) || - Opcode() == Op_UDiv(bt) || Opcode() == Op_UMod(bt); } - //============================================================================= //------------------------------yank------------------------------------------- // Find and remove diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 412e193a612..04631dcbae2 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1143,7 +1143,6 @@ class Node { // Set control or add control as precedence edge void ensure_control_or_add_prec(Node* c); - void add_prec_from(Node* n); // Visit boundary uses of the node and apply a callback function for each. // Recursively traverse uses, stopping and applying the callback when @@ -1255,8 +1254,6 @@ class Node { // Whether this is a memory phi node bool is_memory_phi() const { return is_Phi() && bottom_type() == Type::MEMORY; } - bool is_div_or_mod(BasicType bt) const; - //----------------- Printing, etc #ifndef PRODUCT public: @@ -2026,10 +2023,6 @@ Op_IL(URShift) Op_IL(LShift) Op_IL(Xor) Op_IL(Cmp) -Op_IL(Div) -Op_IL(Mod) -Op_IL(UDiv) -Op_IL(UMod) inline int Op_ConIL(BasicType bt) { assert(bt == T_INT || bt == T_LONG, "only for int or longs"); diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java b/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java deleted file mode 100644 index 7f22db08a36..00000000000 --- a/test/hotspot/jtreg/compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright (c) 2024, Red Hat, Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 8324517 - * @summary C2: out of bound array load because of dependency on removed range check CastIIs - * - * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation - * -XX:CompileCommand=dontinline,TestArrayAccessAboveRCAfterRCCastIIEliminated::notInlined - * TestArrayAccessAboveRCAfterRCCastIIEliminated - * @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation - * -XX:CompileCommand=dontinline,TestArrayAccessAboveRCAfterRCCastIIEliminated::notInlined - * -XX:+UnlockDiagnosticVMOptions -XX:+StressGCM TestArrayAccessAboveRCAfterRCCastIIEliminated - * @run main/othervm TestArrayAccessAboveRCAfterRCCastIIEliminated - * @run main/othervm -XX:CompileCommand=dontinline,TestArrayAccessAboveRCAfterRCCastIIEliminated::notInlined - * TestArrayAccessAboveRCAfterRCCastIIEliminated - * - */ - -public class TestArrayAccessAboveRCAfterRCCastIIEliminated { - private static int intField; - private static long longField; - private static volatile int volatileField; - - public static void main(String[] args) { - int[] array = new int[100]; - for (int i = 0; i < 20_000; i++) { - test1(9, 10, 1, true); - test1(9, 10, 1, false); - test2(9, 10, 1, true); - test2(9, 10, 1, false); - test3(9, 10, 1, true); - test3(9, 10, 1, false); - test4(9, 10, 1, true); - test4(9, 10, 1, false); - test5(9, 10, 1, true); - test5(9, 10, 1, false); - test6(9, 10, 1, true); - test6(9, 10, 1, false); - test7(9, 10, 1, true); - test7(9, 10, 1, false); - test8(9, 10, 1, true); - test8(9, 10, 1, false); - test9(9, 10, 1, true); - test9(9, 10, 1, false); - test10(9, 10, 1, true); - test10(9, 10, 1, false); - test11(9, 10, 1, true); - test11(9, 10, 1, false); - test12(9, 10, 1, true); - test12(9, 10, 1, false); - test13(9, 10, 1, true); - test13(9, 10, 1, false); - } - try { - test1(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test2(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test3(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test4(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test5(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test6(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test7(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test8(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test9(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test10(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test11(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test12(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - try { - test13(-1, 10, 1, true); - } catch (ArrayIndexOutOfBoundsException arrayIndexOutOfBoundsException) { - } - } - - private static void test1(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = array[otherArray.length]; - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = array[otherArray.length]; - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test2(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 / (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 / (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test3(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L / (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L / (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test4(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 % (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 % (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test5(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L % (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L % (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test6(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 % (otherArray.length + 1) + 1 / (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = 1 % (otherArray.length + 1) + 1 / (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test7(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L % (otherArray.length + 1) + 1L / (otherArray.length + 1); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = 1L % (otherArray.length + 1) + 1L / (otherArray.length + 1); - } - for (int k = 0; k < 10; k++) { - - } - } - private static void test8(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.divideUnsigned(1, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.divideUnsigned(1, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test9(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.divideUnsigned(1L, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.divideUnsigned(1L, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test10(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.remainderUnsigned(1, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.remainderUnsigned(1, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test11(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.remainderUnsigned(1L, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.remainderUnsigned(1L, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test12(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.divideUnsigned(1, (otherArray.length + 1)) + - Integer.remainderUnsigned(1, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - intField = Integer.divideUnsigned(1, (otherArray.length + 1)) + - Integer.remainderUnsigned(1, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void test13(int i, int j, int flag, boolean flag2) { - i = Math.min(i, 9); - int[] array = new int[10]; - notInlined(array); - if (flag == 0) { - } - if (flag2) { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.remainderUnsigned(1L, (otherArray.length + 1)) + - Long.divideUnsigned(1L, (otherArray.length + 1)); - } else { - float[] newArray = new float[j]; - newArray[i] = 42; - float[] otherArray = new float[i]; - if (flag == 0) { - } - longField = Long.remainderUnsigned(1L, (otherArray.length + 1)) + - Long.divideUnsigned(1L, (otherArray.length + 1)); - } - for (int k = 0; k < 10; k++) { - - } - } - - private static void notInlined(int[] array) { - - } -} From 0a9d1f8c89e946d99f01549515f6044e53992168 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Thu, 23 May 2024 18:13:23 +0000 Subject: [PATCH 17/99] 8332749: Broken link in MemorySegment.Scope.html Reviewed-by: iris --- .../share/classes/java/lang/foreign/MemorySegment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 95195ef81bf..6c75c0385fa 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -2611,7 +2611,7 @@ static long mismatch(MemorySegment srcSegment, long srcFromOffset, long srcToOff *
  • Segments obtained from the {@linkplain Arena#global() global arena};
  • *
  • Segments obtained from a raw address, using the * {@link MemorySegment#ofAddress(long)} factory; and
  • - *
  • Zero-length memory segments.
  • + *
  • {@link MemorySegment##wrapping-addresses Zero-length memory segments}.
  • * *

    * Conversely, a bounded lifetime is modeled with a segment scope that can be From ddd73b458355bffeaa8e0e5017c27d6c6af2dc94 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Thu, 23 May 2024 22:33:24 +0000 Subject: [PATCH 18/99] 8332082: Shenandoah: Use consistent tests to determine when pre-write barrier is active Reviewed-by: kdnilsen, shade --- .../shenandoahBarrierSetAssembler_aarch64.cpp | 11 ++---- .../shenandoahBarrierSetAssembler_riscv.cpp | 12 ++---- .../shenandoahBarrierSetAssembler_x86.cpp | 1 - .../shenandoah/c1/shenandoahBarrierSetC1.cpp | 38 +++++++++++-------- .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 9 +++-- .../shenandoah/shenandoahThreadLocalData.hpp | 4 -- 6 files changed, 35 insertions(+), 40 deletions(-) diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index fe4df9b8c0d..5db29729239 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -109,18 +109,13 @@ void ShenandoahBarrierSetAssembler::satb_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(ShenandoahThreadLocalData::satb_mark_queue_active_offset())); Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); Address buffer(thread, in_bytes(ShenandoahThreadLocalData::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); - } - __ cbzw(tmp1, done); + Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); + __ ldrb(tmp1, gc_state); + __ tbz(tmp1, ShenandoahHeap::MARKING_BITPOS, done); // Do we need to load the previous value? if (obj != noreg) { diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp index a93bf5394ce..9be8259e7e8 100644 --- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp @@ -112,18 +112,14 @@ void ShenandoahBarrierSetAssembler::satb_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(ShenandoahThreadLocalData::satb_mark_queue_active_offset())); Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_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); - } - __ beqz(tmp1, done); + Address gc_state(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); + __ lbu(t1, gc_state); + __ test_bit(t1, t1, ShenandoahHeap::MARKING_BITPOS); + __ beqz(t1, done); // Do we need to load the previous value? if (obj != noreg) { diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 573edc26dad..25a2b931468 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -219,7 +219,6 @@ void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, assert(pre_val != rax, "check this code"); } - Address in_progress(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset())); Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset())); diff --git a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp index 1131945dc8c..30bf1f7a395 100644 --- a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp +++ b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp @@ -58,26 +58,32 @@ ShenandoahBarrierSetC1::ShenandoahBarrierSetC1() : void ShenandoahBarrierSetC1::pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val) { // First we test whether marking is in progress. - BasicType flag_type; + bool patch = (decorators & C1_NEEDS_PATCHING) != 0; bool do_load = pre_val == LIR_OprFact::illegalOpr; - if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { - flag_type = T_INT; - } else { - guarantee(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, - "Assumption"); - // Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM, - // need to use unsigned instructions to use the large offset to load the satb_mark_queue. - flag_type = T_BOOLEAN; - } + LIR_Opr thrd = gen->getThreadPointer(); - LIR_Address* mark_active_flag_addr = - new LIR_Address(thrd, - in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()), - flag_type); - // Read the marking-in-progress flag. + LIR_Address* gc_state_addr = + new LIR_Address(thrd, + in_bytes(ShenandoahThreadLocalData::gc_state_offset()), + T_BYTE); + // Read the gc_state flag. LIR_Opr flag_val = gen->new_register(T_INT); - __ load(mark_active_flag_addr, flag_val); + __ load(gc_state_addr, flag_val); + + // Create a mask to test if the marking bit is set. + // TODO: can we directly test if bit is set? + LIR_Opr mask = LIR_OprFact::intConst(ShenandoahHeap::MARKING); + LIR_Opr mask_reg = gen->new_register(T_INT); + __ move(mask, mask_reg); + + if (two_operand_lir_form) { + __ logical_and(flag_val, mask_reg, flag_val); + } else { + LIR_Opr masked_flag = gen->new_register(T_INT); + __ logical_and(flag_val, mask_reg, masked_flag); + flag_val = masked_flag; + } __ cmp(lir_cond_notEqual, flag_val, LIR_OprFact::intConst(0)); LIR_PatchCode pre_val_patch_code = lir_patch_none; diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index f34b1cae8fb..7d1f5cc16a8 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -980,7 +980,7 @@ void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase p ShenandoahBarrierC2Support::verify(Compile::current()->root()); } else if (phase == BarrierSetC2::BeforeCodeGen) { // Verify Shenandoah pre-barriers - const int marking_offset = in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset()); + const int gc_state_offset = in_bytes(ShenandoahThreadLocalData::gc_state_offset()); Unique_Node_List visited; Node_List worklist; @@ -988,7 +988,10 @@ void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase p worklist.push(compile->root()); while (worklist.size() > 0) { Node *x = worklist.pop(); - if (x == nullptr || x == compile->top()) continue; + if (x == nullptr || x == compile->top()) { + continue; + } + if (visited.member(x)) { continue; } else { @@ -1016,7 +1019,7 @@ void ShenandoahBarrierSetC2::verify_gc_barriers(Compile* compile, CompilePhase p 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) { + && load->in(2)->in(3)->bottom_type()->is_intptr_t()->get_con() == gc_state_offset) { Node *if_ctrl = iff->in(0); Node *load_ctrl = load->in(0); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp index 9eec573cc56..91f1cfe7f56 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp @@ -158,10 +158,6 @@ class ShenandoahThreadLocalData { } // Offsets - static ByteSize satb_mark_queue_active_offset() { - return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_active(); - } - static ByteSize satb_mark_queue_index_offset() { return satb_mark_queue_offset() + SATBMarkQueue::byte_offset_of_index(); } From f8a3e4e428f7d3e62177bdf148fe25e22d3ee2bf Mon Sep 17 00:00:00 2001 From: steveatgh Date: Thu, 23 May 2024 22:54:24 +0000 Subject: [PATCH 19/99] 8328998: Encoding support for Intel APX extended general-purpose registers Reviewed-by: kvn, sviswanathan, jbhateja --- src/hotspot/cpu/x86/assembler_x86.cpp | 1171 +++++++++++------- src/hotspot/cpu/x86/assembler_x86.hpp | 114 +- src/hotspot/cpu/x86/assembler_x86.inline.hpp | 44 +- src/hotspot/cpu/x86/globals_x86.hpp | 6 +- src/hotspot/cpu/x86/vm_version_x86.cpp | 8 + 5 files changed, 888 insertions(+), 455 deletions(-) diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index bcf4d5ea13b..ee9e2064941 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -76,7 +76,8 @@ static const unsigned char tuple_table[Assembler::EVEX_ETUP + 1][Assembler::AVX_ 2, 4, 8, // EVEX_OVM(0) 16, 16, 16, // EVEX_M128(0) 8, 32, 64, // EVEX_DUP(0) - 0, 0, 0 // EVEX_NTUP + 1, 1, 1, // EVEX_NOSCALE(0) + 0, 0, 0 // EVEX_ETUP }; AddressLiteral::AddressLiteral(address target, relocInfo::relocType rtype) { @@ -294,11 +295,7 @@ void Assembler::emit_data(jint data, RelocationHolder const& rspec, int format) } static int encode(Register r) { - int enc = r->encoding(); - if (enc >= 8) { - enc -= 8; - } - return enc; + return r->encoding() & 7; } void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) { @@ -438,6 +435,9 @@ bool Assembler::query_compressed_disp_byte(int disp, bool is_evex_inst, int vect case EVEX_DUP: break; + case EVEX_NOSCALE: + break; + default: assert(0, "no valid evex tuple_table entry"); break; @@ -525,6 +525,9 @@ bool Assembler::emit_compressed_disp_byte(int &disp) { case EVEX_DUP: break; + case EVEX_NOSCALE: + break; + default: assert(0, "no valid evex tuple_table entry"); break; @@ -546,6 +549,24 @@ bool Assembler::emit_compressed_disp_byte(int &disp) { return is8bit(disp); } +bool Assembler::needs_rex2(Register reg1, Register reg2, Register reg3) { + bool rex2 = (reg1->is_valid() && reg1->encoding() >= 16) || + (reg2->is_valid() && reg2->encoding() >= 16) || + (reg3->is_valid() && reg3->encoding() >= 16); + assert(!rex2 || UseAPX, "extended gpr use requires UseAPX"); + return rex2; +} + +bool Assembler::needs_eevex(Register reg1, Register reg2, Register reg3) { + return needs_rex2(reg1, reg2, reg3); +} + +bool Assembler::needs_eevex(int enc1, int enc2, int enc3) { + bool eevex = enc1 >= 16 || enc2 >= 16 || enc3 >=16; + assert(!eevex || UseAPX, "extended gpr use requires UseAPX"); + return eevex; +} + static bool is_valid_encoding(int reg_enc) { return reg_enc >= 0; } @@ -616,9 +637,9 @@ void Assembler::emit_operand_helper(int reg_enc, int base_enc, int index_enc, if (is_valid_encoding(index_enc)) { assert(scale != Address::no_scale, "inconsistent address"); // [base + index*scale + disp] - if (disp == 0 && no_relocation && - base_enc != rbp->encoding() LP64_ONLY(&& base_enc != r13->encoding())) { + if (disp == 0 && no_relocation && ((base_enc & 0x7) != 5)) { // [base + index*scale] + // !(rbp | r13 | r21 | r29) // [00 reg 100][ss index base] emit_modrm_sib(0b00, reg_enc, 0b100, scale, index_enc, base_enc); @@ -635,7 +656,8 @@ void Assembler::emit_operand_helper(int reg_enc, int base_enc, int index_enc, scale, index_enc, base_enc); emit_data(disp, rspec, disp32_operand); } - } else if (base_enc == rsp->encoding() LP64_ONLY(|| base_enc == r12->encoding())) { + } else if ((base_enc & 0x7) == 4) { + // rsp | r12 | r20 | r28 // [rsp + disp] if (disp == 0 && no_relocation) { // [rsp] @@ -657,10 +679,11 @@ void Assembler::emit_operand_helper(int reg_enc, int base_enc, int index_enc, } } else { // [base + disp] - assert(base_enc != rsp->encoding() LP64_ONLY(&& base_enc != r12->encoding()), "illegal addressing mode"); - if (disp == 0 && no_relocation && - base_enc != rbp->encoding() LP64_ONLY(&& base_enc != r13->encoding())) { + // !(rsp | r12 | r20 | r28) were handled above + assert(((base_enc & 0x7) != 4), "illegal addressing mode"); + if (disp == 0 && no_relocation && ((base_enc & 0x7) != 5)) { // [base] + // !(rbp | r13 | r21 | r29) // [00 reg base] emit_modrm(0, reg_enc, base_enc); } else if (emit_compressed_disp_byte(disp) && no_relocation) { @@ -817,6 +840,13 @@ address Assembler::locate_operand(address inst, WhichOperand which) { NOT_LP64(assert(false, "64bit prefixes")); goto again_after_prefix; + case REX2: + NOT_LP64(assert(false, "64bit prefixes")); + if ((0xFF & *ip++) & REXBIT_W) { + is_64bit = true; + } + goto again_after_prefix; + case REX_W: case REX_WB: case REX_WX: @@ -866,6 +896,14 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case REX_WRXB: NOT_LP64(assert(false, "64bit prefix found")); goto again_after_size_prefix2; + + case REX2: + NOT_LP64(assert(false, "64bit prefix found")); + if ((0xFF & *ip++) & REXBIT_W) { + is_64bit = true; + } + goto again_after_size_prefix2; + case 0x8B: // movw r, a case 0x89: // movw a, r debug_only(has_disp32 = true); @@ -1155,6 +1193,7 @@ address Assembler::locate_operand(address inst, WhichOperand which) { case REX_WRB: case REX_WRX: case REX_WRXB: + case REX2: NOT_LP64(assert(false, "found 64bit prefix")); ip++; default: @@ -1281,6 +1320,33 @@ void Assembler::emit_operand(XMMRegister reg, Address adr, int post_addr_length) } } +void Assembler::emit_opcode_prefix_and_encoding(int byte1, int byte2, int ocp_and_encoding, int byte3) { + int opcode_prefix = (ocp_and_encoding & 0xFF00) >> 8; + if (opcode_prefix != 0) { + emit_int32(opcode_prefix, (unsigned char)byte1, byte2 | (ocp_and_encoding & 0xFF), byte3); + } else { + emit_int24((unsigned char)byte1, byte2 | (ocp_and_encoding & 0xFF), byte3); + } +} + +void Assembler::emit_opcode_prefix_and_encoding(int byte1, int byte2, int ocp_and_encoding) { + int opcode_prefix = (ocp_and_encoding & 0xFF00) >> 8; + if (opcode_prefix != 0) { + emit_int24(opcode_prefix, (unsigned char)byte1, byte2 | (ocp_and_encoding & 0xFF)); + } else { + emit_int16((unsigned char)byte1, byte2 | (ocp_and_encoding & 0xFF)); + } +} + +void Assembler::emit_opcode_prefix_and_encoding(int byte1, int ocp_and_encoding) { + int opcode_prefix = (ocp_and_encoding & 0xFF00) >> 8; + if (opcode_prefix != 0) { + emit_int16(opcode_prefix, (unsigned char)byte1 | (ocp_and_encoding & 0xFF)); + } else { + emit_int8((unsigned char)byte1 | (ocp_and_encoding & 0xFF)); + } +} + // Now the Assembler instructions (identical for 32/64 bits) void Assembler::adcl(Address dst, int32_t imm32) { @@ -1603,50 +1669,48 @@ void Assembler::andl(Register dst, Register src) { void Assembler::andnl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF2, (0xC0 | encode)); } void Assembler::andnl(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF2); emit_operand(dst, src2, 0); } void Assembler::bsfl(Register dst, Register src) { - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, - (unsigned char)0xBC, - 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode); } void Assembler::bsrl(Register dst, Register src) { - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, - (unsigned char)0xBD, - 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBD, 0xC0, encode); } void Assembler::bswapl(Register reg) { // bswap - int encode = prefix_and_encode(reg->encoding()); - emit_int16(0x0F, (0xC8 | encode)); + int encode = prefix_and_encode(reg->encoding(), false, true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xC8, encode); } void Assembler::blsil(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsil(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, dst->encoding(), rbx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rbx, src, 0); @@ -1654,8 +1718,8 @@ void Assembler::blsil(Register dst, Address src) { void Assembler::blsmskl(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, 0xC0 | encode); } @@ -1663,7 +1727,8 @@ void Assembler::blsmskl(Register dst, Register src) { void Assembler::blsmskl(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, dst->encoding(), rdx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rdx, src, 0); @@ -1671,15 +1736,16 @@ void Assembler::blsmskl(Register dst, Address src) { void Assembler::blsrl(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsrl(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, dst->encoding(), rcx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rcx, src, 0); @@ -1743,18 +1809,15 @@ void Assembler::cld() { void Assembler::cmovl(Condition cc, Register dst, Register src) { NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction")); - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, - 0x40 | cc, - 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding(0x40 | cc, 0xC0, encode); } - void Assembler::cmovl(Condition cc, Register dst, Address src) { InstructionMark im(this); NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction")); - prefix(src, dst); - emit_int16(0x0F, (0x40 | cc)); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((0x40 | cc)); emit_operand(dst, src, 0); } @@ -1840,16 +1903,16 @@ void Assembler::cmpw(Address dst, Register reg) { // The ZF is set if the compared values were equal, and cleared otherwise. void Assembler::cmpxchgl(Register reg, Address adr) { // cmpxchg InstructionMark im(this); - prefix(adr, reg); - emit_int16(0x0F, (unsigned char)0xB1); + prefix(adr, reg, false, true /* is_map1 */); + emit_int8((unsigned char)0xB1); emit_operand(reg, adr, 0); } void Assembler::cmpxchgw(Register reg, Address adr) { // cmpxchg InstructionMark im(this); size_prefix(); - prefix(adr, reg); - emit_int16(0x0F, (unsigned char)0xB1); + prefix(adr, reg, false, true /* is_map1 */); + emit_int8((unsigned char)0xB1); emit_operand(reg, adr, 0); } @@ -1858,8 +1921,8 @@ void Assembler::cmpxchgw(Register reg, Address adr) { // cmpxchg // The ZF is set if the compared values were equal, and cleared otherwise. void Assembler::cmpxchgb(Register reg, Address adr) { // cmpxchg InstructionMark im(this); - prefix(adr, reg, true); - emit_int16(0x0F, (unsigned char)0xB0); + prefix(adr, reg, true, true /* is_map1 */); + emit_int8((unsigned char)0xB0); emit_operand(reg, adr, 0); } @@ -1917,69 +1980,83 @@ void Assembler::cpuid() { // F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E. Accumulate CRC32 on r / m64. v void Assembler::crc32(Register crc, Register v, int8_t sizeInBytes) { assert(VM_Version::supports_sse4_2(), ""); - int8_t w = 0x01; - Prefix p = Prefix_EMPTY; + if (needs_eevex(crc, v)) { + InstructionAttr attributes(AVX_128bit, /* rex_w */ sizeInBytes == 8, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(crc->encoding(), 0, v->encoding(), sizeInBytes == 2 ? VEX_SIMD_66 : VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes, true); + emit_int16(sizeInBytes == 1 ? (unsigned char)0xF0 : (unsigned char)0xF1, (0xC0 | encode)); + } else { + int8_t w = 0x01; + Prefix p = Prefix_EMPTY; - emit_int8((unsigned char)0xF2); - switch (sizeInBytes) { - case 1: - w = 0; - break; - case 2: - case 4: - break; - LP64_ONLY(case 8:) - // This instruction is not valid in 32 bits - // Note: - // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf - // - // Page B - 72 Vol. 2C says - // qwreg2 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : 11 qwreg1 qwreg2 - // mem64 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : mod qwreg r / m - // F0!!! - // while 3 - 208 Vol. 2A - // F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E.Accumulate CRC32 on r / m64. - // - // the 0 on a last bit is reserved for a different flavor of this instruction : - // F2 REX.W 0F 38 F0 / r CRC32 r64, r / m8 RM Valid N.E.Accumulate CRC32 on r / m8. - p = REX_W; - break; - default: - assert(0, "Unsupported value for a sizeInBytes argument"); - break; + emit_int8((unsigned char)0xF2); + switch (sizeInBytes) { + case 1: + w = 0; + break; + case 2: + case 4: + break; + LP64_ONLY(case 8:) + // This instruction is not valid in 32 bits + // Note: + // http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf + // + // Page B - 72 Vol. 2C says + // qwreg2 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : 11 qwreg1 qwreg2 + // mem64 to qwreg 1111 0010 : 0100 1R0B : 0000 1111 : 0011 1000 : 1111 0000 : mod qwreg r / m + // F0!!! + // while 3 - 208 Vol. 2A + // F2 REX.W 0F 38 F1 / r CRC32 r64, r / m64 RM Valid N.E.Accumulate CRC32 on r / m64. + // + // the 0 on a last bit is reserved for a different flavor of this instruction : + // F2 REX.W 0F 38 F0 / r CRC32 r64, r / m8 RM Valid N.E.Accumulate CRC32 on r / m8. + p = REX_W; + break; + default: + assert(0, "Unsupported value for a sizeInBytes argument"); + break; + } + LP64_ONLY(prefix(crc, v, p);) + emit_int32(0x0F, + 0x38, + 0xF0 | w, + 0xC0 | ((crc->encoding() & 0x7) << 3) | (v->encoding() & 7)); } - LP64_ONLY(prefix(crc, v, p);) - emit_int32(0x0F, - 0x38, - 0xF0 | w, - 0xC0 | ((crc->encoding() & 0x7) << 3) | (v->encoding() & 7)); } void Assembler::crc32(Register crc, Address adr, int8_t sizeInBytes) { assert(VM_Version::supports_sse4_2(), ""); InstructionMark im(this); - int8_t w = 0x01; - Prefix p = Prefix_EMPTY; + if (needs_eevex(crc, adr.base(), adr.index())) { + InstructionAttr attributes(AVX_128bit, /* vex_w */ sizeInBytes == 8, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); + vex_prefix(adr, 0, crc->encoding(), sizeInBytes == 2 ? VEX_SIMD_66 : VEX_SIMD_NONE, VEX_OPCODE_0F_3C, &attributes); + emit_int8(sizeInBytes == 1 ? (unsigned char)0xF0 : (unsigned char)0xF1); + emit_operand(crc, adr, 0); + } else { + int8_t w = 0x01; + Prefix p = Prefix_EMPTY; - emit_int8((uint8_t)0xF2); - switch (sizeInBytes) { - case 1: - w = 0; - break; - case 2: - case 4: - break; - LP64_ONLY(case 8:) - // This instruction is not valid in 32 bits - p = REX_W; - break; - default: - assert(0, "Unsupported value for a sizeInBytes argument"); - break; + emit_int8((uint8_t)0xF2); + switch (sizeInBytes) { + case 1: + w = 0; + break; + case 2: + case 4: + break; + LP64_ONLY(case 8:) + // This instruction is not valid in 32 bits + p = REX_W; + break; + default: + assert(0, "Unsupported value for a sizeInBytes argument"); + break; + } + LP64_ONLY(prefix(crc, adr, p);) + emit_int24(0x0F, 0x38, (0xF0 | w)); + emit_operand(crc, adr, 0); } - LP64_ONLY(prefix(crc, adr, p);) - emit_int24(0x0F, 0x38, (0xF0 | w)); - emit_operand(crc, adr, 0); } void Assembler::cvtdq2pd(XMMRegister dst, XMMRegister src) { @@ -2081,7 +2158,7 @@ void Assembler::cvtsd2ss(XMMRegister dst, Address src) { void Assembler::cvtsi2sdl(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes, true); emit_int16(0x2A, (0xC0 | encode)); } @@ -2098,7 +2175,7 @@ void Assembler::cvtsi2sdl(XMMRegister dst, Address src) { void Assembler::cvtsi2ssl(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes, true); emit_int16(0x2A, (0xC0 | encode)); } @@ -2115,7 +2192,7 @@ void Assembler::cvtsi2ssl(XMMRegister dst, Address src) { void Assembler::cvtsi2ssq(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F3, VEX_OPCODE_0F, &attributes, true); emit_int16(0x2A, (0xC0 | encode)); } @@ -2418,10 +2495,8 @@ void Assembler::imull(Register src) { } void Assembler::imull(Register dst, Register src) { - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, - (unsigned char)0xAF, - (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xAF, 0xC0, encode); } void Assembler::imull(Register dst, Address src, int32_t value) { @@ -2450,8 +2525,8 @@ void Assembler::imull(Register dst, Register src, int value) { void Assembler::imull(Register dst, Address src) { InstructionMark im(this); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xAF); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xAF); emit_operand(dst, src, 0); } @@ -2587,7 +2662,10 @@ void Assembler::jmpb_0(Label& L, const char* file, int line) { } void Assembler::ldmxcsr( Address src) { - if (UseAVX > 0 ) { + // This instruction should be SSE encoded with the REX2 prefix when an + // extended GPR is present. To be consistent when UseAPX is enabled, use + // this encoding even when an extended GPR is not used. + if (UseAVX > 0 && !UseAPX ) { InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); vex_prefix(src, 0, 0, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); @@ -2596,8 +2674,8 @@ void Assembler::ldmxcsr( Address src) { } else { NOT_LP64(assert(VM_Version::supports_sse(), "")); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, (unsigned char)0xAE); + prefix(src, true /* is_map1 */); + emit_int8((unsigned char)0xAE); emit_operand(as_Register(2), src, 0); } } @@ -2624,16 +2702,16 @@ void Assembler::size_prefix() { void Assembler::lzcntl(Register dst, Register src) { assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR"); emit_int8((unsigned char)0xF3); - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBD, (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBD, 0xC0, encode); } void Assembler::lzcntl(Register dst, Address src) { assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR"); InstructionMark im(this); emit_int8((unsigned char)0xF3); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xBD); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xBD); emit_operand(dst, src, 0); } @@ -2725,28 +2803,28 @@ void Assembler::kmovbl(KRegister dst, KRegister src) { void Assembler::kmovbl(KRegister dst, Register src) { assert(VM_Version::supports_avx512dq(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16((unsigned char)0x92, (0xC0 | encode)); } void Assembler::kmovbl(Register dst, KRegister src) { assert(VM_Version::supports_avx512dq(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); emit_int16((unsigned char)0x93, (0xC0 | encode)); } void Assembler::kmovwl(KRegister dst, Register src) { assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes, true); emit_int16((unsigned char)0x92, (0xC0 | encode)); } void Assembler::kmovwl(Register dst, KRegister src) { assert(VM_Version::supports_evex(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int16((unsigned char)0x93, (0xC0 | encode)); } @@ -2754,7 +2832,8 @@ void Assembler::kmovwl(Register dst, KRegister src) { void Assembler::kmovwl(KRegister dst, Address src) { assert(VM_Version::supports_evex(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x90); emit_operand(dst, src, 0); @@ -2763,7 +2842,8 @@ void Assembler::kmovwl(KRegister dst, Address src) { void Assembler::kmovwl(Address dst, KRegister src) { assert(VM_Version::supports_evex(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x91); emit_operand(src, dst, 0); @@ -2778,14 +2858,14 @@ void Assembler::kmovwl(KRegister dst, KRegister src) { void Assembler::kmovdl(KRegister dst, Register src) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes, true); emit_int16((unsigned char)0x92, (0xC0 | encode)); } void Assembler::kmovdl(Register dst, KRegister src) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int16((unsigned char)0x93, (0xC0 | encode)); } @@ -2800,7 +2880,8 @@ void Assembler::kmovql(KRegister dst, KRegister src) { void Assembler::kmovql(KRegister dst, Address src) { assert(VM_Version::supports_avx512bw(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x90); emit_operand(dst, src, 0); @@ -2809,7 +2890,8 @@ void Assembler::kmovql(KRegister dst, Address src) { void Assembler::kmovql(Address dst, KRegister src) { assert(VM_Version::supports_avx512bw(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(dst, 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); emit_int8((unsigned char)0x91); emit_operand(src, dst, 0); @@ -2817,14 +2899,14 @@ void Assembler::kmovql(Address dst, KRegister src) { void Assembler::kmovql(KRegister dst, Register src) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes, true); emit_int16((unsigned char)0x92, (0xC0 | encode)); } void Assembler::kmovql(Register dst, KRegister src) { assert(VM_Version::supports_avx512bw(), ""); - InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int16((unsigned char)0x93, (0xC0 | encode)); } @@ -3105,7 +3187,7 @@ void Assembler::movb(Address dst, Register src) { void Assembler::movdl(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x6E, (0xC0 | encode)); } @@ -3113,7 +3195,7 @@ void Assembler::movdl(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // swap src/dst to get correct prefix - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x7E, (0xC0 | encode)); } @@ -3582,28 +3664,28 @@ void Assembler::movq(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // swap src/dst to get correct prefix - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x7E, (0xC0 | encode)); } void Assembler::movq(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x6E, (0xC0 | encode)); } void Assembler::movsbl(Register dst, Address src) { // movsxb InstructionMark im(this); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xBE); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xBE); emit_operand(dst, src, 0); } void Assembler::movsbl(Register dst, Register src) { // movsxb NOT_LP64(assert(src->has_byte_register(), "must have byte register")); - int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true); - emit_int24(0x0F, (unsigned char)0xBE, (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true, true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBE, 0xC0, encode); } void Assembler::movsd(XMMRegister dst, XMMRegister src) { @@ -3675,14 +3757,14 @@ void Assembler::movss(Address dst, XMMRegister src) { void Assembler::movswl(Register dst, Address src) { // movsxw InstructionMark im(this); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xBF); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xBF); emit_operand(dst, src, 0); } void Assembler::movswl(Register dst, Register src) { // movsxw - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBF, (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBF, 0xC0, encode); } void Assembler::movups(XMMRegister dst, Address src) { @@ -3753,27 +3835,27 @@ void Assembler::movw(Address dst, Register src) { void Assembler::movzbl(Register dst, Address src) { // movzxb InstructionMark im(this); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xB6); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xB6); emit_operand(dst, src, 0); } void Assembler::movzbl(Register dst, Register src) { // movzxb NOT_LP64(assert(src->has_byte_register(), "must have byte register")); - int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true); - emit_int24(0x0F, (unsigned char)0xB6, 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), false, src->encoding(), true, true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB6, 0xC0, encode); } void Assembler::movzwl(Register dst, Address src) { // movzxw InstructionMark im(this); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xB7); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xB7); emit_operand(dst, src, 0); } void Assembler::movzwl(Register dst, Register src) { // movzxw - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xB7, 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB7, 0xC0, encode); } void Assembler::mull(Address src) { @@ -4416,6 +4498,7 @@ void Assembler::ud2() { void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) { assert(VM_Version::supports_sse4_2(), ""); + assert(!needs_eevex(src.base(), src.index()), "does not support extended gprs"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); @@ -4743,7 +4826,7 @@ void Assembler::vmovmskpd(Register dst, XMMRegister src, int vec_enc) { void Assembler::pextrd(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x16, (0xC0 | encode), imm8); } @@ -4761,7 +4844,7 @@ void Assembler::pextrd(Address dst, XMMRegister src, int imm8) { void Assembler::pextrq(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x16, (0xC0 | encode), imm8); } @@ -4797,7 +4880,7 @@ void Assembler::pextrw(Address dst, XMMRegister src, int imm8) { void Assembler::pextrb(Register dst, XMMRegister src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x14, (0xC0 | encode), imm8); } @@ -4815,7 +4898,7 @@ void Assembler::pextrb(Address dst, XMMRegister src, int imm8) { void Assembler::pinsrd(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x22, (0xC0 | encode), imm8); } @@ -4833,14 +4916,14 @@ void Assembler::pinsrd(XMMRegister dst, Address src, int imm8) { void Assembler::vpinsrd(XMMRegister dst, XMMRegister nds, Register src, int imm8) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x22, (0xC0 | encode), imm8); } void Assembler::pinsrq(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x22, (0xC0 | encode), imm8); } @@ -4858,14 +4941,14 @@ void Assembler::pinsrq(XMMRegister dst, Address src, int imm8) { void Assembler::vpinsrq(XMMRegister dst, XMMRegister nds, Register src, int imm8) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x22, (0xC0 | encode), imm8); } void Assembler::pinsrw(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse2(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int24((unsigned char)0xC4, (0xC0 | encode), imm8); } @@ -4883,7 +4966,7 @@ void Assembler::pinsrw(XMMRegister dst, Address src, int imm8) { void Assembler::vpinsrw(XMMRegister dst, XMMRegister nds, Register src, int imm8) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int24((unsigned char)0xC4, (0xC0 | encode), imm8); } @@ -4901,14 +4984,14 @@ void Assembler::pinsrb(XMMRegister dst, Address src, int imm8) { void Assembler::pinsrb(XMMRegister dst, Register src, int imm8) { assert(VM_Version::supports_sse4_1(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x20, (0xC0 | encode), imm8); } void Assembler::vpinsrb(XMMRegister dst, XMMRegister nds, Register src, int imm8) { assert(VM_Version::supports_avx(), ""); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); emit_int24(0x20, (0xC0 | encode), imm8); } @@ -5311,16 +5394,16 @@ void Assembler::popcntl(Register dst, Address src) { assert(VM_Version::supports_popcnt(), "must support"); InstructionMark im(this); emit_int8((unsigned char)0xF3); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xB8); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xB8); emit_operand(dst, src, 0); } void Assembler::popcntl(Register dst, Register src) { assert(VM_Version::supports_popcnt(), "must support"); emit_int8((unsigned char)0xF3); - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xB8, (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB8, 0xC0, encode); } void Assembler::evpopcntb(XMMRegister dst, KRegister mask, XMMRegister src, bool merge, int vector_len) { @@ -5392,48 +5475,48 @@ void Assembler::popl(Address dst) { void Assembler::prefetchnta(Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "must support")); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x18); + prefix(src, true /* is_map1 */); + emit_int8(0x18); emit_operand(rax, src, 0); // 0, src } void Assembler::prefetchr(Address src) { assert(VM_Version::supports_3dnow_prefetch(), "must support"); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x0D); + prefix(src, true /* is_map1 */); + emit_int8(0x0D); emit_operand(rax, src, 0); // 0, src } void Assembler::prefetcht0(Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "must support")); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x18); + prefix(src, true /* is_map1 */); + emit_int8(0x18); emit_operand(rcx, src, 0); // 1, src } void Assembler::prefetcht1(Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "must support")); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x18); + prefix(src, true /* is_map1 */); + emit_int8(0x18); emit_operand(rdx, src, 0); // 2, src } void Assembler::prefetcht2(Address src) { NOT_LP64(assert(VM_Version::supports_sse(), "must support")); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x18); + prefix(src, true /* is_map1 */); + emit_int8(0x18); emit_operand(rbx, src, 0); // 3, src } void Assembler::prefetchw(Address src) { assert(VM_Version::supports_3dnow_prefetch(), "must support"); InstructionMark im(this); - prefix(src); - emit_int16(0x0F, 0x0D); + prefix(src, true /* is_map1 */); + emit_int8(0x0D); emit_operand(rcx, src, 0); // 1, src } @@ -5441,6 +5524,12 @@ void Assembler::prefix(Prefix p) { emit_int8(p); } +void Assembler::prefix16(int prefix) { + assert(UseAPX, "APX features not enabled"); + emit_int8((prefix & 0xff00) >> 8); + emit_int8(prefix & 0xff); +} + void Assembler::pshufb(XMMRegister dst, XMMRegister src) { assert(VM_Version::supports_ssse3(), ""); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); @@ -5648,6 +5737,7 @@ void Assembler::vpslldq(XMMRegister dst, XMMRegister src, int shift, int vector_ void Assembler::ptest(XMMRegister dst, Address src) { assert(VM_Version::supports_sse4_1(), ""); assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes"); + assert(!needs_eevex(src.base(), src.index()), "does not support extended gprs"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); simd_prefix(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); @@ -5665,6 +5755,7 @@ void Assembler::ptest(XMMRegister dst, XMMRegister src) { void Assembler::vptest(XMMRegister dst, Address src) { assert(VM_Version::supports_avx(), ""); + assert(!needs_eevex(src.base(), src.index()), "does not support extended gprs"); InstructionMark im(this); InstructionAttr attributes(AVX_256bit, /* rex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); assert(dst != xnoreg, "sanity"); @@ -6078,8 +6169,8 @@ void Assembler::sbbl(Register dst, Register src) { void Assembler::setb(Condition cc, Register dst) { assert(0 <= cc && cc < 16, "illegal cc"); - int encode = prefix_and_encode(dst->encoding(), true); - emit_int24(0x0F, (unsigned char)0x90 | cc, (0xC0 | encode)); + int encode = prefix_and_encode(dst->encoding(), true, true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0x90 | cc, 0xC0, encode); } void Assembler::palignr(XMMRegister dst, XMMRegister src, int imm8) { @@ -6212,34 +6303,34 @@ void Assembler::shrl(Address dst, int imm8) { void Assembler::shldl(Register dst, Register src) { - int encode = prefix_and_encode(src->encoding(), dst->encoding()); - emit_int24(0x0F, (unsigned char)0xA5, (0xC0 | encode)); + int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xA5, 0xC0, encode); } void Assembler::shldl(Register dst, Register src, int8_t imm8) { - int encode = prefix_and_encode(src->encoding(), dst->encoding()); - emit_int32(0x0F, (unsigned char)0xA4, (0xC0 | encode), imm8); + int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xA4, 0xC0, encode, imm8); } void Assembler::shrdl(Register dst, Register src) { - int encode = prefix_and_encode(src->encoding(), dst->encoding()); - emit_int24(0x0F, (unsigned char)0xAD, (0xC0 | encode)); + int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xAD, 0xC0, encode); } void Assembler::shrdl(Register dst, Register src, int8_t imm8) { - int encode = prefix_and_encode(src->encoding(), dst->encoding()); - emit_int32(0x0F, (unsigned char)0xAC, (0xC0 | encode), imm8); + int encode = prefix_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xAC, 0xC0, encode, imm8); } #ifdef _LP64 void Assembler::shldq(Register dst, Register src, int8_t imm8) { - int encode = prefixq_and_encode(src->encoding(), dst->encoding()); - emit_int32(0x0F, (unsigned char)0xA4, (0xC0 | encode), imm8); + int encode = prefixq_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xA4, 0xC0, encode, imm8); } void Assembler::shrdq(Register dst, Register src, int8_t imm8) { - int encode = prefixq_and_encode(src->encoding(), dst->encoding()); - emit_int32(0x0F, (unsigned char)0xAC, (0xC0 | encode), imm8); + int encode = prefixq_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xAC, 0xC0, encode, imm8); } #endif @@ -6305,8 +6396,11 @@ void Assembler::sqrtss(XMMRegister dst, Address src) { emit_operand(dst, src, 0); } -void Assembler::stmxcsr( Address dst) { - if (UseAVX > 0 ) { +void Assembler::stmxcsr(Address dst) { + // This instruction should be SSE encoded with the REX2 prefix when an + // extended GPR is present. To be consistent when UseAPX is enabled, use + // this encoding even when an extended GPR is not used. + if (UseAVX > 0 && !UseAPX ) { assert(VM_Version::supports_avx(), ""); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); @@ -6316,8 +6410,8 @@ void Assembler::stmxcsr( Address dst) { } else { NOT_LP64(assert(VM_Version::supports_sse(), "")); InstructionMark im(this); - prefix(dst); - emit_int16(0x0F, (unsigned char)0xAE); + prefix(dst, true /* is_map1 */); + emit_int8((unsigned char)0xAE); emit_operand(as_Register(3), dst, 0); } } @@ -6457,34 +6551,32 @@ void Assembler::testl(Register dst, Address src) { void Assembler::tzcntl(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); emit_int8((unsigned char)0xF3); - int encode = prefix_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, - (unsigned char)0xBC, - 0xC0 | encode); + int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode); } void Assembler::tzcntl(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); InstructionMark im(this); emit_int8((unsigned char)0xF3); - prefix(src, dst); - emit_int16(0x0F, (unsigned char)0xBC); + prefix(src, dst, false, true /* is_map1 */); + emit_int8((unsigned char)0xBC); emit_operand(dst, src, 0); } void Assembler::tzcntq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); emit_int8((unsigned char)0xF3); - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBC, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode); } void Assembler::tzcntq(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); InstructionMark im(this); emit_int8((unsigned char)0xF3); - prefixq(src, dst); - emit_int16(0x0F, (unsigned char)0xBC); + prefixq(src, dst, true /* is_map1 */); + emit_int8((unsigned char)0xBC); emit_operand(dst, src, 0); } @@ -6530,23 +6622,23 @@ void Assembler::xabort(int8_t imm8) { void Assembler::xaddb(Address dst, Register src) { InstructionMark im(this); - prefix(dst, src, true); - emit_int16(0x0F, (unsigned char)0xC0); + prefix(dst, src, true, true /* is_map1 */); + emit_int8((unsigned char)0xC0); emit_operand(src, dst, 0); } void Assembler::xaddw(Address dst, Register src) { InstructionMark im(this); emit_int8(0x66); - prefix(dst, src); - emit_int16(0x0F, (unsigned char)0xC1); + prefix(dst, src, false, true /* is_map1 */); + emit_int8((unsigned char)0xC1); emit_operand(src, dst, 0); } void Assembler::xaddl(Address dst, Register src) { InstructionMark im(this); - prefix(dst, src); - emit_int16(0x0F, (unsigned char)0xC1); + prefix(dst, src, false, true /* is_map1 */); + emit_int8((unsigned char)0xC1); emit_operand(src, dst, 0); } @@ -9116,7 +9208,7 @@ void Assembler::extractps(Register dst, XMMRegister src, uint8_t imm8) { assert(VM_Version::supports_sse4_1(), ""); assert(imm8 <= 0x03, "imm8: %u", imm8); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes, true); // imm8: // 0x00 - extract from bits 31:0 // 0x01 - extract from bits 63:32 @@ -10886,7 +10978,7 @@ void Assembler::evpbroadcastb(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true); emit_int16(0x7A, (0xC0 | encode)); } @@ -10895,7 +10987,7 @@ void Assembler::evpbroadcastw(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_avx512bw(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes , true); emit_int16(0x7B, (0xC0 | encode)); } @@ -10904,7 +10996,7 @@ void Assembler::evpbroadcastd(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_evex(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); attributes.set_is_evex_instruction(); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true); emit_int16(0x7C, (0xC0 | encode)); } @@ -10913,7 +11005,7 @@ void Assembler::evpbroadcastq(XMMRegister dst, Register src, int vector_len) { assert(VM_Version::supports_evex(), ""); 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(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true); emit_int16(0x7C, (0xC0 | encode)); } @@ -11673,7 +11765,8 @@ void Assembler::vex_prefix(bool vex_r, bool vex_b, bool vex_x, int nds_enc, VexS } // This is a 4 byte encoding -void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, bool evex_v, int nds_enc, VexSimdPrefix pre, VexOpcode opc){ +void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, bool eevex_b, bool evex_v, + bool eevex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc) { // EVEX 0x62 prefix // byte1 = EVEX_4bytes; @@ -11682,18 +11775,18 @@ void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, boo // EVEX.b is not currently used for broadcast of single element or data rounding modes _attributes->set_evex_encoding(evex_encoding); - // P0: byte 2, initialized to RXBR`00mm + // P0: byte 2, initialized to RXBR'0mmm // instead of not'd int byte2 = (vex_r ? VEX_R : 0) | (vex_x ? VEX_X : 0) | (vex_b ? VEX_B : 0) | (evex_r ? EVEX_Rb : 0); byte2 = (~byte2) & 0xF0; + byte2 |= eevex_b ? EEVEX_B : 0; // confine opc opcode extensions in mm bits to lower two bits - // of form {0F, 0F_38, 0F_3A} + // of form {0F, 0F_38, 0F_3A, 0F_3C} byte2 |= opc; // P1: byte 3 as Wvvvv1pp int byte3 = ((~nds_enc) & 0xf) << 3; - // p[10] is always 1 - byte3 |= EVEX_F; + byte3 |= (eevex_x ? 0 : EEVEX_X); byte3 |= (vex_w & 1) << 7; // confine pre opcode extensions in pp bits to lower two bits // of form {66, F3, F2} @@ -11720,6 +11813,10 @@ void Assembler::evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, boo } void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes) { + if (adr.base_needs_rex2() || adr.index_needs_rex2()) { + assert(UseAPX, "APX features not enabled"); + } + bool is_extended = adr.base_needs_rex2() || adr.index_needs_rex2() || nds_enc >= 16 || xreg_enc >= 16; bool vex_r = (xreg_enc & 8) == 8; bool vex_b = adr.base_needs_rex(); bool vex_x; @@ -11729,13 +11826,12 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix vex_x = adr.index_needs_rex(); } set_attributes(attributes); - // For EVEX instruction (which is not marked as pure EVEX instruction) check and see if this instruction // is allowed in legacy mode and has resources which will fit in it. // Pure EVEX instructions will have is_evex_instruction set in their definition. if (!attributes->is_legacy_mode()) { if (UseAVX > 2 && !attributes->is_evex_instruction() && !is_managed()) { - if ((attributes->get_vector_len() != AVX_512bit) && (nds_enc < 16) && (xreg_enc < 16)) { + if ((attributes->get_vector_len() != AVX_512bit) && !is_extended) { attributes->set_is_legacy_mode(); } } @@ -11746,7 +11842,7 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix (attributes->get_vector_len() == AVX_512bit) || (!_legacy_mode_vl) || (attributes->is_legacy_mode())),"XMM register should be 0-15"); - assert(((nds_enc < 16 && xreg_enc < 16) || (!attributes->is_legacy_mode())),"XMM register should be 0-15"); + assert((!is_extended || (!attributes->is_legacy_mode())),"XMM register should be 0-15"); } clear_managed(); @@ -11760,8 +11856,10 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix } else { evex_v = (nds_enc >= 16); } + bool eevex_x = adr.index_needs_rex2(); + bool eevex_b = adr.base_needs_rex2(); attributes->set_is_evex_instruction(); - evex_prefix(vex_r, vex_b, vex_x, evex_r, evex_v, nds_enc, pre, opc); + evex_prefix(vex_r, vex_b, vex_x, evex_r, eevex_b, evex_v, eevex_x, nds_enc, pre, opc); } else { if (UseAVX > 2 && attributes->is_rex_vex_w_reverted()) { attributes->set_rex_vex_w(false); @@ -11770,7 +11868,11 @@ void Assembler::vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix } } -int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes) { +int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes, bool src_is_gpr) { + if (src_is_gpr && src_enc >= 16) { + assert(UseAPX, "APX features not enabled"); + } + bool is_extended = dst_enc >= 16 || nds_enc >= 16 || src_enc >=16; bool vex_r = (dst_enc & 8) == 8; bool vex_b = (src_enc & 8) == 8; bool vex_x = false; @@ -11782,7 +11884,7 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS if (!attributes->is_legacy_mode()) { if (UseAVX > 2 && !attributes->is_evex_instruction() && !is_managed()) { if ((!attributes->uses_vl() || (attributes->get_vector_len() != AVX_512bit)) && - (dst_enc < 16) && (nds_enc < 16) && (src_enc < 16)) { + !is_extended) { attributes->set_is_legacy_mode(); } } @@ -11799,7 +11901,7 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS (!_legacy_mode_vl) || (attributes->is_legacy_mode())),"XMM register should be 0-15"); // Instruction with legacy_mode true should have dst, nds and src < 15 - assert(((dst_enc < 16 && nds_enc < 16 && src_enc < 16) || (!attributes->is_legacy_mode())),"XMM register should be 0-15"); + assert(((!is_extended) || (!attributes->is_legacy_mode())),"XMM register should be 0-15"); } clear_managed(); @@ -11807,10 +11909,11 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS { bool evex_r = (dst_enc >= 16); bool evex_v = (nds_enc >= 16); + bool evex_b = (src_enc >= 16) && src_is_gpr; // can use vex_x as bank extender on rm encoding - vex_x = (src_enc >= 16); + vex_x = (src_enc >= 16) && !src_is_gpr; attributes->set_is_evex_instruction(); - evex_prefix(vex_r, vex_b, vex_x, evex_r, evex_v, nds_enc, pre, opc); + evex_prefix(vex_r, vex_b, vex_x, evex_r, evex_b, evex_v, false /*eevex_x*/, nds_enc, pre, opc); } else { if (UseAVX > 2 && attributes->is_rex_vex_w_reverted()) { attributes->set_rex_vex_w(false); @@ -11822,7 +11925,6 @@ int Assembler::vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexS return (((dst_enc & 7) << 3) | (src_enc & 7)); } - void Assembler::simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes) { if (UseAVX > 0) { @@ -11836,12 +11938,12 @@ void Assembler::simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexS } int Assembler::simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes) { + VexOpcode opc, InstructionAttr *attributes, bool src_is_gpr) { int dst_enc = dst->encoding(); int src_enc = src->encoding(); if (UseAVX > 0) { int nds_enc = nds->is_valid() ? nds->encoding() : 0; - return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, attributes); + return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, attributes, src_is_gpr); } else { assert((nds == dst) || (nds == src) || (nds == xnoreg), "wrong sse encoding"); return rex_prefix_and_encode(dst_enc, src_enc, pre, opc, attributes->is_rex_vex_w()); @@ -12336,50 +12438,51 @@ void Assembler::evpblendmq (XMMRegister dst, KRegister mask, XMMRegister nds, XM void Assembler::bzhiq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::bzhil(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::pextl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::pdepl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::pextq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::pdepq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF5, (0xC0 | encode)); } void Assembler::pextl(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF5); emit_operand(dst, src2, 0); @@ -12388,7 +12491,8 @@ void Assembler::pextl(Register dst, Register src1, Address src2) { void Assembler::pdepl(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF5); emit_operand(dst, src2, 0); @@ -12397,7 +12501,8 @@ void Assembler::pdepl(Register dst, Register src1, Address src2) { void Assembler::pextq(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF5); emit_operand(dst, src2, 0); @@ -12406,7 +12511,8 @@ void Assembler::pextq(Register dst, Register src1, Address src2) { void Assembler::pdepq(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF5); emit_operand(dst, src2, 0); @@ -12414,15 +12520,16 @@ void Assembler::pdepq(Register dst, Register src1, Address src2) { void Assembler::sarxl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::sarxl(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12430,15 +12537,16 @@ void Assembler::sarxl(Register dst, Address src1, Register src2) { void Assembler::sarxq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::sarxq(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12446,15 +12554,16 @@ void Assembler::sarxq(Register dst, Address src1, Register src2) { void Assembler::shlxl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::shlxl(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12462,15 +12571,16 @@ void Assembler::shlxl(Register dst, Address src1, Register src2) { void Assembler::shlxq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::shlxq(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12478,15 +12588,16 @@ void Assembler::shlxq(Register dst, Address src1, Register src2) { void Assembler::shrxl(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::shrxl(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12494,15 +12605,16 @@ void Assembler::shrxl(Register dst, Address src1, Register src2) { void Assembler::shrxq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); - int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), src2->encoding(), src1->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF7, (0xC0 | encode)); } void Assembler::shrxq(Register dst, Address src1, Register src2) { assert(VM_Version::supports_bmi2(), ""); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ true); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src1, src2->encoding(), dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF7); emit_operand(dst, src1, 0); @@ -12806,13 +12918,48 @@ void Assembler::emit_data64(jlong data, emit_int64(data); } +int Assembler::get_base_prefix_bits(int enc) { + int bits = 0; + if (enc & 16) bits |= REX2BIT_B4; + if (enc & 8) bits |= REXBIT_B; + return bits; +} + +int Assembler::get_index_prefix_bits(int enc) { + int bits = 0; + if (enc & 16) bits |= REX2BIT_X4; + if (enc & 8) bits |= REXBIT_X; + return bits; +} + +int Assembler::get_base_prefix_bits(Register base) { + return base->is_valid() ? get_base_prefix_bits(base->encoding()) : 0; +} + +int Assembler::get_index_prefix_bits(Register index) { + return index->is_valid() ? get_index_prefix_bits(index->encoding()) : 0; +} + +int Assembler::get_reg_prefix_bits(int enc) { + int bits = 0; + if (enc & 16) bits |= REX2BIT_R4; + if (enc & 8) bits |= REXBIT_R; + return bits; +} + void Assembler::prefix(Register reg) { - if (reg->encoding() >= 8) { + if (reg->encoding() >= 16) { + prefix16(WREX2 | get_base_prefix_bits(reg->encoding())); + } else if (reg->encoding() >= 8) { prefix(REX_B); } } void Assembler::prefix(Register dst, Register src, Prefix p) { + if ((p & WREX2) || src->encoding() >= 16 || dst->encoding() >= 16) { + prefix_rex2(dst, src); + return; + } if (src->encoding() >= 8) { p = (Prefix)(p | REX_B); } @@ -12825,7 +12972,17 @@ void Assembler::prefix(Register dst, Register src, Prefix p) { } } +void Assembler::prefix_rex2(Register dst, Register src) { + int bits = 0; + bits |= get_base_prefix_bits(src->encoding()); + bits |= get_reg_prefix_bits(dst->encoding()); + prefix16(WREX2 | bits); +} + void Assembler::prefix(Register dst, Address adr, Prefix p) { + if (adr.base_needs_rex2() || adr.index_needs_rex2() || dst->encoding() >= 16) { + prefix_rex2(dst, adr); + } if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { assert(false, "prefix(Register dst, Address adr, Prefix p) does not support handling of an X"); @@ -12846,7 +13003,19 @@ void Assembler::prefix(Register dst, Address adr, Prefix p) { } } -void Assembler::prefix(Address adr) { +void Assembler::prefix_rex2(Register dst, Address adr) { + assert(!adr.index_needs_rex2(), "prefix(Register dst, Address adr) does not support handling of an X"); + int bits = 0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_reg_prefix_bits(dst->encoding()); + prefix16(WREX2 | bits); +} + +void Assembler::prefix(Address adr, bool is_map1) { + if (adr.base_needs_rex2() || adr.index_needs_rex2()) { + prefix_rex2(adr, is_map1); + return; + } if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { prefix(REX_XB); @@ -12858,9 +13027,21 @@ void Assembler::prefix(Address adr) { prefix(REX_X); } } + if (is_map1) emit_int8(0x0F); +} + +void Assembler::prefix_rex2(Address adr, bool is_map1) { + int bits = is_map1 ? REX2BIT_M0 : 0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + prefix16(WREX2 | bits); } -void Assembler::prefix(Address adr, Register reg, bool byteinst) { +void Assembler::prefix(Address adr, Register reg, bool byteinst, bool is_map1) { + if (reg->encoding() >= 16 || adr.base_needs_rex2() || adr.index_needs_rex2()) { + prefix_rex2(adr, reg, byteinst, is_map1); + return; + } if (reg->encoding() < 8) { if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { @@ -12890,9 +13071,22 @@ void Assembler::prefix(Address adr, Register reg, bool byteinst) { } } } + if (is_map1) emit_int8(0x0F); +} + +void Assembler::prefix_rex2(Address adr, Register reg, bool byteinst, bool is_map1) { + int bits = is_map1 ? REX2BIT_M0 : 0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + bits |= get_reg_prefix_bits(reg->encoding()); + prefix16(WREX2 | bits); } void Assembler::prefix(Address adr, XMMRegister reg) { + if (reg->encoding() >= 16 || adr.base_needs_rex2() || adr.index_needs_rex2()) { + prefixq_rex2(adr, reg); + return; + } if (reg->encoding() < 8) { if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { @@ -12922,17 +13116,37 @@ void Assembler::prefix(Address adr, XMMRegister reg) { } } -int Assembler::prefix_and_encode(int reg_enc, bool byteinst) { +void Assembler::prefix_rex2(Address adr, XMMRegister src) { + int bits = 0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + bits |= get_reg_prefix_bits(src->encoding()); + prefix16(WREX2 | bits); +} + +int Assembler::prefix_and_encode(int reg_enc, bool byteinst, bool is_map1) { + if (reg_enc >= 16) { + return prefix_and_encode_rex2(reg_enc, is_map1); + } if (reg_enc >= 8) { prefix(REX_B); reg_enc -= 8; } else if (byteinst && reg_enc >= 4) { prefix(REX); } - return reg_enc; + int opc_prefix = is_map1 ? 0x0F00 : 0; + return opc_prefix | reg_enc; } -int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { +int Assembler::prefix_and_encode_rex2(int reg_enc, bool is_map1) { + prefix16(WREX2 | (is_map1 ? REX2BIT_M0 : 0) | get_base_prefix_bits(reg_enc)); + return reg_enc & 0x7; +} + +int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte, bool is_map1) { + if (src_enc >= 16 || dst_enc >= 16) { + return prefix_and_encode_rex2(dst_enc, src_enc, is_map1 ? REX2BIT_M0 : 0); + } if (dst_enc < 8) { if (src_enc >= 8) { prefix(REX_B); @@ -12949,16 +13163,46 @@ int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, boo } dst_enc -= 8; } + int opcode_prefix = is_map1 ? 0x0F00 : 0; + return opcode_prefix | (dst_enc << 3 | src_enc); +} + +int Assembler::prefix_and_encode_rex2(int dst_enc, int src_enc, int init_bits) { + int bits = init_bits; + bits |= get_reg_prefix_bits(dst_enc); + bits |= get_base_prefix_bits(src_enc); + dst_enc &= 0x7; + src_enc &= 0x7; + prefix16(WREX2 | bits); return dst_enc << 3 | src_enc; } -int8_t Assembler::get_prefixq(Address adr) { +bool Assembler::prefix_is_rex2(int prefix) { + return (prefix & 0xFF00) == WREX2; +} + +int Assembler::get_prefixq(Address adr, bool is_map1) { + if (adr.base_needs_rex2() || adr.index_needs_rex2()) { + return get_prefixq_rex2(adr, is_map1); + } int8_t prfx = get_prefixq(adr, rax); assert(REX_W <= prfx && prfx <= REX_WXB, "must be"); - return prfx; + return is_map1 ? (((int16_t)prfx) << 8) | 0x0F : (int16_t)prfx; +} + +int Assembler::get_prefixq_rex2(Address adr, bool is_map1) { + assert(UseAPX, "APX features not enabled"); + int bits = REXBIT_W; + if (is_map1) bits |= REX2BIT_M0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + return WREX2 | bits; } -int8_t Assembler::get_prefixq(Address adr, Register src) { +int Assembler::get_prefixq(Address adr, Register src, bool is_map1) { + if (adr.base_needs_rex2() || adr.index_needs_rex2() || src->encoding() >= 16) { + return get_prefixq_rex2(adr, src, is_map1); + } int8_t prfx = (int8_t)(REX_W + ((int)adr.base_needs_rex()) + ((int)adr.index_needs_rex() << 1) + @@ -12994,18 +13238,42 @@ int8_t Assembler::get_prefixq(Address adr, Register src) { } } #endif - return prfx; + return is_map1 ? (((int16_t)prfx) << 8) | 0x0F : (int16_t)prfx; +} + +int Assembler::get_prefixq_rex2(Address adr, Register src, bool is_map1) { + assert(UseAPX, "APX features not enabled"); + int bits = REXBIT_W; + if (is_map1) bits |= REX2BIT_M0; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + bits |= get_reg_prefix_bits(src->encoding()); + return WREX2 | bits; } void Assembler::prefixq(Address adr) { - emit_int8(get_prefixq(adr)); + if (adr.base_needs_rex2() || adr.index_needs_rex2()) { + prefix16(get_prefixq_rex2(adr)); + } else { + emit_int8(get_prefixq(adr)); + } } -void Assembler::prefixq(Address adr, Register src) { - emit_int8(get_prefixq(adr, src)); +void Assembler::prefixq(Address adr, Register src, bool is_map1) { + if (adr.base_needs_rex2() || adr.index_needs_rex2() || src->encoding() >= 16) { + prefix16(get_prefixq_rex2(adr, src, is_map1)); + } else { + emit_int8(get_prefixq(adr, src)); + if (is_map1) emit_int8(0x0F); + } } + void Assembler::prefixq(Address adr, XMMRegister src) { + if (src->encoding() >= 16 || adr.base_needs_rex2() || adr.index_needs_rex2()) { + prefixq_rex2(adr, src); + return; + } if (src->encoding() < 8) { if (adr.base_needs_rex()) { if (adr.index_needs_rex()) { @@ -13037,17 +13305,38 @@ void Assembler::prefixq(Address adr, XMMRegister src) { } } -int Assembler::prefixq_and_encode(int reg_enc) { +void Assembler::prefixq_rex2(Address adr, XMMRegister src) { + int bits = REXBIT_W; + bits |= get_base_prefix_bits(adr.base()); + bits |= get_index_prefix_bits(adr.index()); + bits |= get_reg_prefix_bits(src->encoding()); + prefix16(WREX2 | bits); +} + +int Assembler::prefixq_and_encode(int reg_enc, bool is_map1) { + if (reg_enc >= 16) { + return prefixq_and_encode_rex2(reg_enc, is_map1); + } if (reg_enc < 8) { prefix(REX_W); } else { prefix(REX_WB); reg_enc -= 8; } - return reg_enc; + int opcode_prefix = is_map1 ? 0x0F00 : 0; + return opcode_prefix | reg_enc; } -int Assembler::prefixq_and_encode(int dst_enc, int src_enc) { + +int Assembler::prefixq_and_encode_rex2(int reg_enc, bool is_map1) { + prefix16(WREX2 | REXBIT_W | (is_map1 ? REX2BIT_M0: 0) | get_base_prefix_bits(reg_enc)); + return reg_enc & 0x7; +} + +int Assembler::prefixq_and_encode(int dst_enc, int src_enc, bool is_map1) { + if (dst_enc >= 16 || src_enc >= 16) { + return prefixq_and_encode_rex2(dst_enc, src_enc, is_map1); + } if (dst_enc < 8) { if (src_enc < 8) { prefix(REX_W); @@ -13064,7 +13353,22 @@ int Assembler::prefixq_and_encode(int dst_enc, int src_enc) { } dst_enc -= 8; } - return dst_enc << 3 | src_enc; + int opcode_prefix = is_map1 ? 0x0F00 : 0; + return opcode_prefix | (dst_enc << 3 | src_enc); +} + +int Assembler::prefixq_and_encode_rex2(int dst_enc, int src_enc, bool is_map1) { + int init_bits = REXBIT_W | (is_map1 ? REX2BIT_M0 : 0); + return prefix_and_encode_rex2(dst_enc, src_enc, init_bits); +} + +void Assembler::emit_prefix_and_int8(int prefix, int b1) { + if ((prefix & 0xFF00) == 0) { + emit_int16(prefix, b1); + } else { + assert((prefix & 0xFF00) != WREX2 || UseAPX, "APX features not enabled"); + emit_int24((prefix & 0xFF00) >> 8, prefix & 0x00FF, b1); + } } void Assembler::adcq(Register dst, int32_t imm32) { @@ -13074,7 +13378,7 @@ void Assembler::adcq(Register dst, int32_t imm32) { void Assembler::adcq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x13); + emit_prefix_and_int8(get_prefixq(src, dst), 0x13); emit_operand(dst, src, 0); } @@ -13091,7 +13395,7 @@ void Assembler::addq(Address dst, int32_t imm32) { void Assembler::addq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x01); + emit_prefix_and_int8(get_prefixq(dst, src), 0x01); emit_operand(src, dst, 0); } @@ -13102,7 +13406,7 @@ void Assembler::addq(Register dst, int32_t imm32) { void Assembler::addq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x03); + emit_prefix_and_int8(get_prefixq(src, dst), 0x03); emit_operand(dst, src, 0); } @@ -13113,24 +13417,35 @@ void Assembler::addq(Register dst, Register src) { void Assembler::adcxq(Register dst, Register src) { //assert(VM_Version::supports_adx(), "adx instructions not supported"); - emit_int8(0x66); - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int32(0x0F, - 0x38, - (unsigned char)0xF6, - (0xC0 | encode)); + if (needs_rex2(dst, src)) { + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3C, &attributes, true); + emit_int16((unsigned char)0x66, (0xC0 | encode)); + } else { + emit_int8(0x66); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_int32(0x0F, + 0x38, + (unsigned char)0xF6, + (0xC0 | encode)); + } } void Assembler::adoxq(Register dst, Register src) { //assert(VM_Version::supports_adx(), "adx instructions not supported"); - emit_int8((unsigned char)0xF3); - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int32(0x0F, - 0x38, - (unsigned char)0xF6, - (0xC0 | encode)); + if (needs_rex2(dst, src)) { + InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F3, VEX_OPCODE_0F_3C, &attributes, true); + emit_int16((unsigned char)0x66, (0xC0 | encode)); + } else { + emit_int8((unsigned char)0xF3); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_int32(0x0F, + 0x38, + (unsigned char)0xF6, + (0xC0 | encode)); + } } - void Assembler::andq(Address dst, int32_t imm32) { InstructionMark im(this); prefixq(dst); @@ -13144,7 +13459,7 @@ void Assembler::andq(Register dst, int32_t imm32) { void Assembler::andq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x23); + emit_prefix_and_int8(get_prefixq(src, dst), 0x23); emit_operand(dst, src, 0); } @@ -13155,52 +13470,54 @@ void Assembler::andq(Register dst, Register src) { void Assembler::andq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x21); + emit_prefix_and_int8(get_prefixq(dst, src), 0x21); emit_operand(src, dst, 0); } void Assembler::andnq(Register dst, Register src1, Register src2) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF2, (0xC0 | encode)); } void Assembler::andnq(Register dst, Register src1, Address src2) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src2, src1->encoding(), dst->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF2); emit_operand(dst, src2, 0); } void Assembler::bsfq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBC, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode); } void Assembler::bsrq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBD, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBD, 0xC0, encode); } void Assembler::bswapq(Register reg) { - int encode = prefixq_and_encode(reg->encoding()); - emit_int16(0x0F, (0xC8 | encode)); + int encode = prefixq_and_encode(reg->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xC8, encode); } void Assembler::blsiq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsiq(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src, dst->encoding(), rbx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rbx, src, 0); @@ -13208,15 +13525,16 @@ void Assembler::blsiq(Register dst, Address src) { void Assembler::blsmskq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsmskq(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src, dst->encoding(), rdx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rdx, src, 0); @@ -13224,15 +13542,16 @@ void Assembler::blsmskq(Register dst, Address src) { void Assembler::blsrq(Register dst, Register src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsrq(Register dst, Address src) { assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src, dst->encoding(), rcx->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes); emit_int8((unsigned char)0xF3); emit_operand(rcx, src, 0); @@ -13248,8 +13567,8 @@ void Assembler::cdqe() { void Assembler::clflush(Address adr) { assert(VM_Version::supports_clflush(), "should do"); - prefix(adr); - emit_int16(0x0F, (unsigned char)0xAE); + prefix(adr, true /* is_map1 */); + emit_int8((unsigned char)0xAE); emit_operand(rdi, adr, 0); } @@ -13261,9 +13580,9 @@ void Assembler::clflushopt(Address adr) { assert(adr.disp() == 0, "displacement should be 0"); // instruction prefix is 0x66 emit_int8(0x66); - prefix(adr); + prefix(adr, true /* is_map1 */); // opcode family is 0x0F 0xAE - emit_int16(0x0F, (unsigned char)0xAE); + emit_int8((unsigned char)0xAE); // extended opcode byte is 7 == rdi emit_operand(rdi, adr, 0); } @@ -13276,21 +13595,22 @@ void Assembler::clwb(Address adr) { assert(adr.disp() == 0, "displacement should be 0"); // instruction prefix is 0x66 emit_int8(0x66); - prefix(adr); + prefix(adr, true /* is_map1 */); // opcode family is 0x0f 0xAE - emit_int16(0x0F, (unsigned char)0xAE); + emit_int8((unsigned char)0xAE); // extended opcode byte is 6 == rsi emit_operand(rsi, adr, 0); } void Assembler::cmovq(Condition cc, Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (0x40 | cc), (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((0x40 | cc), 0xC0, encode); } void Assembler::cmovq(Condition cc, Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), 0x0F, (0x40 | cc)); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (0x40 | cc)); emit_operand(dst, src, 0); } @@ -13307,7 +13627,7 @@ void Assembler::cmpq(Register dst, int32_t imm32) { void Assembler::cmpq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x39); + emit_prefix_and_int8(get_prefixq(dst, src), 0x39); emit_operand(src, dst, 0); } @@ -13318,20 +13638,21 @@ void Assembler::cmpq(Register dst, Register src) { void Assembler::cmpq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x3B); + emit_prefix_and_int8(get_prefixq(src, dst), 0x3B); emit_operand(dst, src, 0); } void Assembler::cmpxchgq(Register reg, Address adr) { InstructionMark im(this); - emit_int24(get_prefixq(adr, reg), 0x0F, (unsigned char)0xB1); + int prefix = get_prefixq(adr, reg, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xB1); emit_operand(reg, adr, 0); } void Assembler::cvtsi2sdq(XMMRegister dst, Register src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, dst, as_XMMRegister(src->encoding()), VEX_SIMD_F2, VEX_OPCODE_0F, &attributes, true); emit_int16(0x2A, (0xC0 | encode)); } @@ -13360,7 +13681,9 @@ void Assembler::cvttsd2siq(Register dst, Address src) { // F2 REX.W 0F 2C /r // CVTTSD2SI r64, xmm1/m64 InstructionMark im(this); - emit_int32((unsigned char)0xF2, REX_W, 0x0F, 0x2C); + emit_int8((unsigned char)0xF2); + prefixq(src, dst, true /* is_map1 */); + emit_int8((unsigned char)0x2C); emit_operand(dst, src, 0); } @@ -13402,28 +13725,32 @@ void Assembler::decq(Register dst) { void Assembler::decq(Address dst) { // Don't use it directly. Use MacroAssembler::decrementq() instead. InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xFF); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xFF); emit_operand(rcx, dst, 0); } +// can't use REX2 void Assembler::fxrstor(Address src) { InstructionMark im(this); emit_int24(get_prefixq(src), 0x0F, (unsigned char)0xAE); emit_operand(as_Register(1), src, 0); } +// can't use REX2 void Assembler::xrstor(Address src) { InstructionMark im(this); emit_int24(get_prefixq(src), 0x0F, (unsigned char)0xAE); emit_operand(as_Register(5), src, 0); } +// can't use REX2 void Assembler::fxsave(Address dst) { InstructionMark im(this); emit_int24(get_prefixq(dst), 0x0F, (unsigned char)0xAE); emit_operand(as_Register(0), dst, 0); } +// cant use REX2 void Assembler::xsave(Address dst) { InstructionMark im(this); emit_int24(get_prefixq(dst), 0x0F, (unsigned char)0xAE); @@ -13441,8 +13768,8 @@ void Assembler::divq(Register src) { } void Assembler::imulq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xAF, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xAF, 0xC0, encode); } void Assembler::imulq(Register src) { @@ -13476,7 +13803,8 @@ void Assembler::imulq(Register dst, Register src, int value) { void Assembler::imulq(Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), 0x0F, (unsigned char)0xAF); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xAF); emit_operand(dst, src, 0); } @@ -13497,7 +13825,7 @@ void Assembler::incq(Register dst) { void Assembler::incq(Address dst) { // Don't use it directly. Use MacroAssembler::incrementq() instead. InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xFF); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xFF); emit_operand(rax, dst, 0); } @@ -13507,7 +13835,7 @@ void Assembler::lea(Register dst, Address src) { void Assembler::leaq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), (unsigned char)0x8D); + emit_prefix_and_int8(get_prefixq(src, dst), (unsigned char)0x8D); emit_operand(dst, src, 0); } @@ -13565,16 +13893,16 @@ void Assembler::cmp_narrow_oop(Address src1, int32_t imm32, RelocationHolder con void Assembler::lzcntq(Register dst, Register src) { assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR"); emit_int8((unsigned char)0xF3); - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBD, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBD, 0xC0, encode); } void Assembler::lzcntq(Register dst, Address src) { assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR"); InstructionMark im(this); emit_int8((unsigned char)0xF3); - prefixq(src, dst); - emit_int16(0x0F, (unsigned char)0xBD); + prefixq(src, dst, true /* is_map1 */); + emit_int8((unsigned char)0xBD); emit_operand(dst, src, 0); } @@ -13582,7 +13910,7 @@ void Assembler::movdq(XMMRegister dst, Register src) { // table D-1 says MMX/SSE2 NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, xnoreg, as_XMMRegister(src->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x6E, (0xC0 | encode)); } @@ -13591,7 +13919,7 @@ void Assembler::movdq(Register dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); // swap src/dst to get correct prefix - int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(src, xnoreg, as_XMMRegister(dst->encoding()), VEX_SIMD_66, VEX_OPCODE_0F, &attributes, true); emit_int16(0x7E, (0xC0 | encode)); } @@ -13604,19 +13932,19 @@ void Assembler::movq(Register dst, Register src) { void Assembler::movq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), (unsigned char)0x8B); + emit_prefix_and_int8(get_prefixq(src, dst), (unsigned char)0x8B); emit_operand(dst, src, 0); } void Assembler::movq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), (unsigned char)0x89); + emit_prefix_and_int8(get_prefixq(dst, src), (unsigned char)0x89); emit_operand(src, dst, 0); } void Assembler::movq(Address dst, int32_t imm32) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xC7); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xC7); emit_operand(as_Register(0), dst, 4); emit_int32(imm32); } @@ -13629,28 +13957,27 @@ void Assembler::movq(Register dst, int32_t imm32) { void Assembler::movsbq(Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), - 0x0F, - (unsigned char)0xBE); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xBE); emit_operand(dst, src, 0); } void Assembler::movsbq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBE, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBE, 0xC0, encode); } void Assembler::movslq(Address dst, int32_t imm32) { assert(is_simm32(imm32), "lost bits"); InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xC7); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xC7); emit_operand(rax, dst, 4); emit_int32(imm32); } void Assembler::movslq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x63); + emit_prefix_and_int8(get_prefixq(src, dst), 0x63); emit_operand(dst, src, 0); } @@ -13661,46 +13988,43 @@ void Assembler::movslq(Register dst, Register src) { void Assembler::movswq(Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), - 0x0F, - (unsigned char)0xBF); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xBF); emit_operand(dst, src, 0); } void Assembler::movswq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xBF, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBF, 0xC0, encode); } void Assembler::movzbq(Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), - 0x0F, - (unsigned char)0xB6); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xB6); emit_operand(dst, src, 0); } void Assembler::movzbq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xB6, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB6, 0xC0, encode); } void Assembler::movzwq(Register dst, Address src) { InstructionMark im(this); - emit_int24(get_prefixq(src, dst), - 0x0F, - (unsigned char)0xB7); + int prefix = get_prefixq(src, dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xB7); emit_operand(dst, src, 0); } void Assembler::movzwq(Register dst, Register src) { - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xB7, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB7, 0xC0, encode); } void Assembler::mulq(Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src), (unsigned char)0xF7); + emit_prefix_and_int8(get_prefixq(src), (unsigned char)0xF7); emit_operand(rsp, src, 0); } @@ -13711,8 +14035,8 @@ void Assembler::mulq(Register src) { void Assembler::mulxq(Register dst1, Register dst2, Register src) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst1->encoding(), dst2->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst1->encoding(), dst2->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF6, (0xC0 | encode)); } @@ -13723,7 +14047,7 @@ void Assembler::negq(Register dst) { void Assembler::negq(Address dst) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xF7); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xF7); emit_operand(as_Register(3), dst, 0); } @@ -13733,24 +14057,22 @@ void Assembler::notq(Register dst) { } void Assembler::btq(Register dst, Register src) { - int encode = prefixq_and_encode(src->encoding(), dst->encoding()); - emit_int24(0x0F, (unsigned char)0xA3, (encode | 0xC0)); + int encode = prefixq_and_encode(src->encoding(), dst->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xA3, 0xC0, encode); } void Assembler::btq(Register src, int imm8) { assert(isByte(imm8), "not a byte"); - int encode = prefixq_and_encode(src->encoding()); - emit_int16(0x0f, 0xba); - emit_int8(0xe0|encode); + int encode = prefixq_and_encode(src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xBA, 0xE0, encode); emit_int8(imm8); } void Assembler::btsq(Address dst, int imm8) { assert(isByte(imm8), "not a byte"); InstructionMark im(this); - emit_int24(get_prefixq(dst), - 0x0F, - (unsigned char)0xBA); + int prefix = get_prefixq(dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xBA); emit_operand(rbp /* 5 */, dst, 1); emit_int8(imm8); } @@ -13758,9 +14080,8 @@ void Assembler::btsq(Address dst, int imm8) { void Assembler::btrq(Address dst, int imm8) { assert(isByte(imm8), "not a byte"); InstructionMark im(this); - emit_int24(get_prefixq(dst), - 0x0F, - (unsigned char)0xBA); + int prefix = get_prefixq(dst, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xBA); emit_operand(rsi /* 6 */, dst, 1); emit_int8(imm8); } @@ -13773,7 +14094,7 @@ void Assembler::orq(Address dst, int32_t imm32) { void Assembler::orq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), (unsigned char)0x09); + emit_prefix_and_int8(get_prefixq(dst, src), (unsigned char)0x09); emit_operand(src, dst, 0); } @@ -13789,7 +14110,7 @@ void Assembler::orq_imm32(Register dst, int32_t imm32) { void Assembler::orq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x0B); + emit_prefix_and_int8(get_prefixq(src, dst), 0x0B); emit_operand(dst, src, 0); } @@ -13801,28 +14122,27 @@ void Assembler::orq(Register dst, Register src) { void Assembler::popcntq(Register dst, Address src) { assert(VM_Version::supports_popcnt(), "must support"); InstructionMark im(this); - emit_int32((unsigned char)0xF3, - get_prefixq(src, dst), - 0x0F, - (unsigned char)0xB8); + emit_int8((unsigned char)0xF3); + emit_prefix_and_int8(get_prefixq(src, dst, true /* is_map1 */), (unsigned char) 0xB8); emit_operand(dst, src, 0); } void Assembler::popcntq(Register dst, Register src) { assert(VM_Version::supports_popcnt(), "must support"); emit_int8((unsigned char)0xF3); - int encode = prefixq_and_encode(dst->encoding(), src->encoding()); - emit_int24(0x0F, (unsigned char)0xB8, (0xC0 | encode)); + int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); + emit_opcode_prefix_and_encoding((unsigned char)0xB8, 0xC0, encode); } void Assembler::popq(Address dst) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0x8F); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0x8F); emit_operand(rax, dst, 0); } void Assembler::popq(Register dst) { - emit_int8((unsigned char)0x58 | dst->encoding()); + int encode = prefix_and_encode(dst->encoding()); + emit_int8((unsigned char)0x58 | encode); } // Precomputable: popa, pusha, vzeroupper @@ -13962,7 +14282,7 @@ void Assembler::vzeroall() { void Assembler::pushq(Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src), (unsigned char)0xFF); + emit_prefix_and_int8(get_prefixq(src), (unsigned char)0xFF); emit_operand(rsi, src, 0); } @@ -13988,15 +14308,16 @@ void Assembler::rcrq(Register dst, int imm8) { void Assembler::rorxl(Register dst, Register src, int imm8) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes, true); emit_int24((unsigned char)0xF0, (0xC0 | encode), imm8); } void Assembler::rorxl(Register dst, Address src, int imm8) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes); emit_int8((unsigned char)0xF0); emit_operand(dst, src, 1); @@ -14005,15 +14326,16 @@ void Assembler::rorxl(Register dst, Address src, int imm8) { void Assembler::rorxq(Register dst, Register src, int imm8) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes, true); emit_int24((unsigned char)0xF0, (0xC0 | encode), imm8); } void Assembler::rorxq(Register dst, Address src, int imm8) { assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); InstructionMark im(this); - InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false); + InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); + attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); vex_prefix(src, 0, dst->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, &attributes); emit_int8((unsigned char)0xF0); emit_operand(dst, src, 1); @@ -14025,11 +14347,11 @@ void Assembler::salq(Address dst, int imm8) { InstructionMark im(this); assert(isShiftCount(imm8 >> 1), "illegal shift count"); if (imm8 == 1) { - emit_int16(get_prefixq(dst), (unsigned char)0xD1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD1); emit_operand(as_Register(4), dst, 0); } else { - emit_int16(get_prefixq(dst), (unsigned char)0xC1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xC1); emit_operand(as_Register(4), dst, 1); emit_int8(imm8); } @@ -14037,7 +14359,7 @@ void Assembler::salq(Address dst, int imm8) { void Assembler::salq(Address dst) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xD3); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD3); emit_operand(as_Register(4), dst, 0); } @@ -14060,11 +14382,11 @@ void Assembler::sarq(Address dst, int imm8) { InstructionMark im(this); assert(isShiftCount(imm8 >> 1), "illegal shift count"); if (imm8 == 1) { - emit_int16(get_prefixq(dst), (unsigned char)0xD1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD1); emit_operand(as_Register(7), dst, 0); } else { - emit_int16(get_prefixq(dst), (unsigned char)0xC1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xC1); emit_operand(as_Register(7), dst, 1); emit_int8(imm8); } @@ -14072,7 +14394,7 @@ void Assembler::sarq(Address dst, int imm8) { void Assembler::sarq(Address dst) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xD3); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD3); emit_operand(as_Register(7), dst, 0); } @@ -14105,7 +14427,7 @@ void Assembler::sbbq(Register dst, int32_t imm32) { void Assembler::sbbq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x1B); + emit_prefix_and_int8(get_prefixq(src, dst), 0x1B); emit_operand(dst, src, 0); } @@ -14147,7 +14469,7 @@ void Assembler::shrq(Register dst) { void Assembler::shrq(Address dst) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xD3); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD3); emit_operand(as_Register(5), dst, 0); } @@ -14155,11 +14477,11 @@ void Assembler::shrq(Address dst, int imm8) { InstructionMark im(this); assert(isShiftCount(imm8 >> 1), "illegal shift count"); if (imm8 == 1) { - emit_int16(get_prefixq(dst), (unsigned char)0xD1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xD1); emit_operand(as_Register(5), dst, 0); } else { - emit_int16(get_prefixq(dst), (unsigned char)0xC1); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xC1); emit_operand(as_Register(5), dst, 1); emit_int8(imm8); } @@ -14173,7 +14495,7 @@ void Assembler::subq(Address dst, int32_t imm32) { void Assembler::subq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x29); + emit_prefix_and_int8(get_prefixq(dst, src), 0x29); emit_operand(src, dst, 0); } @@ -14190,7 +14512,7 @@ void Assembler::subq_imm32(Register dst, int32_t imm32) { void Assembler::subq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x2B); + emit_prefix_and_int8(get_prefixq(src, dst), 0x2B); emit_operand(dst, src, 0); } @@ -14201,7 +14523,7 @@ void Assembler::subq(Register dst, Register src) { void Assembler::testq(Address dst, int32_t imm32) { InstructionMark im(this); - emit_int16(get_prefixq(dst), (unsigned char)0xF7); + emit_prefix_and_int8(get_prefixq(dst), (unsigned char)0xF7); emit_operand(as_Register(0), dst, 4); emit_int32(imm32); } @@ -14229,19 +14551,20 @@ void Assembler::testq(Register dst, Register src) { void Assembler::testq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), (unsigned char)0x85); + emit_prefix_and_int8(get_prefixq(src, dst), (unsigned char)0x85); emit_operand(dst, src, 0); } void Assembler::xaddq(Address dst, Register src) { InstructionMark im(this); - emit_int24(get_prefixq(dst, src), 0x0F, (unsigned char)0xC1); + int prefix = get_prefixq(dst, src, true /* is_map1 */); + emit_prefix_and_int8(prefix, (unsigned char)0xC1); emit_operand(src, dst, 0); } void Assembler::xchgq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), (unsigned char)0x87); + emit_prefix_and_int8(get_prefixq(src, dst), (unsigned char)0x87); emit_operand(dst, src, 0); } @@ -14257,7 +14580,7 @@ void Assembler::xorq(Register dst, Register src) { void Assembler::xorq(Register dst, Address src) { InstructionMark im(this); - emit_int16(get_prefixq(src, dst), 0x33); + emit_prefix_and_int8(get_prefixq(src, dst), 0x33); emit_operand(dst, src, 0); } @@ -14274,7 +14597,7 @@ void Assembler::xorq(Address dst, int32_t imm32) { void Assembler::xorq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x31); + emit_prefix_and_int8(get_prefixq(dst, src), 0x31); emit_operand(src, dst, 0); } diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 097bc9de62a..32a81519f82 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -308,17 +308,29 @@ class Address { private: bool base_needs_rex() const { - return _base->is_valid() && _base->encoding() >= 8; + return _base->is_valid() && ((_base->encoding() & 8) == 8); + } + + bool base_needs_rex2() const { + return _base->is_valid() && _base->encoding() >= 16; } bool index_needs_rex() const { - return _index->is_valid() &&_index->encoding() >= 8; + return _index->is_valid() && ((_index->encoding() & 8) == 8); + } + + bool index_needs_rex2() const { + return _index->is_valid() &&_index->encoding() >= 16; } bool xmmindex_needs_rex() const { return _xmmindex->is_valid() && ((_xmmindex->encoding() & 8) == 8); } + bool xmmindex_needs_rex2() const { + return _xmmindex->is_valid() && _xmmindex->encoding() >= 16; + } + relocInfo::relocType reloc() const { return _rspec.type(); } friend class Assembler; @@ -508,12 +520,26 @@ class Assembler : public AbstractAssembler { REX_WRX = 0x4E, REX_WRXB = 0x4F, + REX2 = 0xd5, + WREX2 = REX2 << 8, + VEX_3bytes = 0xC4, VEX_2bytes = 0xC5, EVEX_4bytes = 0x62, Prefix_EMPTY = 0x0 }; + enum PrefixBits { + REXBIT_B = 0x01, + REXBIT_X = 0x02, + REXBIT_R = 0x04, + REXBIT_W = 0x08, + REX2BIT_B4 = 0x10, + REX2BIT_X4 = 0x20, + REX2BIT_R4 = 0x40, + REX2BIT_M0 = 0x80 + }; + enum VexPrefix { VEX_B = 0x20, VEX_X = 0x40, @@ -525,10 +551,18 @@ class Assembler : public AbstractAssembler { EVEX_F = 0x04, EVEX_V = 0x08, EVEX_Rb = 0x10, + EVEX_B = 0x20, EVEX_X = 0x40, EVEX_Z = 0x80 }; + enum ExtEvexPrefix { + EEVEX_R = 0x10, + EEVEX_B = 0x08, + EEVEX_X = 0x04, + EEVEX_V = 0x08 + }; + enum EvexRoundPrefix { EVEX_RNE = 0x0, EVEX_RD = 0x1, @@ -540,7 +574,7 @@ class Assembler : public AbstractAssembler { VEX_SIMD_NONE = 0x0, VEX_SIMD_66 = 0x1, VEX_SIMD_F3 = 0x2, - VEX_SIMD_F2 = 0x3 + VEX_SIMD_F2 = 0x3, }; enum VexOpcode { @@ -548,6 +582,7 @@ class Assembler : public AbstractAssembler { VEX_OPCODE_0F = 0x1, VEX_OPCODE_0F_38 = 0x2, VEX_OPCODE_0F_3A = 0x3, + VEX_OPCODE_0F_3C = 0x4, VEX_OPCODE_MASK = 0x1F }; @@ -572,7 +607,8 @@ class Assembler : public AbstractAssembler { EVEX_OVM = 20, EVEX_M128 = 21, EVEX_DUP = 22, - EVEX_ETUP = 23 + EVEX_NOSCALE = 23, + EVEX_ETUP = 24 }; enum EvexInputSizeInBits { @@ -686,33 +722,62 @@ class Assembler : public AbstractAssembler { InstructionAttr *_attributes; void set_attributes(InstructionAttr* attributes); + int get_base_prefix_bits(int enc); + int get_index_prefix_bits(int enc); + int get_base_prefix_bits(Register base); + int get_index_prefix_bits(Register index); + int get_reg_prefix_bits(int enc); + // 64bit prefixes void prefix(Register reg); void prefix(Register dst, Register src, Prefix p); + void prefix_rex2(Register dst, Register src); void prefix(Register dst, Address adr, Prefix p); - - void prefix(Address adr); - void prefix(Address adr, Register reg, bool byteinst = false); + void prefix_rex2(Register dst, Address adr); + + // The is_map1 bool indicates an x86 map1 instruction which, when + // legacy encoded, uses a 0x0F opcode prefix. By specification, the + // opcode prefix is omitted when using rex2 encoding in support + // of APX extended GPRs. + void prefix(Address adr, bool is_map1 = false); + void prefix_rex2(Address adr, bool is_map1 = false); + void prefix(Address adr, Register reg, bool byteinst = false, bool is_map1 = false); + void prefix_rex2(Address adr, Register reg, bool byteinst = false, bool is_map1 = false); void prefix(Address adr, XMMRegister reg); + void prefix_rex2(Address adr, XMMRegister reg); - int prefix_and_encode(int reg_enc, bool byteinst = false); - int prefix_and_encode(int dst_enc, int src_enc) { - return prefix_and_encode(dst_enc, false, src_enc, false); + int prefix_and_encode(int reg_enc, bool byteinst = false, bool is_map1 = false); + int prefix_and_encode_rex2(int reg_enc, bool is_map1 = false); + int prefix_and_encode(int dst_enc, int src_enc, bool is_map1 = false) { + return prefix_and_encode(dst_enc, false, src_enc, false, is_map1); } - int prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte); + int prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte, bool is_map1 = false); + int prefix_and_encode_rex2(int dst_enc, int src_enc, int init_bits = 0); // Some prefixq variants always emit exactly one prefix byte, so besides a // prefix-emitting method we provide a method to get the prefix byte to emit, // which can then be folded into a byte stream. - int8_t get_prefixq(Address adr); - int8_t get_prefixq(Address adr, Register reg); + int get_prefixq(Address adr, bool is_map1 = false); + int get_prefixq_rex2(Address adr, bool is_map1 = false); + int get_prefixq(Address adr, Register reg, bool is_map1 = false); + int get_prefixq_rex2(Address adr, Register reg, bool ismap1 = false); void prefixq(Address adr); - void prefixq(Address adr, Register reg); + void prefixq(Address adr, Register reg, bool is_map1 = false); void prefixq(Address adr, XMMRegister reg); + void prefixq_rex2(Address adr, XMMRegister src); - int prefixq_and_encode(int reg_enc); - int prefixq_and_encode(int dst_enc, int src_enc); + bool prefix_is_rex2(int prefix); + + int prefixq_and_encode(int reg_enc, bool is_map1 = false); + int prefixq_and_encode_rex2(int reg_enc, bool is_map1 = false); + int prefixq_and_encode(int dst_enc, int src_enc, bool is_map1 = false); + int prefixq_and_encode_rex2(int dst_enc, int src_enc, bool is_map1 = false); + + bool needs_rex2(Register reg1, Register reg2 = noreg, Register reg3 = noreg); + + bool needs_eevex(Register reg1, Register reg2 = noreg, Register reg3 = noreg); + bool needs_eevex(int enc1, int enc2 = -1, int enc3 = -1); void rex_prefix(Address adr, XMMRegister xreg, VexSimdPrefix pre, VexOpcode opc, bool rex_w); @@ -721,22 +786,21 @@ class Assembler : public AbstractAssembler { void vex_prefix(bool vex_r, bool vex_b, bool vex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc); - void evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_r, bool evex_v, - int nds_enc, VexSimdPrefix pre, VexOpcode opc); + void evex_prefix(bool vex_r, bool vex_b, bool vex_x, bool evex_v, bool evex_r, bool evex_b, + bool eevex_x, int nds_enc, VexSimdPrefix pre, VexOpcode opc); - void vex_prefix(Address adr, int nds_enc, int xreg_enc, - VexSimdPrefix pre, VexOpcode opc, + void vex_prefix(Address adr, int nds_enc, int xreg_enc, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes); int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, - InstructionAttr *attributes); + InstructionAttr *attributes, bool src_is_gpr = false); void simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr, VexSimdPrefix pre, VexOpcode opc, InstructionAttr *attributes); int simd_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, VexSimdPrefix pre, - VexOpcode opc, InstructionAttr *attributes); + VexOpcode opc, InstructionAttr *attributes, bool src_is_gpr = false); // Helper functions for groups of instructions void emit_arith_b(int op1, int op2, Register dst, int imm8); @@ -821,6 +885,10 @@ class Assembler : public AbstractAssembler { void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0); void emit_data64(jlong data, RelocationHolder const& rspec, int format = 0); + void emit_prefix_and_int8(int prefix, int b1); + void emit_opcode_prefix_and_encoding(int byte1, int ocp_and_encoding); + void emit_opcode_prefix_and_encoding(int byte1, int byte2, int ocp_and_encoding); + void emit_opcode_prefix_and_encoding(int byte1, int byte2, int ocp_and_encoding, int byte3); bool always_reachable(AddressLiteral adr) NOT_LP64( { return true; } ); bool reachable(AddressLiteral adr) NOT_LP64( { return true; } ); @@ -907,6 +975,8 @@ class Assembler : public AbstractAssembler { // Instruction prefixes void prefix(Prefix p); + void prefix16(int p); + public: // Creation diff --git a/src/hotspot/cpu/x86/assembler_x86.inline.hpp b/src/hotspot/cpu/x86/assembler_x86.inline.hpp index 66aebb32e21..d2aa76fcf56 100644 --- a/src/hotspot/cpu/x86/assembler_x86.inline.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.inline.hpp @@ -30,23 +30,53 @@ #include "code/codeCache.hpp" #ifndef _LP64 -inline int Assembler::prefix_and_encode(int reg_enc, bool byteinst) { return reg_enc; } -inline int Assembler::prefixq_and_encode(int reg_enc) { return reg_enc; } +inline int Assembler::prefix_and_encode(int reg_enc, bool byteinst, bool is_map1) +{ + int opc_prefix = is_map1 ? 0x0F00 : 0; + return opc_prefix | reg_enc; +} -inline int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte) { return dst_enc << 3 | src_enc; } -inline int Assembler::prefixq_and_encode(int dst_enc, int src_enc) { return dst_enc << 3 | src_enc; } +inline int Assembler::prefixq_and_encode(int reg_enc, bool is_map1) { + int opc_prefix = is_map1 ? 0xF00 : 0; + return opc_prefix | reg_enc; +} + +inline int Assembler::prefix_and_encode(int dst_enc, bool dst_is_byte, int src_enc, bool src_is_byte, bool is_map1) { + int opc_prefix = is_map1 ? 0xF00 : 0; + return opc_prefix | (dst_enc << 3 | src_enc); +} + +inline int Assembler::prefixq_and_encode(int dst_enc, int src_enc, bool is_map1) { + int opc_prefix = is_map1 ? 0xF00 : 0; + return opc_prefix | dst_enc << 3 | src_enc; +} inline void Assembler::prefix(Register reg) {} inline void Assembler::prefix(Register dst, Register src, Prefix p) {} inline void Assembler::prefix(Register dst, Address adr, Prefix p) {} -inline void Assembler::prefix(Address adr) {} + +inline void Assembler::prefix(Address adr, bool is_map1) { + if (is_map1) { + emit_int8(0x0F); + } +} + inline void Assembler::prefixq(Address adr) {} -inline void Assembler::prefix(Address adr, Register reg, bool byteinst) {} -inline void Assembler::prefixq(Address adr, Register reg) {} +inline void Assembler::prefix(Address adr, Register reg, bool byteinst, bool is_map1) { + if (is_map1) { + emit_int8(0x0F); + } +} +inline void Assembler::prefixq(Address adr, Register reg, bool is_map1) { + if (is_map1) { + emit_int8(0x0F); + } +} inline void Assembler::prefix(Address adr, XMMRegister reg) {} inline void Assembler::prefixq(Address adr, XMMRegister reg) {} + #endif // _LP64 #endif // CPU_X86_ASSEMBLER_X86_INLINE_HPP diff --git a/src/hotspot/cpu/x86/globals_x86.hpp b/src/hotspot/cpu/x86/globals_x86.hpp index 0f01eb3a0c4..d73a8d03171 100644 --- a/src/hotspot/cpu/x86/globals_x86.hpp +++ b/src/hotspot/cpu/x86/globals_x86.hpp @@ -232,8 +232,10 @@ define_pd_global(intx, InitArrayShortSize, 8*BytesPerLong); \ product(bool, IntelJccErratumMitigation, true, DIAGNOSTIC, \ "Turn off JVM mitigations related to Intel micro code " \ - "mitigations for the Intel JCC erratum") - + "mitigations for the Intel JCC erratum") \ + \ + product(bool, UseAPX, false, EXPERIMENTAL, \ + "Use Advanced Performance Extensions on x86") \ // end of ARCH_FLAGS #endif // CPU_X86_GLOBALS_X86_HPP diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index fbc952fc8d1..f5389d0ef90 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -1002,6 +1002,14 @@ void VM_Version::get_processor_features() { } } + // APX support not enabled yet + if (UseAPX) { + if (!FLAG_IS_DEFAULT(UseAPX)) { + warning("APX is not supported on this CPU."); + } + FLAG_SET_DEFAULT(UseAPX, false); + } + if (FLAG_IS_DEFAULT(IntelJccErratumMitigation)) { _has_intel_jcc_erratum = compute_has_intel_jcc_erratum(); } else { From 9b1d6d66b8297d53c6b96b9e2f9bd69af90ab8fb Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Thu, 23 May 2024 23:40:00 +0000 Subject: [PATCH 20/99] 8316328: Test jdk/jfr/event/oldobject/TestSanityDefault.java times out for some heap sizes Reviewed-by: phh, shade, egahlin --- test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java b/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java index d3d8377183d..7480acb1d1d 100644 --- a/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java +++ b/test/jdk/jdk/jfr/event/oldobject/TestSanityDefault.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -37,7 +37,7 @@ * @requires vm.hasJFR * @library /test/lib /test/jdk * @summary Purpose of this test is to run leak profiler without command line tweaks or WhiteBox hacks until we succeed - * @run main/othervm jdk.jfr.event.oldobject.TestSanityDefault + * @run main/othervm -Xmx1G jdk.jfr.event.oldobject.TestSanityDefault */ public class TestSanityDefault { From 424eb60dedb332237b8ec97e9da6bd95442c0083 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Fri, 24 May 2024 00:32:49 +0000 Subject: [PATCH 21/99] 8331683: Clean up GetCarrierThread Reviewed-by: sspitsyn, cjplummer --- src/hotspot/share/prims/jvmtiEnvBase.cpp | 8 -------- src/hotspot/share/prims/jvmtiEnvBase.hpp | 18 ------------------ src/hotspot/share/prims/jvmtiExtensions.cpp | 17 ++++++++++------- 3 files changed, 10 insertions(+), 33 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index de3d3f76528..94472baf27c 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -2642,11 +2642,3 @@ GetFrameLocationClosure::do_vthread(Handle target_h) { _result = ((JvmtiEnvBase*)_env)->get_frame_location(target_h(), _depth, _method_ptr, _location_ptr); } - -void -VirtualThreadGetThreadClosure::do_thread(Thread *target) { - assert(target->is_Java_thread(), "just checking"); - JavaThread *jt = JavaThread::cast(target); - oop carrier_thread = java_lang_VirtualThread::carrier_thread(_vthread_h()); - *_carrier_thread_ptr = (jthread)JNIHandles::make_local(jt, carrier_thread); -} diff --git a/src/hotspot/share/prims/jvmtiEnvBase.hpp b/src/hotspot/share/prims/jvmtiEnvBase.hpp index 00de17a8a6b..d984cc8bd37 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.hpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.hpp @@ -784,24 +784,6 @@ class GetFrameLocationClosure : public JvmtiUnitedHandshakeClosure { void do_vthread(Handle target_h); }; -// HandshakeClosure to get virtual thread thread at safepoint. -class VirtualThreadGetThreadClosure : public HandshakeClosure { -private: - Handle _vthread_h; - jthread* _carrier_thread_ptr; - jvmtiError _result; - -public: - VirtualThreadGetThreadClosure(Handle vthread_h, jthread* carrier_thread_ptr) - : HandshakeClosure("VirtualThreadGetThread"), - _vthread_h(vthread_h), - _carrier_thread_ptr(carrier_thread_ptr), - _result(JVMTI_ERROR_NONE) {} - - void do_thread(Thread *target); - jvmtiError result() { return _result; } -}; - // ResourceTracker // // ResourceTracker works a little like a ResourceMark. All allocates diff --git a/src/hotspot/share/prims/jvmtiExtensions.cpp b/src/hotspot/share/prims/jvmtiExtensions.cpp index c1767454227..ec6c6689673 100644 --- a/src/hotspot/share/prims/jvmtiExtensions.cpp +++ b/src/hotspot/share/prims/jvmtiExtensions.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,6 +130,10 @@ static jvmtiError JNICALL GetCarrierThread(const jvmtiEnv* env, ...) { thread_ptr = va_arg(ap, jthread*); va_end(ap); + if (thread_ptr == nullptr) { + return JVMTI_ERROR_NULL_POINTER; + } + MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, current_thread)); ThreadInVMfromNative tiv(current_thread); JvmtiVTMSTransitionDisabler disabler; @@ -156,12 +160,11 @@ static jvmtiError JNICALL GetCarrierThread(const jvmtiEnv* env, ...) { if (!java_lang_VirtualThread::is_instance(vthread_oop)) { return JVMTI_ERROR_INVALID_THREAD; } - if (thread_ptr == nullptr) { - return JVMTI_ERROR_NULL_POINTER; - } - VirtualThreadGetThreadClosure op(Handle(current_thread, vthread_oop), thread_ptr); - Handshake::execute(&op, &tlh, current_thread); - return op.result(); + + oop carrier_thread = java_lang_VirtualThread::carrier_thread(vthread_oop); + *thread_ptr = (jthread)JNIHandles::make_local(current_thread, carrier_thread); + + return JVMTI_ERROR_NONE; } // register extension functions and events. In this implementation we From da3001daf79bf943d6194d9fd60250d519b9680d Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 24 May 2024 01:16:43 +0000 Subject: [PATCH 22/99] 8331975: Enable case-insensitive check in ccache and keytab entry lookup Reviewed-by: mpowers, valeriep --- .../share/conf/security/java.security | 20 ++++ .../sun/security/krb5/PrincipalName.java | 48 +++++--- .../sun/security/krb5/auto/CaseSensitive.java | 108 ++++++++++++++++++ test/jdk/sun/security/krb5/auto/KDC.java | 28 +++-- 4 files changed, 178 insertions(+), 26 deletions(-) create mode 100644 test/jdk/sun/security/krb5/auto/CaseSensitive.java diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 4c0f4cda13d..5188362033d 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1515,3 +1515,23 @@ jdk.tls.alpnCharset=ISO_8859_1 # # [1] https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-sfu/bde93b0e-f3c9-4ddf-9f44-e1453be7af5a #jdk.security.krb5.s4u2proxy.acceptNonForwardableServiceTicket=false + +# +# Policy for name comparison in keytab and ccache entry lookup +# +# When looking up a keytab or credentials cache (ccache) entry for a Kerberos +# principal, the principal name is compared with the name in the entry. +# The comparison is by default case-insensitive. However, many Kerberos +# implementations consider principal names to be case-sensitive. Consequently, +# if two principals have names that differ only in case, there is a risk that +# an incorrect keytab or ccache entry might be selected. +# +# If this security property is set to "true", the comparison of principal +# names at keytab and ccache entry lookup is case-sensitive. +# +# The default value is "false". +# +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# +#jdk.security.krb5.name.case.sensitive=false diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java b/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java index d11c96a6613..130f2c23f86 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/PrincipalName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, 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 @@ -109,6 +109,12 @@ public class PrincipalName implements Cloneable { public static final String NAME_REALM_SEPARATOR_STR = "@"; public static final String REALM_COMPONENT_SEPARATOR_STR = "."; + private static final boolean NAME_CASE_SENSITIVE_IN_MATCH + = "true".equalsIgnoreCase( + SecurityProperties.privilegedGetOverridable( + "jdk.security.krb5.name.case.sensitive")); + + // Instance fields. /** @@ -607,33 +613,47 @@ public byte[] asn1Encode() throws Asn1Exception, IOException { /** - * Checks if two PrincipalName objects have identical values in their corresponding data fields. + * Checks if two PrincipalName objects have identical values + * in their corresponding data fields. + *

    + * If {@systemProperty jdk.security.krb5.name.case.sensitive} is set to true, + * the name comparison is case-sensitive. Otherwise, it's case-insensitive. + *

    + * It is used in {@link sun.security.krb5.internal.ccache.FileCredentialsCache} + * and {@link sun.security.krb5.internal.ktab.KeyTab} to retrieve ccache + * or keytab entry for a principal. * * @param pname the other PrincipalName object. * @return true if two have identical values, otherwise, return false. */ - // It is used in sun.security.krb5.internal.ccache package. public boolean match(PrincipalName pname) { - boolean matched = true; - //name type is just a hint, no two names can be the same ignoring name type. - // if (this.nameType != pname.nameType) { - // matched = false; - // } - if ((this.nameRealm != null) && (pname.nameRealm != null)) { + // No need to check name type. It's just a hint, no two names can be + // the same ignoring name type. + if (NAME_CASE_SENSITIVE_IN_MATCH) { + if (!(this.nameRealm.toString().equals(pname.nameRealm.toString()))) { + return false; + } + } else { if (!(this.nameRealm.toString().equalsIgnoreCase(pname.nameRealm.toString()))) { - matched = false; + return false; } } if (this.nameStrings.length != pname.nameStrings.length) { - matched = false; + return false; } else { for (int i = 0; i < this.nameStrings.length; i++) { - if (!(this.nameStrings[i].equalsIgnoreCase(pname.nameStrings[i]))) { - matched = false; + if (NAME_CASE_SENSITIVE_IN_MATCH) { + if (!(this.nameStrings[i].equals(pname.nameStrings[i]))) { + return false; + } + } else { + if (!(this.nameStrings[i].equalsIgnoreCase(pname.nameStrings[i]))) { + return false; + } } } } - return matched; + return true; } /** diff --git a/test/jdk/sun/security/krb5/auto/CaseSensitive.java b/test/jdk/sun/security/krb5/auto/CaseSensitive.java new file mode 100644 index 00000000000..365d8c6c6f0 --- /dev/null +++ b/test/jdk/sun/security/krb5/auto/CaseSensitive.java @@ -0,0 +1,108 @@ +/* + * 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 8331975 + * @summary ensure correct name comparison when a system property is set + * @library /test/lib + * @compile -XDignore.symbol.file CaseSensitive.java + * @run main jdk.test.lib.FileInstaller TestHosts TestHosts + * @run main/othervm -Djdk.net.hosts.file=TestHosts CaseSensitive no + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.security.krb5.name.case.sensitive=true CaseSensitive yes + */ + +import jdk.test.lib.Asserts; +import org.ietf.jgss.GSSException; +import sun.security.jgss.GSSUtil; + +public class CaseSensitive { + + public static void main(String[] args) throws Exception { + switch (args[0]) { + case "yes" -> testSensitive(); + case "no" -> testInsensitive(); + } + } + + static void testSensitive() throws Exception { + var kdc = new OneKDC(null).writeJAASConf(); + kdc.addPrincipal("hello", "password".toCharArray()); + kdc.writeKtab(OneKDC.KTAB); + + Context c = Context.fromJAAS("client"); + Context s = Context.fromJAAS("com.sun.security.jgss.krb5.accept"); + + // There is only "hello". Cannot talk to "HELLO" + c.startAsClient("HELLO", GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + try { + Context.handshake(c, s); + throw new RuntimeException("Should not succeed"); + } catch(GSSException ge) { + System.out.println(ge.getMessage()); + System.out.println("No HELLO in db. Expected"); + } + + // Add "HELLO". Can talk to "HELLO" now. + kdc.addPrincipal("HELLO", "different".toCharArray()); + kdc.writeKtab(OneKDC.KTAB); + + c.startAsClient("HELLO", GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + // Name could be partial without realm, so only compare the beginning + Asserts.assertTrue(c.x().getTargName().toString().startsWith("HELLO"), + c.x().getTargName().toString()); + Asserts.assertTrue(s.x().getTargName().toString().startsWith("HELLO"), + s.x().getTargName().toString()); + + // Can also talk to "hello", which has a different password. + c.startAsClient("hello", GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + Asserts.assertTrue(c.x().getTargName().toString().startsWith("hello"), + c.x().getTargName().toString()); + Asserts.assertTrue(s.x().getTargName().toString().startsWith("hello"), + s.x().getTargName().toString()); + } + + static void testInsensitive() throws Exception { + var kdc = new OneKDC(null).writeJAASConf(); + kdc.addPrincipal("hello", "password".toCharArray()); + kdc.writeKtab(OneKDC.KTAB); + + Context c = Context.fromJAAS("client"); + Context s = Context.fromJAAS("com.sun.security.jgss.krb5.accept"); + + // There is only "hello" but we can talk to "HELLO". + c.startAsClient("HELLO", GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + Context.handshake(c, s); + Asserts.assertTrue(c.x().getTargName().toString().startsWith("HELLO"), + c.x().getTargName().toString()); + Asserts.assertTrue(s.x().getTargName().toString().startsWith("HELLO"), + s.x().getTargName().toString()); + } +} diff --git a/test/jdk/sun/security/krb5/auto/KDC.java b/test/jdk/sun/security/krb5/auto/KDC.java index 6e4bfba61f4..bb744281eb9 100644 --- a/test/jdk/sun/security/krb5/auto/KDC.java +++ b/test/jdk/sun/security/krb5/auto/KDC.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 @@ -143,6 +143,9 @@ public class KDC { private static final String SUPPORTED_ETYPES = System.getProperty("kdc.supported.enctypes"); + private static final boolean NAME_CASE_SENSITIVE + = Boolean.getBoolean("jdk.security.krb5.name.case.sensitive"); + // The native KDC private final NativeKdc nativeKdc; @@ -154,27 +157,28 @@ public class KDC { // Principal db. principal -> pass. A case-insensitive TreeMap is used // so that even if the client provides a name with different case, the KDC // can still locate the principal and give back correct salt. - private TreeMap passwords = new TreeMap<> - (String.CASE_INSENSITIVE_ORDER); + private TreeMap passwords = newTreeMap(); // Non default salts. Precisely, there should be different salts for // different etypes, pretend they are the same at the moment. - private TreeMap salts = new TreeMap<> - (String.CASE_INSENSITIVE_ORDER); + private TreeMap salts = newTreeMap(); // Non default s2kparams for newer etypes. Precisely, there should be // different s2kparams for different etypes, pretend they are the same // at the moment. - private TreeMap s2kparamses = new TreeMap<> - (String.CASE_INSENSITIVE_ORDER); + private TreeMap s2kparamses = newTreeMap(); // Alias for referrals. - private TreeMap aliasReferrals = new TreeMap<> - (String.CASE_INSENSITIVE_ORDER); + private TreeMap aliasReferrals = newTreeMap(); // Alias for local resolution. - private TreeMap alias2Principals = new TreeMap<> - (String.CASE_INSENSITIVE_ORDER); + private TreeMap alias2Principals = newTreeMap(); + + private static TreeMap newTreeMap() { + return NAME_CASE_SENSITIVE + ? new TreeMap<>() + : new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + } // Realm name private String realm; @@ -354,7 +358,7 @@ public void writeKtab(String tab, boolean append, String... names) } if (nativeKdc == null) { char[] pass = passwords.get(name); - int kvno = 0; + int kvno = -1; // always create new keys if (Character.isDigit(pass[pass.length - 1])) { kvno = pass[pass.length - 1] - '0'; } From af056c1676dab3b0b35666a8259db60f9bbf824e Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Fri, 24 May 2024 06:27:45 +0000 Subject: [PATCH 23/99] 8332106: VerifyError when using switch pattern in this(...) or super(...) Reviewed-by: abimpoudis, vromero --- .../classes/com/sun/tools/javac/jvm/Gen.java | 65 ++- .../com/sun/tools/javac/tree/TreeInfo.java | 10 + .../patterns/UninitializedThisException.java | 390 ++++++++++++++++++ 3 files changed, 450 insertions(+), 15 deletions(-) create mode 100644 test/langtools/tools/javac/patterns/UninitializedThisException.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index 37846b8b966..b9bfe587c6c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -172,8 +172,8 @@ protected Gen(Context context) { Chain switchExpressionFalseChain; List stackBeforeSwitchExpression; LocalItem switchResult; - Set invocationsWithPatternMatchingCatch = Set.of(); - ListBuffer patternMatchingInvocationRanges; + PatternMatchingCatchConfiguration patternMatchingCatchConfiguration = + new PatternMatchingCatchConfiguration(Set.of(), null, null, null); /** Cache the symbol to reflect the qualifying type. * key: corresponding type @@ -1087,21 +1087,31 @@ public void visitBlock(JCBlock tree) { } private void visitBlockWithPatterns(JCBlock tree) { - Set prevInvocationsWithPatternMatchingCatch = invocationsWithPatternMatchingCatch; - ListBuffer prevRanges = patternMatchingInvocationRanges; - State startState = code.state.dup(); + PatternMatchingCatchConfiguration prevConfiguration = patternMatchingCatchConfiguration; try { - invocationsWithPatternMatchingCatch = tree.patternMatchingCatch.calls2Handle(); - patternMatchingInvocationRanges = new ListBuffer<>(); + patternMatchingCatchConfiguration = + new PatternMatchingCatchConfiguration(tree.patternMatchingCatch.calls2Handle(), + new ListBuffer(), + tree.patternMatchingCatch.handler(), + code.state.dup()); internalVisitBlock(tree); } finally { + generatePatternMatchingCatch(env); + patternMatchingCatchConfiguration = prevConfiguration; + } + } + + private void generatePatternMatchingCatch(Env env) { + if (patternMatchingCatchConfiguration.handler != null && + !patternMatchingCatchConfiguration.ranges.isEmpty()) { Chain skipCatch = code.branch(goto_); - JCCatch handler = tree.patternMatchingCatch.handler(); - code.entryPoint(startState, handler.param.sym.type); - genPatternMatchingCatch(handler, env, patternMatchingInvocationRanges.toList()); + JCCatch handler = patternMatchingCatchConfiguration.handler(); + code.entryPoint(patternMatchingCatchConfiguration.startState(), + handler.param.sym.type); + genPatternMatchingCatch(handler, + env, + patternMatchingCatchConfiguration.ranges.toList()); code.resolve(skipCatch); - invocationsWithPatternMatchingCatch = prevInvocationsWithPatternMatchingCatch; - patternMatchingInvocationRanges = prevRanges; } } @@ -1926,12 +1936,26 @@ public void visitApply(JCMethodInvocation tree) { if (!msym.isDynamic()) { code.statBegin(tree.pos); } - if (invocationsWithPatternMatchingCatch.contains(tree)) { + if (patternMatchingCatchConfiguration.invocations().contains(tree)) { int start = code.curCP(); result = m.invoke(); - patternMatchingInvocationRanges.add(new int[] {start, code.curCP()}); + patternMatchingCatchConfiguration.ranges().add(new int[] {start, code.curCP()}); } else { - result = m.invoke(); + if (msym.isConstructor() && TreeInfo.isConstructorCall(tree)) { + //if this is a this(...) or super(...) call, there is a pending + //"uninitialized this" before this call. One catch handler cannot + //handle exceptions that may come from places with "uninitialized this" + //and (initialized) this, hence generate one set of handlers here + //for the "uninitialized this" case, and another set of handlers + //will be generated at the end of the method for the initialized this, + //if needed: + generatePatternMatchingCatch(env); + result = m.invoke(); + patternMatchingCatchConfiguration = + patternMatchingCatchConfiguration.restart(code.state.dup()); + } else { + result = m.invoke(); + } } } @@ -2555,4 +2579,15 @@ void addCont(Chain c) { } } + record PatternMatchingCatchConfiguration(Set invocations, + ListBuffer ranges, + JCCatch handler, + State startState) { + public PatternMatchingCatchConfiguration restart(State newState) { + return new PatternMatchingCatchConfiguration(invocations(), + new ListBuffer(), + handler(), + newState); + } + } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index 54917c90dc2..f2edd5c97e9 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -303,6 +303,16 @@ public void visitLambda(JCLambda tree) { } } + /** + * Is the given method invocation an invocation of this(...) or super(...)? + */ + public static boolean isConstructorCall(JCMethodInvocation invoke) { + Name name = TreeInfo.name(invoke.meth); + Names names = name.table.names; + + return (name == names._this || name == names._super); + } + /** Finds super() invocations and translates them using the given mapping. */ public static void mapSuperCalls(JCBlock block, Function mapper) { diff --git a/test/langtools/tools/javac/patterns/UninitializedThisException.java b/test/langtools/tools/javac/patterns/UninitializedThisException.java new file mode 100644 index 00000000000..b0acba4e1b1 --- /dev/null +++ b/test/langtools/tools/javac/patterns/UninitializedThisException.java @@ -0,0 +1,390 @@ +/* + * 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 8332106 + * @summary Verify the synthetic catch clauses are generated correctly for constructors + * @enablePreview + * @compile UninitializedThisException.java + * @run main UninitializedThisException + */ + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Objects; +import java.util.function.Supplier; + +public class UninitializedThisException extends Base { + + public UninitializedThisException(String s1, String s2) { + super(s1, s2); + } + + public UninitializedThisException(R o1, R o2, R o3) { + out.println("-pre(" + o1.fail() + ")" + + "-nest(" + o2.fail() + ")" + + "-post(" + o3.fail() + ")"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + this(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, R o2, R o3) { + out.println("-nest(" + o2.fail() + ")" + + "-post(" + o3.fail() + ")"); + String val1 = o1; + out.println("check1"); + this(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, String o2, R o3) { + out.println("-pre(" + o1.fail() + ")" + + "-post(" + o3.fail() + ")"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + this(val1, o2); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, R o2, String o3) { + out.println("-pre(" + o1.fail() + ")" + + "-nest(" + o2.fail() + ")"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + this(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, String o2, String o3) { + out.println("-pre(" + o1.fail() + ")"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + this(val1, o2); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, R o2, String o3) { + out.println("-nest(" + o2.fail() + ")"); + String val1 = o1; + out.println("check1"); + this(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, String o2, R o3) { + out.println("-post(" + o3.fail() + ")"); + String val1 = o1; + out.println("check1"); + this(val1, o2); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, R o2, R o3, boolean superMarker) { + out.println("-pre(" + o1.fail() + ")" + + "-nest(" + o2.fail() + ")" + + "-post(" + o3.fail() + ")" + + "-super"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + super(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, R o2, R o3, boolean superMarker) { + out.println("-nest(" + o2.fail() + ")" + + "-post(" + o3.fail() + ")" + + "-super"); + String val1 = o1; + out.println("check1"); + super(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, String o2, R o3, boolean superMarker) { + out.println("-pre(" + o1.fail() + ")" + + "-post(" + o3.fail() + ")" + + "-super"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + super(val1, o2); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, R o2, String o3, boolean superMarker) { + out.println("-pre(" + o1.fail() + ")" + + "-nest(" + o2.fail() + ")" + + "-super"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + super(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(R o1, String o2, String o3, boolean superMarker) { + out.println("-pre(" + o1.fail() + ")" + + "-super"); + String val1 = o1 instanceof R(String s, _) ? s : null; + out.println("check1"); + super(val1, o2); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, R o2, String o3, boolean superMarker) { + out.println("-nest(" + o2.fail() + ")" + + "-super"); + String val1 = o1; + out.println("check1"); + super(val1, o2 instanceof R(String s, _) ? s : null); + out.println("check2"); + String val2 = o3; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public UninitializedThisException(String o1, String o2, R o3, boolean superMarker) { + out.println("-post(" + o3.fail() + ")" + + "-super"); + String val1 = o1; + out.println("check1"); + super(val1, o2); + out.println("check2"); + String val2 = o3 instanceof R(String s, _) ? s : null; + out.println("check3"); + Objects.requireNonNull(val2); + } + + public static void main(String... args) { + runAndCatch(() -> new UninitializedThisException(new R("", true), new R("", false), new R("", false))); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", true), new R("", false))); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", false), new R("", true))); + new UninitializedThisException(new R("", false), new R("", false), new R("", false)); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", new R("", true), new R("", false))); + runAndCatch(() -> new UninitializedThisException("", new R("", false), new R("", true))); + new UninitializedThisException("", new R("", false), new R("", false)); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), "", new R("", false))); + runAndCatch(() -> new UninitializedThisException(new R("", false), "", new R("", true))); + new UninitializedThisException(new R("", false), "", new R("", false)); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), new R("", false), "")); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", true), "")); + new UninitializedThisException(new R("", false), new R("", false), ""); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), "", "")); + new UninitializedThisException(new R("", false), "", ""); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", new R("", true), "")); + new UninitializedThisException("", new R("", false), ""); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", "", new R("", true))); + new UninitializedThisException("", "", new R("", false)); + + runAndCatch(() -> new UninitializedThisException(new R("", true), new R("", false), new R("", false), true)); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", true), new R("", false), true)); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", false), new R("", true), true)); + new UninitializedThisException(new R("", false), new R("", false), new R("", false), true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", new R("", true), new R("", false), true)); + runAndCatch(() -> new UninitializedThisException("", new R("", false), new R("", true), true)); + new UninitializedThisException("", new R("", false), new R("", false), true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), "", new R("", false), true)); + runAndCatch(() -> new UninitializedThisException(new R("", false), "", new R("", true), true)); + new UninitializedThisException(new R("", false), "", new R("", false), true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), new R("", false), "", true)); + runAndCatch(() -> new UninitializedThisException(new R("", false), new R("", true), "", true)); + new UninitializedThisException(new R("", false), new R("", false), "", true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException(new R("", true), "", "", true)); + new UninitializedThisException(new R("", false), "", "", true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", new R("", true), "", true)); + new UninitializedThisException("", new R("", false), "", true); + + out.println(); + + runAndCatch(() -> new UninitializedThisException("", "", new R("", true), true)); + new UninitializedThisException("", "", new R("", false), true); + + String actualLog = log.toString().replaceAll("\\R", "\n"); + String expectedLog = EXPECTED_LOG_PATTERN.replace("${super}", "") + + EXPECTED_LOG_PATTERN.replace("${super}", "-super"); + + if (!Objects.equals(actualLog, expectedLog)) { + throw new AssertionError("Expected log:\n" + expectedLog + + ", but got: " + actualLog); + } + } + + static final String EXPECTED_LOG_PATTERN = + """ + -pre(true)-nest(false)-post(false)${super} + -pre(false)-nest(true)-post(false)${super} + check1 + -pre(false)-nest(false)-post(true)${super} + check1 + check2 + -pre(false)-nest(false)-post(false)${super} + check1 + check2 + check3 + + -nest(true)-post(false)${super} + check1 + -nest(false)-post(true)${super} + check1 + check2 + -nest(false)-post(false)${super} + check1 + check2 + check3 + + -pre(true)-post(false)${super} + -pre(false)-post(true)${super} + check1 + check2 + -pre(false)-post(false)${super} + check1 + check2 + check3 + + -pre(true)-nest(false)${super} + -pre(false)-nest(true)${super} + check1 + -pre(false)-nest(false)${super} + check1 + check2 + check3 + + -pre(true)${super} + -pre(false)${super} + check1 + check2 + check3 + + -nest(true)${super} + check1 + -nest(false)${super} + check1 + check2 + check3 + + -post(true)${super} + check1 + check2 + -post(false)${super} + check1 + check2 + check3 + """; + + static final StringWriter log = new StringWriter(); + static final PrintWriter out = new PrintWriter(log); + + static void runAndCatch(Supplier toRun) { + try { + toRun.get(); + throw new AssertionError("Didn't get the expected exception!"); + } catch (MatchException ex) { + //OK + } + } + record R(String s, boolean fail) { + public String s() { + if (fail) { + throw new NullPointerException(); + } else { + return s; + } + } + } +} +class Base { + public Base(String s1, String s2) { + Objects.requireNonNull(s1); + Objects.requireNonNull(s2); + } +} From a71b40478510db3c69696df608fd1b32f41c57f3 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 24 May 2024 07:12:12 +0000 Subject: [PATCH 24/99] 8331398: G1: G1HeapRegionPrinter reclamation events should print the original region type Reviewed-by: ayang, iwalulya, gli --- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 4 +- .../share/gc/g1/g1HeapRegionPrinter.cpp | 38 ------------------- .../share/gc/g1/g1HeapRegionPrinter.hpp | 6 +-- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 4 +- 4 files changed, 5 insertions(+), 47 deletions(-) delete mode 100644 src/hotspot/share/gc/g1/g1HeapRegionPrinter.cpp diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 804f255217f..e3ab84e9555 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -1247,6 +1247,7 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { hr->set_containing_set(nullptr); hr->clear_cardtable(); _g1h->concurrent_mark()->clear_statistics(hr); + G1HeapRegionPrinter::mark_reclaim(hr); _g1h->free_humongous_region(hr, _local_cleanup_list); }; @@ -1263,6 +1264,7 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { hr->set_containing_set(nullptr); hr->clear_cardtable(); _g1h->concurrent_mark()->clear_statistics(hr); + G1HeapRegionPrinter::mark_reclaim(hr); _g1h->free_region(hr, _local_cleanup_list); } @@ -1317,8 +1319,6 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { ~G1UpdateRegionLivenessAndSelectForRebuildTask() { if (!_cleanup_list.is_empty()) { log_debug(gc)("Reclaimed %u empty regions", _cleanup_list.length()); - // Now print the empty regions list. - G1HeapRegionPrinter::mark_reclaim(&_cleanup_list); // And actually make them available. _g1h->prepend_to_freelist(&_cleanup_list); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.cpp b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.cpp deleted file mode 100644 index 1c87b800601..00000000000 --- a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -#include "precompiled.hpp" - -#include "gc/g1/g1HeapRegionPrinter.hpp" -#include "gc/g1/g1HeapRegionSet.hpp" - -void G1HeapRegionPrinter::mark_reclaim(FreeRegionList* cleanup_list) { - if (is_active()) { - FreeRegionListIterator iter(cleanup_list); - while (iter.more_available()) { - HeapRegion* hr = iter.get_next(); - mark_reclaim(hr); - } - } -} diff --git a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp index 20a6e795da0..ed6d171fb6f 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp @@ -39,10 +39,6 @@ class G1HeapRegionPrinter : public AllStatic { action, hr->get_type_str(), p2i(hr->bottom()), p2i(hr->top()), p2i(hr->end())); } - static void mark_reclaim(HeapRegion* hr) { - print("MARK-RECLAIM", hr); - } - public: // In some places we iterate over a list in order to generate output // for the list's elements. By exposing this we can avoid this @@ -61,7 +57,7 @@ class G1HeapRegionPrinter : public AllStatic { static void evac_failure(HeapRegion* hr) { print("EVAC-FAILURE", hr); } - static void mark_reclaim(FreeRegionList* free_list); + static void mark_reclaim(HeapRegion* hr) { print("MARK-RECLAIM", hr); } static void eager_reclaim(HeapRegion* hr) { print("EAGER-RECLAIM", hr); } diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 288abc87be9..ac1a758a709 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -412,8 +412,8 @@ class G1FreeHumongousRegionClosure : public HeapRegionIndexClosure { _freed_bytes += r->used(); r->set_containing_set(nullptr); _humongous_regions_reclaimed++; - _g1h->free_humongous_region(r, nullptr); G1HeapRegionPrinter::eager_reclaim(r); + _g1h->free_humongous_region(r, nullptr); }; _g1h->humongous_obj_regions_iterate(r, free_humongous_region); @@ -759,9 +759,9 @@ class FreeCSetClosure : public HeapRegionClosure { assert(!r->is_empty(), "Region %u is an empty region in the collection set.", r->hrm_index()); stats()->account_evacuated_region(r); + G1HeapRegionPrinter::evac_reclaim(r); // Free the region and its remembered set. _g1h->free_region(r, nullptr); - G1HeapRegionPrinter::evac_reclaim(r); } void handle_failed_region(HeapRegion* r) { From 9b61a7608efff13fc3685488f3f54a810ec0ac22 Mon Sep 17 00:00:00 2001 From: Gui Cao Date: Fri, 24 May 2024 07:12:22 +0000 Subject: [PATCH 25/99] 8332615: RISC-V: Support vector unsigned comparison instructions for machines with RVV Reviewed-by: fyang --- src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp | 4 ++++ src/hotspot/cpu/riscv/matcher_riscv.hpp | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 2468bf70fe5..dd9a9974f1b 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -2762,6 +2762,10 @@ void C2_MacroAssembler::compare_integral_v(VectorRegister vd, VectorRegister src case BoolTest::ge: vmsge_vv(vd, src1, src2, vm); break; case BoolTest::lt: vmslt_vv(vd, src1, src2, vm); break; case BoolTest::gt: vmsgt_vv(vd, src1, src2, vm); break; + case BoolTest::ule: vmsleu_vv(vd, src1, src2, vm); break; + case BoolTest::uge: vmsgeu_vv(vd, src1, src2, vm); break; + case BoolTest::ult: vmsltu_vv(vd, src1, src2, vm); break; + case BoolTest::ugt: vmsgtu_vv(vd, src1, src2, vm); break; default: assert(false, "unsupported compare condition"); ShouldNotReachHere(); diff --git a/src/hotspot/cpu/riscv/matcher_riscv.hpp b/src/hotspot/cpu/riscv/matcher_riscv.hpp index 2fa6e8c80ca..d1e10c34939 100644 --- a/src/hotspot/cpu/riscv/matcher_riscv.hpp +++ b/src/hotspot/cpu/riscv/matcher_riscv.hpp @@ -148,8 +148,8 @@ } // Does the CPU supports vector unsigned comparison instructions? - static constexpr bool supports_vector_comparison_unsigned(int vlen, BasicType bt) { - return false; + static bool supports_vector_comparison_unsigned(int vlen, BasicType bt) { + return UseRVV; } // Some microarchitectures have mask registers used on vectors From 239c1b33b47de43369673f33d9449e1904477ce0 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 24 May 2024 07:29:22 +0000 Subject: [PATCH 26/99] 8332807: Parallel: Make some APIs in ParMarkBitMap private Reviewed-by: tschatzl --- .../share/gc/parallel/parMarkBitMap.hpp | 54 +++++++++---------- .../gc/parallel/parMarkBitMap.inline.hpp | 11 +--- 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp index 1975f1e3221..63c4d4e7185 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp @@ -29,9 +29,7 @@ #include "oops/oop.hpp" #include "utilities/bitMap.hpp" -class ParMarkBitMapClosure; class PSVirtualSpace; -class ParCompactionManager; class ParMarkBitMap: public CHeapObj { @@ -54,35 +52,15 @@ class ParMarkBitMap: public CHeapObj inline bool is_marked(HeapWord* addr) const; inline bool is_marked(oop obj) const; - inline bool is_unmarked(idx_t bit) const; inline bool is_unmarked(HeapWord* addr) const; inline bool is_unmarked(oop obj) const; - // Convert sizes from bits to HeapWords and back. An object that is n bits - // long will be bits_to_words(n) words long. An object that is m words long - // will take up words_to_bits(m) bits in the bitmap. - inline static size_t bits_to_words(idx_t bits); - inline static idx_t words_to_bits(size_t words); - - inline HeapWord* region_start() const; - inline HeapWord* region_end() const; - inline size_t region_size() const; - inline size_t size() const; - size_t reserved_byte_size() const { return _reserved_byte_size; } // Convert a heap address to/from a bit index. inline idx_t addr_to_bit(HeapWord* addr) const; inline HeapWord* bit_to_addr(idx_t bit) const; - // Return word-aligned up range_end, which must not be greater than size(). - inline idx_t align_range_end(idx_t range_end) const; - - // Return the bit index of the first marked object that begins (or ends, - // respectively) in the range [beg, end). If no object is found, return end. - // end must be word-aligned. - inline idx_t find_obj_beg(idx_t beg, idx_t end) const; - inline HeapWord* find_obj_beg(HeapWord* beg, HeapWord* end) const; // Return the address of the last obj-start in the range [beg, end). If no @@ -92,11 +70,6 @@ class ParMarkBitMap: public CHeapObj // cleared). inline void clear_range(idx_t beg, idx_t end); - // Return the number of bits required to represent the specified number of - // HeapWords, or the specified region. - static inline idx_t bits_required(size_t words); - static inline idx_t bits_required(MemRegion covered_region); - void print_on_error(outputStream* st) const { st->print_cr("Marking Bits: (ParMarkBitMap*) " PTR_FORMAT, p2i(this)); _beg_bits.print_on_error(st, " Begin Bits: "); @@ -104,8 +77,6 @@ class ParMarkBitMap: public CHeapObj #ifdef ASSERT void verify_clear() const; - inline void verify_bit(idx_t bit) const; - inline void verify_addr(HeapWord* addr) const; #endif // #ifdef ASSERT private: @@ -113,7 +84,6 @@ class ParMarkBitMap: public CHeapObj // Each bit in the bitmap represents one unit of 'object granularity.' Objects // are double-word aligned in 32-bit VMs, but not in 64-bit VMs, so the 32-bit // granularity is 2, 64-bit is 1. - static inline size_t obj_granularity() { return size_t(MinObjAlignment); } static inline int obj_granularity_shift() { return LogMinObjAlignment; } HeapWord* _region_start; @@ -121,6 +91,30 @@ class ParMarkBitMap: public CHeapObj BitMapView _beg_bits; PSVirtualSpace* _virtual_space; size_t _reserved_byte_size; + + // Return the number of bits required to represent the specified number of + // HeapWords, or the specified region. + static inline idx_t bits_required(size_t words); + static inline idx_t bits_required(MemRegion covered_region); + + // Convert sizes from bits to HeapWords and back. An object that is n bits + // long will be bits_to_words(n) words long. An object that is m words long + // will take up words_to_bits(m) bits in the bitmap. + inline static size_t bits_to_words(idx_t bits); + inline static idx_t words_to_bits(size_t words); + + // Return word-aligned up range_end, which must not be greater than size(). + inline idx_t align_range_end(idx_t range_end) const; + + inline HeapWord* region_start() const; + inline HeapWord* region_end() const; + inline size_t region_size() const; + inline size_t size() const; + +#ifdef ASSERT + inline void verify_bit(idx_t bit) const; + inline void verify_addr(HeapWord* addr) const; +#endif // #ifdef ASSERT }; #endif // SHARE_GC_PARALLEL_PARMARKBITMAP_HPP diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp index 98c2fcc1981..6d4aba8e36f 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp @@ -74,10 +74,6 @@ inline bool ParMarkBitMap::is_marked(oop obj) const { return is_marked(cast_from_oop(obj)); } -inline bool ParMarkBitMap::is_unmarked(idx_t bit) const { - return !is_marked(bit); -} - inline bool ParMarkBitMap::is_unmarked(HeapWord* addr) const { return !is_marked(addr); } @@ -118,15 +114,12 @@ inline ParMarkBitMap::idx_t ParMarkBitMap::align_range_end(idx_t range_end) cons return align_up(range_end, BitsPerWord); } -inline ParMarkBitMap::idx_t ParMarkBitMap::find_obj_beg(idx_t beg, idx_t end) const { - return _beg_bits.find_first_set_bit_aligned_right(beg, end); -} - inline HeapWord* ParMarkBitMap::find_obj_beg(HeapWord* beg, HeapWord* end) const { const idx_t beg_bit = addr_to_bit(beg); const idx_t end_bit = addr_to_bit(end); const idx_t search_end = align_range_end(end_bit); - const idx_t res_bit = MIN2(find_obj_beg(beg_bit, search_end), end_bit); + const idx_t res_bit = MIN2(_beg_bits.find_first_set_bit_aligned_right(beg_bit, search_end), + end_bit); return bit_to_addr(res_bit); } From 5a2ba952b120394d7cc0d0890619780c1c27a078 Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Fri, 24 May 2024 11:55:46 +0000 Subject: [PATCH 27/99] 8325841: Remove unused references to vmSymbols.hpp Reviewed-by: kvn, coleenp --- src/hotspot/share/classfile/vmSymbols.hpp | 55 ----------------------- src/hotspot/share/opto/macro.cpp | 3 +- 2 files changed, 1 insertion(+), 57 deletions(-) diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index f79af705f0b..39340243bc4 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -58,7 +58,6 @@ class SerializeClosure; template(java_lang_System, "java/lang/System") \ template(java_lang_Object, "java/lang/Object") \ template(java_lang_Class, "java/lang/Class") \ - template(java_lang_Package, "java/lang/Package") \ template(java_lang_Module, "java/lang/Module") \ template(java_lang_String, "java/lang/String") \ template(java_lang_StringLatin1, "java/lang/StringLatin1") \ @@ -118,7 +117,6 @@ class SerializeClosure; template(java_lang_reflect_RecordComponent, "java/lang/reflect/RecordComponent") \ template(java_lang_StringBuffer, "java/lang/StringBuffer") \ template(java_lang_StringBuilder, "java/lang/StringBuilder") \ - template(java_lang_CharSequence, "java/lang/CharSequence") \ template(java_lang_SecurityManager, "java/lang/SecurityManager") \ template(java_lang_ScopedValue, "java/lang/ScopedValue") \ template(java_lang_ScopedValue_Carrier, "java/lang/ScopedValue$Carrier") \ @@ -131,28 +129,16 @@ class SerializeClosure; template(java_net_URL, "java/net/URL") \ template(java_net_URLClassLoader, "java/net/URLClassLoader") \ template(java_util_jar_Manifest, "java/util/jar/Manifest") \ - template(java_io_OutputStream, "java/io/OutputStream") \ - template(java_io_Reader, "java/io/Reader") \ - template(java_io_BufferedReader, "java/io/BufferedReader") \ - template(java_io_File, "java/io/File") \ - template(java_io_FileInputStream, "java/io/FileInputStream") \ template(java_io_ByteArrayInputStream, "java/io/ByteArrayInputStream") \ template(java_io_Serializable, "java/io/Serializable") \ template(java_nio_Buffer, "java/nio/Buffer") \ template(java_util_Arrays, "java/util/Arrays") \ - template(java_util_Objects, "java/util/Objects") \ template(java_util_Properties, "java/util/Properties") \ - template(java_util_Vector, "java/util/Vector") \ - template(java_util_AbstractList, "java/util/AbstractList") \ - template(java_util_Hashtable, "java/util/Hashtable") \ template(java_util_DualPivotQuicksort, "java/util/DualPivotQuicksort") \ - template(java_lang_Compiler, "java/lang/Compiler") \ template(jdk_internal_misc_Signal, "jdk/internal/misc/Signal") \ template(jdk_internal_util_Preconditions, "jdk/internal/util/Preconditions") \ template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \ - template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ template(jdk_internal_vm_PostVMInitHook, "jdk/internal/vm/PostVMInitHook") \ - template(sun_net_www_ParseUtil, "sun/net/www/ParseUtil") \ template(java_util_Iterator, "java/util/Iterator") \ template(java_lang_Record, "java/lang/Record") \ template(sun_instrument_InstrumentationImpl, "sun/instrument/InstrumentationImpl") \ @@ -227,7 +213,6 @@ class SerializeClosure; template(java_lang_BootstrapMethodError, "java/lang/BootstrapMethodError") \ template(java_lang_LinkageError, "java/lang/LinkageError") \ template(java_lang_NegativeArraySizeException, "java/lang/NegativeArraySizeException") \ - template(java_lang_NoSuchFieldException, "java/lang/NoSuchFieldException") \ template(java_lang_NoSuchMethodException, "java/lang/NoSuchMethodException") \ template(java_lang_NullPointerException, "java/lang/NullPointerException") \ template(java_lang_StringIndexOutOfBoundsException, "java/lang/StringIndexOutOfBoundsException")\ @@ -237,7 +222,6 @@ class SerializeClosure; template(java_lang_Exception, "java/lang/Exception") \ template(java_lang_RuntimeException, "java/lang/RuntimeException") \ template(java_io_IOException, "java/io/IOException") \ - template(java_security_PrivilegedActionException, "java/security/PrivilegedActionException") \ \ /* error klasses: at least all errors thrown by the VM have entries here */ \ template(java_lang_AbstractMethodError, "java/lang/AbstractMethodError") \ @@ -283,7 +267,6 @@ class SerializeClosure; template(reflect_CallerSensitive_signature, "Ljdk/internal/reflect/CallerSensitive;") \ template(reflect_DirectConstructorHandleAccessor_NativeAccessor, "jdk/internal/reflect/DirectConstructorHandleAccessor$NativeAccessor") \ template(reflect_SerializationConstructorAccessorImpl, "jdk/internal/reflect/SerializationConstructorAccessorImpl") \ - template(checkedExceptions_name, "checkedExceptions") \ template(clazz_name, "clazz") \ template(exceptionTypes_name, "exceptionTypes") \ template(modifiers_name, "modifiers") \ @@ -363,10 +346,6 @@ class SerializeClosure; template(linkDynamicConstant_signature, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \ template(linkCallSite_name, "linkCallSite") \ template(linkCallSite_signature, "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/invoke/MemberName;") \ - template(setTargetNormal_name, "setTargetNormal") \ - template(setTargetVolatile_name, "setTargetVolatile") \ - template(setTarget_signature, "(Ljava/lang/invoke/MethodHandle;)V") \ - template(DEFAULT_CONTEXT_name, "DEFAULT_CONTEXT") \ NOT_LP64( do_alias(intptr_signature, int_signature) ) \ LP64_ONLY( do_alias(intptr_signature, long_signature) ) \ /* Foreign API Support */ \ @@ -411,7 +390,6 @@ class SerializeClosure; template(maxPriority_name, "maxPriority") \ template(shutdown_name, "shutdown") \ template(finalize_method_name, "finalize") \ - template(reference_lock_name, "lock") \ template(reference_discovered_name, "discovered") \ template(run_finalization_name, "runFinalization") \ template(dispatchUncaughtException_name, "dispatchUncaughtException") \ @@ -426,8 +404,6 @@ class SerializeClosure; template(enter_name, "enter") \ template(enterSpecial_name, "enterSpecial") \ template(onContinue_name, "onContinue0") \ - template(getStacks_name, "getStacks") \ - template(onPinned_name, "onPinned0") \ template(scope_name, "scope") \ template(yieldInfo_name, "yieldInfo") \ template(tail_name, "tail") \ @@ -435,26 +411,21 @@ class SerializeClosure; template(bottom_name, "bottom") \ template(mode_name, "mode") \ template(numFrames_name, "numFrames") \ - template(numOops_name, "numOops") \ template(stack_name, "stack") \ template(maxSize_name, "maxSize") \ template(reset_name, "reset") \ template(done_name, "done") \ template(mounted_name, "mounted") \ - template(numInterpretedFrames_name, "numInterpretedFrames") \ template(jfrTraceId_name, "jfrTraceId") \ template(fp_name, "fp") \ template(sp_name, "sp") \ template(pc_name, "pc") \ template(cs_name, "cs") \ - template(refStack_name, "refStack") \ - template(refSP_name, "refSP") \ template(get_name, "get") \ template(refersTo0_name, "refersTo0") \ template(put_name, "put") \ template(type_name, "type") \ template(findNative_name, "findNative") \ - template(deadChild_name, "deadChild") \ template(getFromClass_name, "getFromClass") \ template(dispatch_name, "dispatch") \ template(bootLoader_name, "bootLoader") \ @@ -470,7 +441,6 @@ class SerializeClosure; template(getClassContext_name, "getClassContext") \ template(wait_name, "wait0") \ template(checkPackageAccess_name, "checkPackageAccess") \ - template(newInstance0_name, "newInstance0") \ template(forName_name, "forName") \ template(forName0_name, "forName0") \ template(isJavaIdentifierStart_name, "isJavaIdentifierStart") \ @@ -492,7 +462,6 @@ class SerializeClosure; template(vmholder_name, "vmholder") \ template(method_name, "method") \ template(vmindex_name, "vmindex") \ - template(vmcount_name, "vmcount") \ template(flags_name, "flags") \ template(basicType_name, "basicType") \ template(append_name, "append") \ @@ -560,7 +529,6 @@ class SerializeClosure; template(void_float_signature, "()F") \ template(void_double_signature, "()D") \ template(bool_void_signature, "(Z)V") \ - template(bool_bool_void_signature, "(ZZ)V") \ template(int_void_signature, "(I)V") \ template(int_int_signature, "(I)I") \ template(char_char_signature, "(C)C") \ @@ -589,21 +557,16 @@ class SerializeClosure; template(bool_array_signature, "[Z") \ template(byte_array_signature, "[B") \ template(char_array_signature, "[C") \ - template(int_array_signature, "[I") \ - template(long_array_signature, "[J") \ template(runnable_signature, "Ljava/lang/Runnable;") \ template(continuation_signature, "Ljdk/internal/vm/Continuation;") \ template(continuationscope_signature, "Ljdk/internal/vm/ContinuationScope;") \ template(stackchunk_signature, "Ljdk/internal/vm/StackChunk;") \ - template(vthread_signature, "Ljava/lang/VirtualThread;") \ template(object_void_signature, "(Ljava/lang/Object;)V") \ template(object_int_signature, "(Ljava/lang/Object;)I") \ template(long_object_long_signature, "(JLjava/lang/Object;)J") \ template(object_boolean_signature, "(Ljava/lang/Object;)Z") \ template(object_object_signature, "(Ljava/lang/Object;)Ljava/lang/Object;") \ template(string_void_signature, "(Ljava/lang/String;)V") \ - template(string_int_signature, "(Ljava/lang/String;)I") \ - template(string_byte_array_signature, "(Ljava/lang/String;)[B") \ template(string_bool_byte_array_signature, "(Ljava/lang/String;Z)[B") \ template(throwable_signature, "Ljava/lang/Throwable;") \ template(throwable_void_signature, "(Ljava/lang/Throwable;)V") \ @@ -613,10 +576,6 @@ class SerializeClosure; template(class_long_signature, "(Ljava/lang/Class;)J") \ template(class_boolean_signature, "(Ljava/lang/Class;)Z") \ template(throwable_throwable_signature, "(Ljava/lang/Throwable;)Ljava/lang/Throwable;") \ - template(throwable_string_void_signature, "(Ljava/lang/Throwable;Ljava/lang/String;)V") \ - template(string_array_void_signature, "([Ljava/lang/String;)V") \ - template(string_array_string_array_void_signature, "([Ljava/lang/String;[Ljava/lang/String;)V") \ - template(thread_throwable_void_signature, "(Ljava/lang/Thread;Ljava/lang/Throwable;)V") \ template(thread_void_signature, "(Ljava/lang/Thread;)V") \ template(runnable_void_signature, "(Ljava/lang/Runnable;)V") \ template(threadgroup_runnable_void_signature, "(Ljava/lang/ThreadGroup;Ljava/lang/Runnable;)V") \ @@ -625,12 +584,9 @@ class SerializeClosure; template(string_class_signature, "(Ljava/lang/String;)Ljava/lang/Class;") \ template(string_boolean_class_signature, "(Ljava/lang/String;Z)Ljava/lang/Class;") \ template(object_object_object_signature, "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \ - template(string_string_string_signature, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;") \ template(string_string_signature, "(Ljava/lang/String;)Ljava/lang/String;") \ template(classloader_string_long_signature, "(Ljava/lang/ClassLoader;Ljava/lang/String;)J") \ template(byte_array_void_signature, "([B)V") \ - template(char_array_void_signature, "([C)V") \ - template(int_int_void_signature, "(II)V") \ template(long_long_void_signature, "(JJ)V") \ template(void_byte_array_signature, "()[B") \ template(void_classloader_signature, "()Ljava/lang/ClassLoader;") \ @@ -639,16 +595,13 @@ class SerializeClosure; template(void_class_signature, "()Ljava/lang/Class;") \ template(void_class_array_signature, "()[Ljava/lang/Class;") \ template(void_string_signature, "()Ljava/lang/String;") \ - template(void_module_signature, "()Ljava/lang/Module;") \ template(object_array_object_signature, "([Ljava/lang/Object;)Ljava/lang/Object;") \ template(object_object_array_object_signature, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")\ - template(exception_void_signature, "(Ljava/lang/Exception;)V") \ template(protectiondomain_signature, "[Ljava/security/ProtectionDomain;") \ template(accesscontrolcontext_signature, "Ljava/security/AccessControlContext;") \ template(class_protectiondomain_signature, "(Ljava/lang/Class;Ljava/security/ProtectionDomain;)V") \ template(thread_signature, "Ljava/lang/Thread;") \ template(thread_fieldholder_signature, "Ljava/lang/Thread$FieldHolder;") \ - template(thread_array_signature, "[Ljava/lang/Thread;") \ template(threadgroup_signature, "Ljava/lang/ThreadGroup;") \ template(threadgroup_array_signature, "[Ljava/lang/ThreadGroup;") \ template(class_array_signature, "[Ljava/lang/Class;") \ @@ -660,7 +613,6 @@ class SerializeClosure; template(string_array_signature, "[Ljava/lang/String;") \ template(reference_signature, "Ljava/lang/ref/Reference;") \ template(referencequeue_signature, "Ljava/lang/ref/ReferenceQueue;") \ - template(weakreference_array_signature, "[Ljava/lang/ref/WeakReference;") \ template(executable_signature, "Ljava/lang/reflect/Executable;") \ template(module_signature, "Ljava/lang/Module;") \ template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \ @@ -690,7 +642,6 @@ class SerializeClosure; \ /* JVM monitoring and management support */ \ template(java_lang_StackTraceElement_array, "[Ljava/lang/StackTraceElement;") \ - template(java_lang_management_ThreadState, "java/lang/management/ThreadState") \ template(java_lang_management_MemoryUsage, "java/lang/management/MemoryUsage") \ template(java_lang_management_ThreadInfo, "java/lang/management/ThreadInfo") \ template(jdk_internal_agent_Agent, "jdk/internal/agent/Agent") \ @@ -727,17 +678,12 @@ class SerializeClosure; template(java_lang_management_MemoryPoolMXBean, "java/lang/management/MemoryPoolMXBean") \ template(java_lang_management_MemoryManagerMXBean, "java/lang/management/MemoryManagerMXBean") \ template(java_lang_management_GarbageCollectorMXBean,"java/lang/management/GarbageCollectorMXBean") \ - template(gcInfoBuilder_name, "gcInfoBuilder") \ template(createMemoryPool_name, "createMemoryPool") \ template(createMemoryManager_name, "createMemoryManager") \ template(createGarbageCollector_name, "createGarbageCollector") \ template(createMemoryPool_signature, "(Ljava/lang/String;ZJJ)Ljava/lang/management/MemoryPoolMXBean;") \ template(createMemoryManager_signature, "(Ljava/lang/String;)Ljava/lang/management/MemoryManagerMXBean;") \ template(createGarbageCollector_signature, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/management/GarbageCollectorMXBean;") \ - template(addThreadDumpForMonitors_name, "addThreadDumpForMonitors") \ - template(addThreadDumpForSynchronizers_name, "addThreadDumpForSynchronizers") \ - template(addThreadDumpForMonitors_signature, "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;[I)V") \ - template(addThreadDumpForSynchronizers_signature, "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;)V") \ \ /* JVMTI/java.lang.instrument support and VM Attach mechanism */ \ template(jdk_internal_module_Modules, "jdk/internal/module/Modules") \ @@ -791,7 +737,6 @@ class SerializeClosure; template(java_util_ArrayList, "java/util/ArrayList") \ template(toFileURL_name, "toFileURL") \ template(toFileURL_signature, "(Ljava/lang/String;)Ljava/net/URL;") \ - template(url_void_signature, "(Ljava/net/URL;)V") \ template(url_array_classloader_void_signature, "([Ljava/net/URL;Ljava/lang/ClassLoader;)V") \ \ /* Thread.dump_to_file jcmd */ \ diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 38b82e6af93..2a26a4ebed3 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -1312,8 +1312,7 @@ void PhaseMacroExpand::expand_allocate_common( slow_region = new RegionNode(3); // Now make the initial failure test. Usually a too-big test but - // might be a TRUE for finalizers or a fancy class check for - // newInstance0. + // might be a TRUE for finalizers. IfNode *toobig_iff = new IfNode(ctrl, initial_slow_test, PROB_MIN, COUNT_UNKNOWN); transform_later(toobig_iff); // Plug the failing-too-big test into the slow-path region From f16265d69b09640b972b7494ad57158dbdc426bb Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Fri, 24 May 2024 12:24:15 +0000 Subject: [PATCH 28/99] 8332226: "Invalid package name:" from source launcher Reviewed-by: alanb --- .../javac/launcher/ProgramDescriptor.java | 74 +++++++++++++++---- .../launcher/ModuleSourceLauncherTests.java | 13 +++- 2 files changed, 67 insertions(+), 20 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/ProgramDescriptor.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/ProgramDescriptor.java index 087b1708acd..fd99838427b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/ProgramDescriptor.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/launcher/ProgramDescriptor.java @@ -32,6 +32,7 @@ import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; +import java.lang.module.InvalidModuleDescriptorException; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -39,6 +40,10 @@ import java.util.Optional; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.lang.model.SourceVersion; /** * Describes a launch-able Java compilation unit. @@ -113,25 +118,62 @@ public boolean isModular() { } public Set computePackageNames() { - try (var stream = Files.find(sourceRootPath, 99, (path, attr) -> attr.isDirectory())) { - var names = new TreeSet(); - stream.filter(ProgramDescriptor::containsAtLeastOneRegularFile) - .map(sourceRootPath::relativize) - .map(Path::toString) - .filter(string -> !string.isEmpty()) - .map(string -> string.replace(File.separatorChar, '.')) - .forEach(names::add); - return names; - } catch (IOException exception) { - throw new UncheckedIOException(exception); + return explodedPackages(sourceRootPath); + } + + // -- exploded directories --> based on jdk.internal.module.ModulePath + + private static Set explodedPackages(Path dir) { + String separator = dir.getFileSystem().getSeparator(); + try (Stream stream = Files.find(dir, Integer.MAX_VALUE, + (path, attrs) -> attrs.isRegularFile() && !isHidden(path))) { + return stream.map(dir::relativize) + .map(path -> toPackageName(path, separator)) + .flatMap(Optional::stream) + .collect(Collectors.toSet()); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } + + /** + * Maps the relative path of an entry in an exploded module to a package + * name. + * + * @throws InvalidModuleDescriptorException if the name is a class file in + * the top-level directory (and it's not module-info.class) + */ + private static Optional toPackageName(Path file, String separator) { + assert file.getRoot() == null; + + Path parent = file.getParent(); + if (parent == null) { + String name = file.toString(); + if (name.endsWith(".class") && !name.equals("module-info.class")) { + String msg = name + " found in top-level directory" + + " (unnamed package not allowed in module)"; + throw new InvalidModuleDescriptorException(msg); + } + return Optional.empty(); + } + + String pn = parent.toString().replace(separator, "."); + if (SourceVersion.isName(pn)) { + return Optional.of(pn); + } else { + // not a valid package name + return Optional.empty(); } } - private static boolean containsAtLeastOneRegularFile(Path directory) { - try (var stream = Files.newDirectoryStream(directory, Files::isRegularFile)) { - return stream.iterator().hasNext(); - } catch (IOException exception) { - throw new UncheckedIOException(exception); + /** + * Returns true if the given file exists and is a hidden file + */ + private static boolean isHidden(Path file) { + try { + return Files.isHidden(file); + } catch (IOException ioe) { + return false; } } } diff --git a/test/langtools/tools/javac/launcher/ModuleSourceLauncherTests.java b/test/langtools/tools/javac/launcher/ModuleSourceLauncherTests.java index 908674eb692..ebb39e2dccf 100644 --- a/test/langtools/tools/javac/launcher/ModuleSourceLauncherTests.java +++ b/test/langtools/tools/javac/launcher/ModuleSourceLauncherTests.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,7 +23,7 @@ /* * @test - * @bug 8304400 + * @bug 8304400 8332226 * @summary Test source launcher running Java programs contained in one module * @modules jdk.compiler/com.sun.tools.javac.launcher * @run junit ModuleSourceLauncherTests @@ -112,6 +112,8 @@ public static void main(String... args) throws Exception { Files.writeString(barFolder.resolve("Bar.java"), "package bar; public record Bar() {}"); var bazFolder = Files.createDirectories(base.resolve("baz")); Files.writeString(bazFolder.resolve("baz.txt"), "baz"); + var badFolder = Files.createDirectories(base.resolve(".bad")); + Files.writeString(badFolder.resolve("bad.txt"), "bad"); Files.writeString(base.resolve("module-info.java"), """ @@ -140,8 +142,11 @@ public static void main(String... args) throws Exception { assertEquals("m", module.getName()); var reference = module.getLayer().configuration().findModule(module.getName()).orElseThrow().reference(); try (var reader = reference.open()) { + var actual = reader.list().toList(); assertLinesMatch( """ + .bad/ + .bad/bad.txt bar/ bar/Bar.class bar/Bar.java @@ -152,8 +157,8 @@ public static void main(String... args) throws Exception { foo/Main.java module-info.class module-info.java - """.lines(), - reader.list()); + """.lines().toList(), + actual, "Actual lines -> " + actual); } } From 6a35311468222f9335b43d548df2ecb80746b389 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Fri, 24 May 2024 12:42:16 +0000 Subject: [PATCH 29/99] 8241550: [macOS] SSLSocketImpl/ReuseAddr.java failed due to "BindException: Address already in use" Reviewed-by: jpai, mullan --- .../security/ssl/SSLSocketImpl/ReuseAddr.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java b/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java index abad01099bc..f7e677bbbd0 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/ReuseAddr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, 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 @@ -34,9 +34,12 @@ */ import java.net.ServerSocket; +import java.net.BindException; public class ReuseAddr extends SSLSocketTemplate { + private static final int MAX_ATTEMPTS = 3; + @Override protected void doServerSide() throws Exception { super.doServerSide(); @@ -50,6 +53,21 @@ protected void doServerSide() throws Exception { } public static void main(String[] args) throws Exception { - new ReuseAddr().run(); + for (int i=1 ; i <= MAX_ATTEMPTS; i++) { + try { + new ReuseAddr().run(); + System.out.println("Test succeeded at attempt " + i); + break; + } catch (BindException x) { + System.out.println("attempt " + i + " failed: " + x); + if (i == MAX_ATTEMPTS) { + String msg = "Could not succeed after " + i + " attempts"; + System.err.println(msg); + throw new AssertionError("Failed to reuse address: " + msg, x); + } else { + System.out.println("Retrying..."); + } + } + } } } From c099f14f07260713229cffbe7d23aa8305415a67 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Fri, 24 May 2024 13:37:14 +0000 Subject: [PATCH 30/99] 8305457: Implement java.io.IO Reviewed-by: naoto, smarks, jpai, jlahoda --- .../share/classes/java/io/Console.java | 64 +++++++ src/java.base/share/classes/java/io/IO.java | 110 +++++++++++ .../classes/java/io/ProxyingConsole.java | 36 ++++ .../classes/jdk/internal/io/JdkConsole.java | 3 + .../jdk/internal/io/JdkConsoleImpl.java | 33 ++++ .../org/jline/JdkConsoleProviderImpl.java | 24 +++ .../jshell/execution/impl/ConsoleImpl.java | 40 ++++ test/jdk/java/io/IO/IO.java | 177 ++++++++++++++++++ test/jdk/java/io/IO/Input.java | 36 ++++ test/jdk/java/io/IO/Methods.java | 36 ++++ test/jdk/java/io/IO/Output.java | 63 +++++++ test/jdk/java/io/IO/input.exp | 36 ++++ test/jdk/java/io/IO/output.exp | 32 ++++ .../tools/javac/diags/examples.not-yet.txt | 1 - .../javac/diags/examples/ImplicitClass.java | 9 +- 15 files changed, 695 insertions(+), 5 deletions(-) create mode 100644 src/java.base/share/classes/java/io/IO.java create mode 100644 test/jdk/java/io/IO/IO.java create mode 100644 test/jdk/java/io/IO/Input.java create mode 100644 test/jdk/java/io/IO/Methods.java create mode 100644 test/jdk/java/io/IO/Output.java create mode 100644 test/jdk/java/io/IO/input.exp create mode 100644 test/jdk/java/io/IO/output.exp diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index 45f5dddafb2..c735f9af853 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -33,6 +33,7 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.io.JdkConsoleImpl; import jdk.internal.io.JdkConsoleProvider; +import jdk.internal.javac.PreviewFeature; import jdk.internal.util.StaticProperty; import sun.security.action.GetPropertyAction; @@ -150,6 +151,69 @@ public Reader reader() { throw newUnsupportedOperationException(); } + /** + * Writes a string representation of the specified object to this console's + * output stream, terminates the line using {@link System#lineSeparator()} + * and then flushes the console. + * + *

    The string representation of the specified object is obtained as if + * by calling {@link String#valueOf(Object)}. + * + * @param obj + * An object whose string representation is to be written, + * may be {@code null}. + * + * @return This console + * + * @since 23 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public Console println(Object obj) { + throw newUnsupportedOperationException(); + } + + /** + * Writes a string representation of the specified object to this console's + * output stream and then flushes the console. + * + *

    The string representation of the specified object is obtained as if + * by calling {@link String#valueOf(Object)}. + * + * @param obj + * An object whose string representation is to be written, + * may be {@code null}. + * + * @return This console + * + * @since 23 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public Console print(Object obj) { + throw newUnsupportedOperationException(); + } + + /** + * Writes a prompt as if by calling {@code print}, then reads a single line + * of text from this console. + * + * @param prompt + * A prompt string, may be {@code null}. + * + * @throws IOError + * If an I/O error occurs. + * + * @return A string containing the line read from the console, not + * including any line-termination characters, or {@code null} + * if an end of stream has been reached without having read + * any characters. + * + * @since 23 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public String readln(String prompt) { + throw newUnsupportedOperationException(); + } + /** * Writes a formatted string to this console's output stream using * the specified format string and arguments with the diff --git a/src/java.base/share/classes/java/io/IO.java b/src/java.base/share/classes/java/io/IO.java new file mode 100644 index 00000000000..7485f87f03f --- /dev/null +++ b/src/java.base/share/classes/java/io/IO.java @@ -0,0 +1,110 @@ +/* + * 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. 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 java.io; + +import jdk.internal.javac.PreviewFeature; + +/** + * A collection of static convenience methods that provide access to + * {@linkplain System#console() system console} for implicitly declared classes. + * + *

    Each of this class' methods throws {@link IOError} if the system console + * is {@code null}; otherwise, the effect is as if a similarly-named method + * had been called on that console. + * + *

    Input and output from methods in this class use the character set of + * the system console as specified by {@link Console#charset}. + * + * @since 23 + */ +@PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) +public final class IO { + + private IO() { + throw new Error("no instances"); + } + + /** + * Writes a string representation of the specified object to the system + * console, terminates the line and then flushes that console. + * + *

    The effect is as if {@link Console#println(Object) println(obj)} + * had been called on {@code System.console()}. + * + * @param obj the object to print, may be {@code null} + * + * @throws IOError if {@code System.console()} returns {@code null}, + * or if an I/O error occurs + */ + public static void println(Object obj) { + con().println(obj); + } + + /** + * Writes a string representation of the specified object to the system + * console and then flushes that console. + * + *

    The effect is as if {@link Console#print(Object) print(obj)} + * had been called on {@code System.console()}. + * + * @param obj the object to print, may be {@code null} + * + * @throws IOError if {@code System.console()} returns {@code null}, + * or if an I/O error occurs + */ + public static void print(Object obj) { + con().print(obj); + } + + /** + * Writes a prompt as if by calling {@code print}, then reads a single line + * of text from the system console. + * + *

    The effect is as if {@link Console#readln(String) readln(prompt)} + * had been called on {@code System.console()}. + * + * @param prompt the prompt string, may be {@code null} + * + * @return a string containing the line read from the system console, not + * including any line-termination characters. Returns {@code null} if an + * end of stream has been reached without having read any characters. + * + * @throws IOError if {@code System.console()} returns {@code null}, + * or if an I/O error occurs + */ + public static String readln(String prompt) { + return con().readln(prompt); + } + + private static Console con() { + var con = System.console(); + if (con != null) { + return con; + } else { + throw new IOError(null); + } + } +} diff --git a/src/java.base/share/classes/java/io/ProxyingConsole.java b/src/java.base/share/classes/java/io/ProxyingConsole.java index 2179afa31c0..1babceb665f 100644 --- a/src/java.base/share/classes/java/io/ProxyingConsole.java +++ b/src/java.base/share/classes/java/io/ProxyingConsole.java @@ -81,6 +81,42 @@ public Reader reader() { return reader; } + /** + * {@inheritDoc} + */ + @Override + public Console println(Object obj) { + synchronized (writeLock) { + delegate.println(obj); + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public Console print(Object obj) { + synchronized (writeLock) { + delegate.print(obj); + } + return this; + } + + /** + * {@inheritDoc} + * + * @throws IOError {@inheritDoc} + */ + @Override + public String readln(String prompt) { + synchronized (writeLock) { + synchronized (readLock) { + return delegate.readln(prompt); + } + } + } + /** * {@inheritDoc} */ diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsole.java b/src/java.base/share/classes/jdk/internal/io/JdkConsole.java index 2d48748fbfc..6c911ed6fed 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsole.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsole.java @@ -38,6 +38,9 @@ public interface JdkConsole { PrintWriter writer(); Reader reader(); + JdkConsole println(Object obj); + JdkConsole print(Object obj); + String readln(String prompt); JdkConsole format(Locale locale, String format, Object ... args); String readLine(Locale locale, String format, Object ... args); String readLine(); diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java index e25626ead0c..7930e00fbc0 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java @@ -57,6 +57,39 @@ public Reader reader() { return reader; } + @Override + public JdkConsole println(Object obj) { + pw.println(obj); + // automatic flushing covers println + return this; + } + + @Override + public JdkConsole print(Object obj) { + pw.print(obj); + pw.flush(); // automatic flushing does not cover print + return this; + } + + @Override + public String readln(String prompt) { + String line = null; + synchronized (writeLock) { + synchronized(readLock) { + pw.print(prompt); + pw.flush(); // automatic flushing does not cover print + try { + char[] ca = readline(false); + if (ca != null) + line = new String(ca); + } catch (IOException x) { + throw new IOError(x); + } + } + } + return line; + } + @Override public JdkConsole format(Locale locale, String format, Object ... args) { formatter.format(locale, format, args).flush(); diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java index aa90f68c1cf..cb327b3f6e0 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java @@ -84,6 +84,30 @@ public Reader reader() { return terminal.reader(); } + @Override + public JdkConsole println(Object obj) { + writer().println(obj); + writer().flush(); + return this; + } + + @Override + public JdkConsole print(Object obj) { + writer().print(obj); + writer().flush(); + return this; + } + + @Override + public String readln(String prompt) { + try { + initJLineIfNeeded(); + return jline.readLine(prompt == null ? "null" : prompt.replace("%", "%%")); + } catch (EndOfFileException eofe) { + return null; + } + } + @Override public JdkConsole format(Locale locale, String format, Object ... args) { writer().format(locale, format, args).flush(); diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java index 68901aebc84..e481a699d1b 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java @@ -191,6 +191,46 @@ public void close() throws IOException { } return reader; } + /** + * {@inheritDoc} + */ + @Override + public JdkConsole println(Object obj) { + writer().println(obj); + writer().flush(); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public JdkConsole print(Object obj) { + writer().print(obj); + writer().flush(); + return this; + } + + /** + * {@inheritDoc} + * + * @throws IOError {@inheritDoc} + */ + @Override + public String readln(String prompt) { + try { + return sendAndReceive(() -> { + remoteInput.write(Task.READ_LINE.ordinal()); + char[] chars = (prompt == null ? "null" : prompt).toCharArray(); + sendChars(chars, 0, chars.length); + char[] line = readChars(); + return new String(line); + }); + } catch (IOException ex) { + throw new IOError(ex); + } + } + /** * {@inheritDoc} */ diff --git a/test/jdk/java/io/IO/IO.java b/test/jdk/java/io/IO/IO.java new file mode 100644 index 00000000000..9b35fe1ab81 --- /dev/null +++ b/test/jdk/java/io/IO/IO.java @@ -0,0 +1,177 @@ +/* + * 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.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.stream.Stream; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jtreg.SkippedException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; + +/* + * @test + * @bug 8305457 + * @summary java.io.IO tests + * @library /test/lib + * @run junit IO + */ +public class IO { + + @Nested + @EnabledOnOs({OS.LINUX, OS.MAC}) + public class OSSpecificTests { + + private static Path expect; + + @BeforeAll + public static void prepareTTY() { + expect = Paths.get("/usr/bin/expect"); // os-specific path + if (!Files.exists(expect) || !Files.isExecutable(expect)) { + throw new SkippedException("'" + expect + "' not found"); + } + } + + /* + * Unlike printTest, which tests a _default_ console that is normally + * jdk.internal.org.jline.JdkConsoleProviderImpl, this test tests + * jdk.internal.io.JdkConsoleImpl. Those console implementations operate + * in different conditions and, thus, are tested separately. + * + * To test jdk.internal.io.JdkConsoleImpl one needs to ensure that both + * conditions are met: + * + * - a non-existent console provider is requested + * - isatty is true + * + * To achieve isatty, the test currently uses the EXPECT(1) Unix command, + * which does not work for Windows. Later, a library like pty4j or JPty + * might be used instead of EXPECT, to cover both Unix and Windows. + */ + @ParameterizedTest + @ValueSource(strings = {"println", "print"}) + public void outputTestInteractive(String mode) throws Exception { + var testSrc = System.getProperty("test.src", "."); + OutputAnalyzer output = ProcessTools.executeProcess( + expect.toString(), + Path.of(testSrc, "output.exp").toAbsolutePath().toString(), + System.getProperty("test.jdk") + "/bin/java", + "--enable-preview", + "-Djdk.console=gibberish", + Path.of(testSrc, "Output.java").toAbsolutePath().toString(), + mode); + assertEquals(0, output.getExitValue()); + assertTrue(output.getStderr().isEmpty()); + output.reportDiagnosticSummary(); + String out = output.getStdout(); + // The first half of the output is produced by Console, the second + // half is produced by IO: those halves must match. + // Executing Console and IO in the same VM (as opposed to + // consecutive VM runs, which are cleaner) to be able to compare string + // representation of objects. + assertFalse(out.isBlank()); + assertEquals(out.substring(0, out.length() / 2), + out.substring(out.length() / 2)); + } + + /* + * This tests simulates terminal interaction (isatty), to check that the + * prompt is output. + * + * To simulate a terminal, the test currently uses the EXPECT(1) Unix + * command, which does not work for Windows. Later, a library like pty4j + * or JPty might be used instead of EXPECT, to cover both Unix and Windows. + */ + @ParameterizedTest + @MethodSource("args") + public void inputTestInteractive(String console, String prompt) throws Exception { + var testSrc = System.getProperty("test.src", "."); + var command = new ArrayList(); + command.add(expect.toString()); + command.add(Path.of(testSrc, "input.exp").toAbsolutePath().toString()); + command.add(System.getProperty("test.jdk") + "/bin/java"); + command.add("--enable-preview"); + if (console != null) + command.add("-Djdk.console=" + console); + command.add(Path.of(testSrc, "Input.java").toAbsolutePath().toString()); + command.add(prompt == null ? "0" : "1"); + command.add(String.valueOf(prompt)); + OutputAnalyzer output = ProcessTools.executeProcess(command.toArray(new String[]{})); + output.reportDiagnosticSummary(); + assertEquals(0, output.getExitValue()); + } + + public static Stream args() { + // cross product: consoles x prompts + return Stream.of(null, "gibberish").flatMap(console -> Stream.of(null, "?", "%s") + .map(prompt -> new String[]{console, prompt}).map(Arguments::of)); + } + } + + @ParameterizedTest + @ValueSource(strings = {"println", "print"}) + public void printTest(String mode) throws Exception { + var file = Path.of(System.getProperty("test.src", "."), "Output.java") + .toAbsolutePath().toString(); + var pb = ProcessTools.createTestJavaProcessBuilder("--enable-preview", file, mode); + OutputAnalyzer output = ProcessTools.executeProcess(pb); + assertEquals(0, output.getExitValue()); + assertTrue(output.getStderr().isEmpty()); + output.reportDiagnosticSummary(); + String out = output.getStdout(); + // The first half of the output is produced by Console, the second + // half is produced by IO: those halves must match. + // Executing Console and IO in the same VM (as opposed to + // consecutive VM runs, which are cleaner) to be able to compare string + // representation of objects. + assertFalse(out.isBlank()); + assertEquals(out.substring(0, out.length() / 2), + out.substring(out.length() / 2)); + } + + + @ParameterizedTest + @ValueSource(strings = {"println", "print", "input"}) + public void nullConsole(String method) throws Exception { + var file = Path.of(System.getProperty("test.src", "."), "Methods.java") + .toAbsolutePath().toString(); + var pb = ProcessTools.createTestJavaProcessBuilder("-Djdk.console=gibberish", + "--enable-preview", file, method); + OutputAnalyzer output = ProcessTools.executeProcess(pb); + output.reportDiagnosticSummary(); + assertEquals(1, output.getExitValue()); + output.shouldContain("Exception in thread \"main\" java.io.IOError"); + } +} diff --git a/test/jdk/java/io/IO/Input.java b/test/jdk/java/io/IO/Input.java new file mode 100644 index 00000000000..1bc03c8bb8a --- /dev/null +++ b/test/jdk/java/io/IO/Input.java @@ -0,0 +1,36 @@ +/* + * 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.IOException; + +import static java.io.IO.readln; + +public class Input { + + public static void main(String[] args) throws IOException { + if (args[0].equals("0")) + System.out.print(readln(null)); + else + System.out.print(readln(args[1])); + } +} diff --git a/test/jdk/java/io/IO/Methods.java b/test/jdk/java/io/IO/Methods.java new file mode 100644 index 00000000000..c1700241b32 --- /dev/null +++ b/test/jdk/java/io/IO/Methods.java @@ -0,0 +1,36 @@ +/* + * 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 static java.io.IO.*; + +public class Methods { + + public static void main(String[] args) { + switch (args[0]) { + case "println" -> println("hello"); + case "print" -> print("hello"); + case "input" -> readln("hello"); + default -> throw new IllegalArgumentException(args[0]); + } + } +} diff --git a/test/jdk/java/io/IO/Output.java b/test/jdk/java/io/IO/Output.java new file mode 100644 index 00000000000..38d37fa9f41 --- /dev/null +++ b/test/jdk/java/io/IO/Output.java @@ -0,0 +1,63 @@ +/* + * 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 static java.io.IO.*; +import java.util.function.Consumer; + +public class Output { + + private static final Object[] OBJECTS = { + null, + false, + (byte) 1, + (short) 2, + 'a', + 3, + 4L, + 5f, + 6d, + new Object(), + "%s", // to test that print(ln) does not interpret its argument as a format string + new char[]{'a'}, + }; + + public static void main(String[] args) { + switch (args[0]) { + case "print" -> { + printObjects(obj -> System.console().format("%s", obj).flush()); + printObjects(obj -> print(obj)); + } + case "println" -> { + printObjects(obj -> System.console().format("%s%n", obj).flush()); + printObjects(obj -> println(obj)); + } + default -> throw new IllegalArgumentException(); + } + } + + private static void printObjects(Consumer printer) { + for (var obj : OBJECTS) { + printer.accept(obj); + } + } +} diff --git a/test/jdk/java/io/IO/input.exp b/test/jdk/java/io/IO/input.exp new file mode 100644 index 00000000000..ba86b57b131 --- /dev/null +++ b/test/jdk/java/io/IO/input.exp @@ -0,0 +1,36 @@ +# +# 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. +# + +set prompt [lindex $argv $argc-1] +set stty_init "rows 24 cols 80" + +spawn {*}$argv +expect { + -exact "$prompt" { + send "hello\r" + } + timeout { + puts "timeout"; exit 1 + } +} +expect eof diff --git a/test/jdk/java/io/IO/output.exp b/test/jdk/java/io/IO/output.exp new file mode 100644 index 00000000000..9044912cfaf --- /dev/null +++ b/test/jdk/java/io/IO/output.exp @@ -0,0 +1,32 @@ +# +# 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. +# + +################################################################################ +# This script does not expect/verify anything and is only used to simulate tty # +################################################################################ + +# Use `noecho` below, otherwise, expect will output the expanded "spawn ..." +# command, which will interfere with asserting output from the java test + +spawn -noecho {*}$argv +expect eof diff --git a/test/langtools/tools/javac/diags/examples.not-yet.txt b/test/langtools/tools/javac/diags/examples.not-yet.txt index 716301a913f..c1c0a0fc9ac 100644 --- a/test/langtools/tools/javac/diags/examples.not-yet.txt +++ b/test/langtools/tools/javac/diags/examples.not-yet.txt @@ -118,7 +118,6 @@ compiler.warn.illegal.char.for.encoding compiler.warn.incubating.modules # requires adjusted classfile compiler.warn.invalid.archive.file compiler.warn.invalid.utf8.in.classfile # bad class file -compiler.warn.is.preview # difficult to produce reliably despite future changes to java.base compiler.warn.is.preview.reflective # difficult to produce reliably despite future changes to java.base compiler.warn.output.file.clash # this warning is not generated on Linux compiler.warn.override.bridge diff --git a/test/langtools/tools/javac/diags/examples/ImplicitClass.java b/test/langtools/tools/javac/diags/examples/ImplicitClass.java index c032bdefeff..30285293b18 100644 --- a/test/langtools/tools/javac/diags/examples/ImplicitClass.java +++ b/test/langtools/tools/javac/diags/examples/ImplicitClass.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 @@ -21,9 +21,10 @@ * questions. */ - // key: compiler.misc.feature.implicit.classes - // key: compiler.warn.preview.feature.use.plural - // options: -source ${jdk.version} --enable-preview -Xlint:preview +// key: compiler.misc.feature.implicit.classes +// key: compiler.warn.preview.feature.use.plural +// key: compiler.warn.is.preview +// options: -source ${jdk.version} --enable-preview -Xlint:preview public static void main(String... args) { } From 0c934ff4e2fb53a72ad25a080d956745a5649f9b Mon Sep 17 00:00:00 2001 From: Damon Fenacci Date: Fri, 24 May 2024 13:39:17 +0000 Subject: [PATCH 31/99] 8325520: Vector loads and stores with indices and masks incorrectly compiled Reviewed-by: epeter, thartmann --- src/hotspot/share/opto/memnode.cpp | 24 +- src/hotspot/share/opto/node.hpp | 6 + src/hotspot/share/opto/vectornode.hpp | 23 + .../compiler/lib/ir_framework/IRNode.java | 10 + .../VectorGatherMaskFoldingTest.java | 1404 +++++++++++++++++ 5 files changed, 1465 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index fa26825e19f..a436703b050 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -3516,7 +3516,10 @@ Node* StoreNode::Identity(PhaseGVN* phase) { val->in(MemNode::Address)->eqv_uncast(adr) && val->in(MemNode::Memory )->eqv_uncast(mem) && val->as_Load()->store_Opcode() == Opcode()) { - result = mem; + // Ensure vector type is the same + if (!is_StoreVector() || as_StoreVector()->vect_type() == mem->as_LoadVector()->vect_type()) { + result = mem; + } } // Two stores in a row of the same value? @@ -3525,7 +3528,24 @@ Node* StoreNode::Identity(PhaseGVN* phase) { mem->in(MemNode::Address)->eqv_uncast(adr) && mem->in(MemNode::ValueIn)->eqv_uncast(val) && mem->Opcode() == Opcode()) { - result = mem; + if (!is_StoreVector()) { + result = mem; + } else { + const StoreVectorNode* store_vector = as_StoreVector(); + const StoreVectorNode* mem_vector = mem->as_StoreVector(); + const Node* store_indices = store_vector->indices(); + const Node* mem_indices = mem_vector->indices(); + const Node* store_mask = store_vector->mask(); + const Node* mem_mask = mem_vector->mask(); + // Ensure types, indices, and masks match + if (store_vector->vect_type() == mem_vector->vect_type() && + ((store_indices == nullptr) == (mem_indices == nullptr) && + (store_indices == nullptr || store_indices->eqv_uncast(mem_indices))) && + ((store_mask == nullptr) == (mem_mask == nullptr) && + (store_mask == nullptr || store_mask->eqv_uncast(mem_mask)))) { + result = mem; + } + } } // Store of zero anywhere into a freshly-allocated object? diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 04631dcbae2..314f165ac8b 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -180,8 +180,10 @@ class LoadVectorNode; class LoadVectorMaskedNode; class StoreVectorMaskedNode; class LoadVectorGatherNode; +class LoadVectorGatherMaskedNode; class StoreVectorNode; class StoreVectorScatterNode; +class StoreVectorScatterMaskedNode; class VerifyVectorAlignmentNode; class VectorMaskCmpNode; class VectorUnboxNode; @@ -996,8 +998,12 @@ class Node { DEFINE_CLASS_QUERY(CompressM) DEFINE_CLASS_QUERY(LoadVector) DEFINE_CLASS_QUERY(LoadVectorGather) + DEFINE_CLASS_QUERY(LoadVectorMasked) + DEFINE_CLASS_QUERY(LoadVectorGatherMasked) DEFINE_CLASS_QUERY(StoreVector) DEFINE_CLASS_QUERY(StoreVectorScatter) + DEFINE_CLASS_QUERY(StoreVectorMasked) + DEFINE_CLASS_QUERY(StoreVectorScatterMasked) DEFINE_CLASS_QUERY(ShiftV) DEFINE_CLASS_QUERY(Unlock) diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index d35f623555d..a9ded1bfa2d 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -910,6 +910,10 @@ class LoadVectorGatherNode : public LoadVectorNode { ((is_subword_type(vect_type()->element_basic_type())) && idx == MemNode::ValueIn + 1); } + virtual int store_Opcode() const { + // Ensure it is different from any store opcode to avoid folding when indices are used + return -1; + } }; //------------------------------StoreVectorNode-------------------------------- @@ -942,6 +946,8 @@ class StoreVectorNode : public StoreNode { // Needed for proper cloning. virtual uint size_of() const { return sizeof(*this); } + virtual Node* mask() const { return nullptr; } + virtual Node* indices() const { return nullptr; } #ifdef ASSERT // When AlignVector is enabled, SuperWord only creates aligned vector loads and stores. @@ -957,6 +963,7 @@ class StoreVectorNode : public StoreNode { class StoreVectorScatterNode : public StoreVectorNode { public: + enum { Indices = 4 }; StoreVectorScatterNode(Node* c, Node* mem, Node* adr, const TypePtr* at, Node* val, Node* indices) : StoreVectorNode(c, mem, adr, at, val) { init_class_id(Class_StoreVectorScatter); @@ -968,12 +975,14 @@ class StoreVectorNode : public StoreNode { virtual uint match_edge(uint idx) const { return idx == MemNode::Address || idx == MemNode::ValueIn || idx == MemNode::ValueIn + 1; } + virtual Node* indices() const { return in(Indices); } }; //------------------------------StoreVectorMaskedNode-------------------------------- // Store Vector to memory under the influence of a predicate register(mask). class StoreVectorMaskedNode : public StoreVectorNode { public: + enum { Mask = 4 }; StoreVectorMaskedNode(Node* c, Node* mem, Node* dst, Node* src, const TypePtr* at, Node* mask) : StoreVectorNode(c, mem, dst, at, src) { init_class_id(Class_StoreVectorMasked); @@ -987,6 +996,7 @@ class StoreVectorMaskedNode : public StoreVectorNode { return idx > 1; } virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual Node* mask() const { return in(Mask); } }; //------------------------------LoadVectorMaskedNode-------------------------------- @@ -1007,6 +1017,10 @@ class LoadVectorMaskedNode : public LoadVectorNode { return idx > 1; } virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual int store_Opcode() const { + // Ensure it is different from any store opcode to avoid folding when a mask is used + return -1; + } }; //-------------------------------LoadVectorGatherMaskedNode--------------------------------- @@ -1030,12 +1044,19 @@ class LoadVectorGatherMaskedNode : public LoadVectorNode { idx == MemNode::ValueIn + 1 || (is_subword_type(vect_type()->is_vect()->element_basic_type()) && idx == MemNode::ValueIn + 2); } + virtual int store_Opcode() const { + // Ensure it is different from any store opcode to avoid folding when indices and mask are used + return -1; + } }; //------------------------------StoreVectorScatterMaskedNode-------------------------------- // Store Vector into memory via index map under the influence of a predicate register(mask). class StoreVectorScatterMaskedNode : public StoreVectorNode { public: + enum { Indices = 4, + Mask + }; StoreVectorScatterMaskedNode(Node* c, Node* mem, Node* adr, const TypePtr* at, Node* val, Node* indices, Node* mask) : StoreVectorNode(c, mem, adr, at, val) { init_class_id(Class_StoreVectorScatterMasked); @@ -1050,6 +1071,8 @@ class StoreVectorScatterMaskedNode : public StoreVectorNode { idx == MemNode::ValueIn || idx == MemNode::ValueIn + 1 || idx == MemNode::ValueIn + 2; } + virtual Node* mask() const { return in(Mask); } + virtual Node* indices() const { return in(Indices); } }; // Verify that memory address (adr) is aligned. The mask specifies the diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 11f324a91e1..1fb68439afb 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -755,6 +755,11 @@ public class IRNode { beforeMatchingNameRegex(LOAD_VECTOR_GATHER, "LoadVectorGather"); } + public static final String LOAD_VECTOR_MASKED = PREFIX + "LOAD_VECTOR_MASKED" + POSTFIX; + static { + beforeMatchingNameRegex(LOAD_VECTOR_MASKED, "LoadVectorMasked"); + } + public static final String LOAD_VECTOR_GATHER_MASKED = PREFIX + "LOAD_VECTOR_GATHER_MASKED" + POSTFIX; static { beforeMatchingNameRegex(LOAD_VECTOR_GATHER_MASKED, "LoadVectorGatherMasked"); @@ -1479,6 +1484,11 @@ public class IRNode { beforeMatchingNameRegex(STORE_VECTOR_SCATTER, "StoreVectorScatter"); } + public static final String STORE_VECTOR_MASKED = PREFIX + "STORE_VECTOR_MASKED" + POSTFIX; + static { + beforeMatchingNameRegex(STORE_VECTOR_MASKED, "StoreVectorMasked"); + } + public static final String STORE_VECTOR_SCATTER_MASKED = PREFIX + "STORE_VECTOR_SCATTER_MASKED" + POSTFIX; static { beforeMatchingNameRegex(STORE_VECTOR_SCATTER_MASKED, "StoreVectorScatterMasked"); diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java new file mode 100644 index 00000000000..88d1bbde1d4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorGatherMaskFoldingTest.java @@ -0,0 +1,1404 @@ +/* + * 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.vectorapi; + +import compiler.lib.ir_framework.*; + +import jdk.test.lib.Asserts; +import jdk.incubator.vector.*; +import java.util.Arrays; +import java.nio.ByteOrder; + +/** + * @test + * @bug 8325520 + * @library /test/lib / + * @summary Don't allow folding of Load/Store vectors when using incompatible indices or masks + * @modules jdk.incubator.vector + * + * @run driver compiler.vectorapi.VectorGatherMaskFoldingTest + */ + +public class VectorGatherMaskFoldingTest { + // Species + private static final VectorSpecies L_SPECIES = LongVector.SPECIES_MAX; + private static final VectorSpecies I_SPECIES = IntVector.SPECIES_MAX; + private static final VectorSpecies F_SPECIES = FloatVector.SPECIES_MAX; + private static final VectorSpecies D_SPECIES = DoubleVector.SPECIES_MAX; + // Vectors + private static final LongVector longVector; + private static final LongVector longVector2; + private static final IntVector intVector; + private static final IntVector intVector2; + private static final DoubleVector doubleVector; + private static final DoubleVector doubleVector2; + private static final FloatVector floatVector; + private static final FloatVector floatVector2; + // Arrays + private static final long[] longArray = new long[L_SPECIES.length()]; + private static final long[] longArray2 = new long[L_SPECIES.length()]; + private static final int[] intArray = new int[I_SPECIES.length()]; + private static final int[] intArray2 = new int[I_SPECIES.length()]; + private static final double[] doubleArray = new double[D_SPECIES.length()]; + private static final double[] doubleArray2 = new double[D_SPECIES.length()]; + private static final float[] floatArray = new float[F_SPECIES.length()]; + private static final float[] floatArray2 = new float[F_SPECIES.length()]; + // Indices + private static final int[] longIndices = new int[L_SPECIES.length()]; + private static final int[] longIndices2 = new int[L_SPECIES.length()]; + private static final int[] duplicateLongIndices = new int[L_SPECIES.length()]; + private static final int[] intIndices = new int[I_SPECIES.length()]; + private static final int[] intIndices2 = new int[I_SPECIES.length()]; + private static final int[] duplicateIntIndices = new int[I_SPECIES.length()]; + private static final int[] doubleIndices = new int[D_SPECIES.length()]; + private static final int[] doubleIndices2 = new int[D_SPECIES.length()]; + private static final int[] duplicateDoubleIndices = new int[D_SPECIES.length()]; + private static final int[] floatIndices = new int[F_SPECIES.length()]; + private static final int[] floatIndices2 = new int[F_SPECIES.length()]; + private static final int[] duplicateFloatIndices = new int[F_SPECIES.length()]; + // Masks + private static final boolean[] longMask = new boolean[L_SPECIES.length()]; + private static final boolean[] longMask2 = new boolean[L_SPECIES.length()]; + private static final boolean[] intMask = new boolean[I_SPECIES.length()]; + private static final boolean[] intMask2 = new boolean[I_SPECIES.length()]; + private static final boolean[] doubleMask = new boolean[D_SPECIES.length()]; + private static final boolean[] doubleMask2 = new boolean[D_SPECIES.length()]; + private static final boolean[] floatMask = new boolean[F_SPECIES.length()]; + private static final boolean[] floatMask2 = new boolean[F_SPECIES.length()]; + private static final VectorMask longVectorMask; + private static final VectorMask longVectorMask2; + private static final VectorMask intVectorMask; + private static final VectorMask intVectorMask2; + private static final VectorMask doubleVectorMask; + private static final VectorMask doubleVectorMask2; + private static final VectorMask floatVectorMask; + private static final VectorMask floatVectorMask2; + + // Filling vectors/indices/masks + static { + for (int i = 0; i < L_SPECIES.length(); i++) { + longArray[i] = i + 1; + longArray2[i] = L_SPECIES.length() - i + 1; + longMask[i] = i % 2 == 0; + longMask2[i] = i >= L_SPECIES.length() / 2; + longIndices[i] = (i + L_SPECIES.length() / 2) % L_SPECIES.length(); + longIndices2[i] = (L_SPECIES.length() - i) % L_SPECIES.length(); + duplicateLongIndices[i] = longIndices[i] / 2; + } + longVector = LongVector.fromArray(L_SPECIES, longArray, 0); + longVector2 = LongVector.fromArray(L_SPECIES, longArray2, 0); + longVectorMask = VectorMask.fromArray(L_SPECIES, longMask, 0); + longVectorMask2 = VectorMask.fromArray(L_SPECIES, longMask2, 0); + for (int i = 0; i < I_SPECIES.length(); i++) { + intArray[i] = i + 1; + intArray2[i] = I_SPECIES.length() - i + 1; + intMask[i] = i % 2 == 0; + intMask2[i] = i >= I_SPECIES.length() / 2; + intIndices[i] = (i + I_SPECIES.length() / 2) % I_SPECIES.length(); + intIndices2[i] = (I_SPECIES.length() - i) % I_SPECIES.length(); + duplicateIntIndices[i] = intIndices[i] / 2; + } + intVector = IntVector.fromArray(I_SPECIES, intArray, 0); + intVector2 = IntVector.fromArray(I_SPECIES, intArray2, 0); + intVectorMask = VectorMask.fromArray(I_SPECIES, intMask, 0); + intVectorMask2 = VectorMask.fromArray(I_SPECIES, intMask2, 0); + for (int i = 0; i < D_SPECIES.length(); i++) { + doubleArray[i] = (double) i + 1.0; + doubleArray2[i] = (double) (D_SPECIES.length() - i) + 1.0; + doubleMask[i] = i % 2 == 0; + doubleMask2[i] = i >= D_SPECIES.length() / 2; + doubleIndices[i] = (i + D_SPECIES.length() / 2) % D_SPECIES.length(); + doubleIndices2[i] = (D_SPECIES.length() - i) % D_SPECIES.length(); + duplicateDoubleIndices[i] = doubleIndices[i] / 2; + } + doubleVector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + doubleVector2 = DoubleVector.fromArray(D_SPECIES, doubleArray2, 0); + doubleVectorMask = VectorMask.fromArray(D_SPECIES, doubleMask, 0); + doubleVectorMask2 = VectorMask.fromArray(D_SPECIES, doubleMask2, 0); + for (int i = 0; i < F_SPECIES.length(); i++) { + floatArray[i] = i + 1.0f; + floatArray2[i] = F_SPECIES.length() - i + 1.0f; + floatMask[i] = i % 2 == 0; + floatMask2[i] = i >= F_SPECIES.length() / 2; + floatIndices[i] = (i + F_SPECIES.length() / 2) % F_SPECIES.length(); + floatIndices2[i] = (F_SPECIES.length() - i) % F_SPECIES.length(); + duplicateFloatIndices[i] = floatIndices[i] / 2; + } + floatVector = FloatVector.fromArray(F_SPECIES, floatArray, 0); + floatVector2 = FloatVector.fromArray(F_SPECIES, floatArray2, 0); + floatVectorMask = VectorMask.fromArray(F_SPECIES, floatMask, 0); + floatVectorMask2 = VectorMask.fromArray(F_SPECIES, floatMask2, 0); + } + + // LOAD TESTS + + // LongVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherNotEqualArray() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray2, 0, longIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherNotEqualIndices() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneLongVectorLoadGather() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_L, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneLongVectorLoadMasked() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherEquals() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadMaskedEquals() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoLongVectorLoadMaskedNotEqualMask() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherMaskedEquals() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherMaskedNotEqualMask() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorLoadGatherMaskedNotEqualIndices() { + LongVector res = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices2, 0, longVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherNotEqualArray() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray2, 0, intIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherNotEqualIndices() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneIntVectorLoadGather() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_I, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneIntVectorLoadMasked() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherEquals() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadMaskedEquals() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoIntVectorLoadMaskedNotEqualMask() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherMaskedEquals() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherMaskedNotEqualMask() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorLoadGatherMaskedNotEqualIndices() { + IntVector res = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices2, 0, intVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherNotEqualArray() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray2, 0, doubleIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherNotEqualIndices() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_D, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadGather() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_D, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadMasked() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherEquals() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadMaskedEquals() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadMaskedNotEqualMask() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherMaskedEquals() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherMaskedNotEqualMask() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorLoadGatherMaskedNotEqualIndices() { + DoubleVector res = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices2, 0, doubleVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherNotEqualArray() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray2, 0, floatIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherNotEqualIndices() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices2, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_F, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneFloatVectorLoadGather() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_F, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testOneFloatVectorLoadMasked() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherEquals() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadMaskedEquals() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx2", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadMaskedNotEqualMask() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherMaskedEquals() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + Asserts.assertEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherMaskedNotEqualMask() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask2); + Asserts.assertNotEquals(res, res2); + } + + @Test + @IR(counts = { IRNode.LOAD_VECTOR_GATHER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorLoadGatherMaskedNotEqualIndices() { + FloatVector res = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices2, 0, floatVectorMask); + Asserts.assertNotEquals(res, res2); + } + + + // STORE TESTS + + // LongVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterNotEqualVector() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0); + longVector2.intoArray(res2, 0, longIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterNotEqualIndices() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0); + longVector.intoArray(res2, 0, longIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreScatter() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0); + longVector.intoArray(res2, 0, longIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreMasked() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0); + longVector.intoArray(res2, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterEquals() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0); + longVector.intoArray(res2, 0, longIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreMaskedEquals() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longVectorMask); + longVector.intoArray(res2, 0, longVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreMaskedNotEqualMask() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longVectorMask); + longVector.intoArray(res2, 0, longVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterMaskedEquals() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0, longVectorMask); + longVector.intoArray(res2, 0, longIndices, 0, longVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterMaskedNotEqualMask() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0, longVectorMask); + longVector.intoArray(res2, 0, longIndices, 0, longVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoLongVectorStoreScatterMaskedNotEqualIndices() { + long[] res = new long[L_SPECIES.length()]; + long[] res2 = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longIndices, 0, longVectorMask); + longVector.intoArray(res2, 0, longIndices2, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterNotEqualVector() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0); + intVector2.intoArray(res2, 0, intIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterNotEqualIndices() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0); + intVector.intoArray(res2, 0, intIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreScatter() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0); + intVector.intoArray(res2, 0, intIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreMasked() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0); + intVector.intoArray(res2, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterEquals() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0); + intVector.intoArray(res2, 0, intIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreMaskedEquals() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intVectorMask); + intVector.intoArray(res2, 0, intVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreMaskedNotEqualMask() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intVectorMask); + intVector.intoArray(res2, 0, intVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterMaskedEquals() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0, intVectorMask); + intVector.intoArray(res2, 0, intIndices, 0, intVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterMaskedNotEqualMask() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0, intVectorMask); + intVector.intoArray(res2, 0, intIndices, 0, intVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoIntVectorStoreScatterMaskedNotEqualIndices() { + int[] res = new int[I_SPECIES.length()]; + int[] res2 = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intIndices, 0, intVectorMask); + intVector.intoArray(res2, 0, intIndices2, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterNotEqualVector() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0); + doubleVector2.intoArray(res2, 0, doubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterNotEqualIndices() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0); + doubleVector.intoArray(res2, 0, doubleIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreScatter() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0); + doubleVector.intoArray(res2, 0, doubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreMasked() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0); + doubleVector.intoArray(res2, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterEquals() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0); + doubleVector.intoArray(res2, 0, doubleIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreMaskedEquals() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreMaskedNotEqualMask() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterMaskedEquals() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleIndices, 0, doubleVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterMaskedNotEqualMask() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleIndices, 0, doubleVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoDoubleVectorStoreScatterMaskedNotEqualIndices() { + double[] res = new double[D_SPECIES.length()]; + double[] res2 = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleIndices, 0, doubleVectorMask); + doubleVector.intoArray(res2, 0, doubleIndices2, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterNotEqualVector() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0); + floatVector2.intoArray(res2, 0, floatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterNotEqualIndices() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0); + floatVector.intoArray(res2, 0, floatIndices2, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreScatter() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0); + floatVector.intoArray(res2, 0, floatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreMasked() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0); + floatVector.intoArray(res2, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterEquals() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0); + floatVector.intoArray(res2, 0, floatIndices, 0); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreMaskedEquals() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreMaskedNotEqualMask() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterMaskedEquals() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatIndices, 0, floatVectorMask); + Asserts.assertTrue(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterMaskedNotEqualMask() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatIndices, 0, floatVectorMask2); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER_MASKED, ">= 2" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testTwoFloatVectorStoreScatterMaskedNotEqualIndices() { + float[] res = new float[F_SPECIES.length()]; + float[] res2 = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatIndices, 0, floatVectorMask); + floatVector.intoArray(res2, 0, floatIndices2, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, res2)); + } + + + // STORE - LOAD tests + + // LongVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreLoadGather() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0, longIndices, 0); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreScatterLoad() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0, longIndices, 0); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreLoadMasked() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0, longVectorMask); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorStoreMaskedLoad() { + long[] array = new long[L_SPECIES.length()]; + longVector.intoArray(array, 0, longVectorMask); + LongVector res = LongVector.fromArray(L_SPECIES, array, 0); + Asserts.assertNotEquals(res, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorLoadGatherStoreScatterDuplicateIndicesVector() { + long[] res = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, duplicateLongIndices, 0); + LongVector res2 = LongVector.fromArray(L_SPECIES, res, 0, duplicateLongIndices, 0); + Asserts.assertNotEquals(res2, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorStoreLoadMaskedVector() { + long[] res = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0, longVectorMask); + LongVector res2 = LongVector.fromArray(L_SPECIES, res, 0, longVectorMask); + Asserts.assertNotEquals(res2, longVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadLongVectorDifferentSpeciesVector() { + long[] res = new long[L_SPECIES.length()]; + longVector.intoArray(res, 0); + LongVector res2 = LongVector.fromArray(LongVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, longVector); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreLoadGather() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0, intIndices, 0); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreScatterLoad() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0, intIndices, 0); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreLoadMasked() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0, intVectorMask); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorStoreMaskedLoad() { + int[] array = new int[I_SPECIES.length()]; + intVector.intoArray(array, 0, intVectorMask); + IntVector res = IntVector.fromArray(I_SPECIES, array, 0); + Asserts.assertNotEquals(res, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorLoadGatherStoreScatterDuplicateIndicesVector() { + int[] res = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, duplicateIntIndices, 0); + IntVector res2 = IntVector.fromArray(I_SPECIES, res, 0, duplicateIntIndices, 0); + Asserts.assertNotEquals(res2, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorStoreLoadMaskedVector() { + int[] res = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0, intVectorMask); + IntVector res2 = IntVector.fromArray(I_SPECIES, res, 0, intVectorMask); + Asserts.assertNotEquals(res2, intVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadIntVectorDifferentSpeciesVector() { + int[] res = new int[I_SPECIES.length()]; + intVector.intoArray(res, 0); + IntVector res2 = IntVector.fromArray(IntVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, intVector); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreLoadGather() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0, doubleIndices, 0); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreScatterLoad() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0, doubleIndices, 0); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreLoadMasked() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0, doubleVectorMask); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorStoreMaskedLoad() { + double[] array = new double[D_SPECIES.length()]; + doubleVector.intoArray(array, 0, doubleVectorMask); + DoubleVector res = DoubleVector.fromArray(D_SPECIES, array, 0); + Asserts.assertNotEquals(res, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorLoadGatherStoreScatterDuplicateIndicesVector() { + double[] res = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, duplicateDoubleIndices, 0); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, res, 0, duplicateDoubleIndices, 0); + Asserts.assertNotEquals(res2, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorStoreLoadMaskedVector() { + double[] res = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0, doubleVectorMask); + DoubleVector res2 = DoubleVector.fromArray(D_SPECIES, res, 0, doubleVectorMask); + Asserts.assertNotEquals(res2, doubleVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadDoubleVectorDifferentSpeciesVector() { + double[] res = new double[D_SPECIES.length()]; + doubleVector.intoArray(res, 0); + DoubleVector res2 = DoubleVector.fromArray(DoubleVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, doubleVector); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreLoadGather() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0, floatIndices, 0); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreScatterLoad() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0, floatIndices, 0); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreLoadMasked() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0, floatVectorMask); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorStoreMaskedLoad() { + float[] array = new float[F_SPECIES.length()]; + floatVector.intoArray(array, 0, floatVectorMask); + FloatVector res = FloatVector.fromArray(F_SPECIES, array, 0); + Asserts.assertNotEquals(res, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorLoadGatherStoreScatterDuplicateIndicesVector() { + float[] res = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, duplicateFloatIndices, 0); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, res, 0, duplicateFloatIndices, 0); + Asserts.assertNotEquals(res2, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorStoreLoadMaskedVector() { + float[] res = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0, floatVectorMask); + FloatVector res2 = FloatVector.fromArray(F_SPECIES, res, 0, floatVectorMask); + Asserts.assertNotEquals(res2, floatVector); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testStoreLoadFloatVectorDifferentSpeciesVector() { + float[] res = new float[F_SPECIES.length()]; + floatVector.intoArray(res, 0); + FloatVector res2 = FloatVector.fromArray(FloatVector.SPECIES_64, res, 0); + Asserts.assertNotEquals(res2, floatVector); + } + + + // LOAD - STORE tests + + // LongVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadGatherStore() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, longIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadStoreScatter() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0); + vector.intoArray(res, 0, longIndices, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadMaskedStore() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_L, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneLongVectorLoadStoreMasked() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0); + vector.intoArray(res, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorStoreScatterLoadGatherDuplicateIndicesVector() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, duplicateLongIndices, 0); + vector.intoArray(res, 0, duplicateLongIndices, 0); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testLongVectorLoadMaskedStoreVector() { + long[] res = new long[L_SPECIES.length()]; + LongVector vector = LongVector.fromArray(L_SPECIES, longArray, 0, longVectorMask); + vector.intoArray(res, 0, longVectorMask); + Asserts.assertFalse(Arrays.equals(res, longArray)); + } + + + // IntVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadGatherStore() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, intIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadStoreScatter() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0); + vector.intoArray(res, 0, intIndices, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadMaskedStore() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_I, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneIntVectorLoadStoreMasked() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0); + vector.intoArray(res, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorStoreScatterLoadGatherDuplicateIndicesVector() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, duplicateIntIndices, 0); + vector.intoArray(res, 0, duplicateIntIndices, 0); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testIntVectorLoadMaskedStoreVector() { + int[] res = new int[I_SPECIES.length()]; + IntVector vector = IntVector.fromArray(I_SPECIES, intArray, 0, intVectorMask); + vector.intoArray(res, 0, intVectorMask); + Asserts.assertFalse(Arrays.equals(res, intArray)); + } + + + // DoubleVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadGatherStore() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadStoreScatter() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + vector.intoArray(res, 0, doubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadMaskedStore() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_D, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneDoubleVectorLoadStoreMasked() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0); + vector.intoArray(res, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorStoreScatterLoadGatherDuplicateIndicesVector() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, duplicateDoubleIndices, 0); + vector.intoArray(res, 0, duplicateDoubleIndices, 0); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testDoubleVectorLoadMaskedStoreVector() { + double[] res = new double[D_SPECIES.length()]; + DoubleVector vector = DoubleVector.fromArray(D_SPECIES, doubleArray, 0, doubleVectorMask); + vector.intoArray(res, 0, doubleVectorMask); + Asserts.assertFalse(Arrays.equals(res, doubleArray)); + } + + + // FloatVector tests + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadGatherStore() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatIndices, 0); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadStoreScatter() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0); + vector.intoArray(res, 0, floatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadMaskedStore() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + vector.intoArray(res, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_F, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testOneFloatVectorLoadStoreMasked() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0); + vector.intoArray(res, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_SCATTER, ">= 1", IRNode.LOAD_VECTOR_GATHER, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorStoreScatterLoadGatherDuplicateIndicesVector() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, duplicateFloatIndices, 0); + vector.intoArray(res, 0, duplicateFloatIndices, 0); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + @Test + @IR(counts = { IRNode.STORE_VECTOR_MASKED, ">= 1", IRNode.LOAD_VECTOR_MASKED, ">= 1" }, applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}) + public static void testFloatVectorLoadMaskedStoreVector() { + float[] res = new float[F_SPECIES.length()]; + FloatVector vector = FloatVector.fromArray(F_SPECIES, floatArray, 0, floatVectorMask); + vector.intoArray(res, 0, floatVectorMask); + Asserts.assertFalse(Arrays.equals(res, floatArray)); + } + + + public static void main(String[] args) { + TestFramework testFramework = new TestFramework(); + testFramework.setDefaultWarmup(10000) + .addFlags("--add-modules=jdk.incubator.vector", "-XX:+IncrementalInlineForceCleanup") + .start(); + } +} From cfdc64fcb43e3b261dddc6cc6947235a9e76154e Mon Sep 17 00:00:00 2001 From: Adam Sotona Date: Fri, 24 May 2024 15:58:34 +0000 Subject: [PATCH 32/99] 8331291: java.lang.classfile.Attributes class performs a lot of static initializations Reviewed-by: liach, redestad, vromero --- .../java/lang/classfile/Attributes.java | 1228 +++++------------ .../impl/AbstractAttributeMapper.java | 760 +++++++++- .../classfile/impl/BoundAttribute.java | 92 +- .../internal/classfile/impl/ClassImpl.java | 57 +- .../classfile/impl/ClassReaderImpl.java | 4 +- .../jdk/internal/classfile/impl/CodeImpl.java | 18 +- .../classfile/impl/DirectCodeBuilder.java | 12 +- .../internal/classfile/impl/MethodImpl.java | 2 +- .../classfile/impl/SplitConstantPool.java | 2 +- .../classfile/impl/StackMapGenerator.java | 2 +- .../classfile/impl/UnboundAttribute.java | 70 +- .../jdk/internal/classfile/impl/Util.java | 2 +- .../impl/verifier/VerificationWrapper.java | 4 +- .../classes/sun/tools/jar/FingerPrint.java | 2 +- .../com/sun/tools/javap/AttributeWriter.java | 2 +- .../com/sun/tools/javap/ClassWriter.java | 20 +- .../com/sun/tools/javap/JavapTask.java | 2 +- .../tools/javap/LocalVariableTableWriter.java | 2 +- .../javap/LocalVariableTypeTableWriter.java | 2 +- .../com/sun/tools/javap/SourceWriter.java | 4 +- .../com/sun/tools/javap/StackMapWriter.java | 2 +- .../sun/tools/javap/TypeAnnotationWriter.java | 4 +- .../com/sun/tools/jdeps/Dependencies.java | 8 +- .../runtime/test/TestResolvedJavaMethod.java | 2 +- test/jdk/java/lang/StackWalker/TestBCI.java | 2 +- .../java/lang/invoke/lambda/LambdaAsm.java | 2 +- .../AdvancedTransformationsTest.java | 6 +- .../jdk/classfile/AnnotationModelTest.java | 2 +- test/jdk/jdk/classfile/AttributesTest.java | 55 + .../jdk/jdk/classfile/BoundAttributeTest.java | 2 +- test/jdk/jdk/classfile/CorpusTest.java | 6 +- .../jdk/classfile/FilterDeadLabelsTest.java | 6 +- test/jdk/jdk/classfile/LimitsTest.java | 4 +- .../jdk/classfile/LowJCovAttributeTest.java | 6 +- test/jdk/jdk/classfile/LvtTest.java | 4 +- .../MassAdaptCopyPrimitiveMatchCodeTest.java | 2 +- test/jdk/jdk/classfile/ModuleBuilderTest.java | 8 +- test/jdk/jdk/classfile/SignaturesTest.java | 12 +- .../jdk/classfile/TestRecordComponent.java | 4 +- .../examples/AnnotationsExamples.java | 25 +- .../classfile/examples/ModuleExamples.java | 6 +- .../jdk/classfile/helpers/ClassRecord.java | 130 +- .../helpers/RebuildingTransformation.java | 2 +- .../CallerSensitiveFinder.java | 2 +- .../reflect/CallerSensitive/CheckCSMs.java | 4 +- .../StripJavaDebugAttributesPluginTest.java | 8 +- .../tools/javac/4241573/T4241573.java | 2 +- .../tools/javac/7003595/T7003595.java | 2 +- .../8009170/RedundantByteCodeInArrayTest.java | 2 +- .../AnonymousClass/AnonymousClassFlags.java | 2 +- .../MethodParameters/ClassFileVisitor.java | 2 +- .../LegacyOutputTest/LegacyOutputTest.java | 2 +- .../tools/javac/MethodParametersTest.java | 4 +- .../ImplicitParameters.java | 2 +- .../StringConcat/TestIndyStringConcat.java | 5 +- .../StringConcat/WellKnownTypeSignatures.java | 2 +- .../tools/javac/StringConcat/access/Test.java | 2 +- ...ationsAreNotCopiedToBridgeMethodsTest.java | 4 +- .../DebugPointerAtBadPositionTest.java | 4 +- .../InlinedFinallyConfuseDebuggersTest.java | 4 +- .../tools/javac/T7053059/DoubleCastTest.java | 2 +- test/langtools/tools/javac/T7093325.java | 2 +- ...rClassAttrMustNotHaveStrictFPFlagTest.java | 2 +- .../javac/T8019486/WrongLNTForLambdaTest.java | 4 +- .../DeadCodeGeneratedForEmptyTryTest.java | 2 +- .../NoDeadCodeGenerationOnTrySmtTest.java | 2 +- .../DontGenerateLVTForGNoneOpTest.java | 4 +- .../MissingLNTEntryForBreakContinueTest.java | 4 +- .../MissingLNTEntryForFinalizerTest.java | 4 +- ...oLocalsMustBeReservedForDCEedVarsTest.java | 2 +- .../javac/T8222949/TestConstantDynamic.java | 6 +- .../TryWithResources/TwrSimpleClose.java | 2 +- .../ApplicableAnnotationsOnRecords.java | 6 +- .../TypeAnnotationsPositionsOnRecords.java | 6 +- .../VariablesDeclaredWithVarTest.java | 6 +- .../classfile/AnonymousClassTest.java | 20 +- .../classfile/ClassfileTestHelper.java | 10 +- .../classfile/NoTargetAnnotations.java | 4 +- .../classfile/TestAnonInnerClasses.java | 10 +- .../classfile/TestNewCastArray.java | 12 +- .../TypeAnnotationPropagationTest.java | 4 +- .../referenceinfos/ReferenceInfoUtil.java | 10 +- .../intersection/DuplicatedCheckcastTest.java | 2 +- .../InnerClasses/SyntheticClasses.java | 4 +- .../AnnotationDefaultTest.java | 2 +- .../EnclosingMethod/EnclosingMethodTest.java | 2 +- .../LineNumberTable/LineNumberTestBase.java | 6 +- .../attributes/LineNumberTable/T8050993.java | 4 +- .../LocalVariableTestBase.java | 2 +- .../attributes/Module/ModuleTestBase.java | 2 +- .../attributes/Signature/Driver.java | 6 +- .../SourceFile/NoSourceFileAttribute.java | 2 +- .../SourceFile/SourceFileTestBase.java | 2 +- .../Synthetic/SyntheticTestDriver.java | 6 +- .../RuntimeAnnotationsTestBase.java | 4 +- ...timeParameterAnnotationsForLambdaTest.java | 8 +- .../RuntimeParameterAnnotationsTestBase.java | 4 +- .../deprecated/DeprecatedPackageTest.java | 2 +- .../attributes/deprecated/DeprecatedTest.java | 10 +- .../InnerClassesHierarchyTest.java | 2 +- .../innerclasses/InnerClassesIndexTest.java | 2 +- .../innerclasses/InnerClassesTestBase.java | 2 +- .../innerclasses/NoInnerClassesTest.java | 2 +- .../IndyCorrectInvocationName.java | 4 +- .../tools/javac/code/CharImmediateValue.java | 2 +- .../javac/defaultMethods/TestDefaultBody.java | 2 +- .../super/TestDirectSuperInterfaceInvoke.java | 2 +- .../_super/NonDirectSuper/NonDirectSuper.java | 2 +- .../tools/javac/file/SymLinkTest.java | 2 +- .../tools/javac/flow/LVTHarness.java | 4 +- .../tools/javac/lambda/ByteCodeTest.java | 2 +- .../javac/lambda/LocalVariableTable.java | 4 +- .../lambda/TestBootstrapMethodsCount.java | 2 +- .../tools/javac/lambda/TestInvokeDynamic.java | 6 +- .../lambda/bytecode/TestLambdaBytecode.java | 4 +- .../TestLambdaBytecodeTargetRelease14.java | 4 +- .../deduplication/DeduplicationTest.java | 2 +- .../javac/launcher/SourceLauncherTest.java | 4 +- .../ConditionalLineNumberTest.java | 2 +- .../linenumbers/FinallyLineNumberTest.java | 2 +- .../linenumbers/NestedLineNumberTest.java | 2 +- .../linenumbers/NullCheckLineNumberTest.java | 2 +- test/langtools/tools/javac/meth/TestCP.java | 2 +- .../javac/modules/AnnotationsOnModules.java | 14 +- .../tools/javac/modules/JavaBaseTest.java | 2 +- .../tools/javac/modules/ModuleVersion.java | 2 +- .../tools/javac/modules/OpenModulesTest.java | 2 +- .../javac/multicatch/7005371/T7005371.java | 4 +- .../tools/javac/multicatch/Pos05.java | 2 +- .../tools/javac/patterns/Annotations.java | 4 +- .../javac/patterns/LocalVariableTable.java | 4 +- .../NestedPatternVariablesBytecode.java | 2 +- .../javac/patterns/NoUnnecessaryCast.java | 2 +- .../javac/platform/ModuleVersionTest.java | 2 +- .../processing/model/element/TestOrigin.java | 2 +- .../javac/records/RecordCompilationTests.java | 2 +- .../RecordComponentTypeTest.java | 2 +- .../sealed/SealedDiffConfigurationsTest.java | 4 +- .../tools/javac/varargs/6199075/T6199075.java | 2 +- .../tools/javac/varargs/7042566/T7042566.java | 2 +- test/langtools/tools/javap/T6716452.java | 4 +- .../javap/classfile/6888367/T6888367.java | 6 +- .../typeAnnotations/JSR175Annotations.java | 4 +- .../tools/javap/typeAnnotations/NewArray.java | 6 +- .../tools/javap/typeAnnotations/Presence.java | 6 +- .../javap/typeAnnotations/PresenceInner.java | 4 +- .../javap/typeAnnotations/TypeCasts.java | 6 +- .../javap/typeAnnotations/Visibility.java | 4 +- .../javap/typeAnnotations/Wildcards.java | 4 +- 149 files changed, 1670 insertions(+), 1324 deletions(-) create mode 100644 test/jdk/jdk/classfile/AttributesTest.java diff --git a/src/java.base/share/classes/java/lang/classfile/Attributes.java b/src/java.base/share/classes/java/lang/classfile/Attributes.java index 75e06e7c3f3..1e91090f8af 100644 --- a/src/java.base/share/classes/java/lang/classfile/Attributes.java +++ b/src/java.base/share/classes/java/lang/classfile/Attributes.java @@ -24,77 +24,74 @@ */ package java.lang.classfile; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import java.lang.classfile.attribute.AnnotationDefaultAttribute; -import java.lang.classfile.attribute.BootstrapMethodsAttribute; -import java.lang.classfile.attribute.CharacterRangeInfo; -import java.lang.classfile.attribute.CharacterRangeTableAttribute; -import java.lang.classfile.attribute.CodeAttribute; -import java.lang.classfile.attribute.CompilationIDAttribute; -import java.lang.classfile.attribute.ConstantValueAttribute; -import java.lang.classfile.attribute.DeprecatedAttribute; -import java.lang.classfile.attribute.EnclosingMethodAttribute; -import java.lang.classfile.attribute.ExceptionsAttribute; -import java.lang.classfile.attribute.InnerClassInfo; -import java.lang.classfile.attribute.InnerClassesAttribute; -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.attribute.LocalVariableTypeInfo; -import java.lang.classfile.attribute.LocalVariableTypeTableAttribute; -import java.lang.classfile.attribute.MethodParameterInfo; -import java.lang.classfile.attribute.MethodParametersAttribute; -import java.lang.classfile.attribute.ModuleAttribute; -import java.lang.classfile.attribute.ModuleExportInfo; -import java.lang.classfile.attribute.ModuleHashInfo; -import java.lang.classfile.attribute.ModuleHashesAttribute; -import java.lang.classfile.attribute.ModuleMainClassAttribute; -import java.lang.classfile.attribute.ModuleOpenInfo; -import java.lang.classfile.attribute.ModulePackagesAttribute; -import java.lang.classfile.attribute.ModuleProvideInfo; -import java.lang.classfile.attribute.ModuleRequireInfo; -import java.lang.classfile.attribute.ModuleResolutionAttribute; -import java.lang.classfile.attribute.ModuleTargetAttribute; -import java.lang.classfile.attribute.NestHostAttribute; -import java.lang.classfile.attribute.NestMembersAttribute; -import java.lang.classfile.attribute.PermittedSubclassesAttribute; -import java.lang.classfile.attribute.RecordAttribute; -import java.lang.classfile.attribute.RecordComponentInfo; -import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeInvisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute; -import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; -import java.lang.classfile.attribute.SignatureAttribute; -import java.lang.classfile.attribute.SourceDebugExtensionAttribute; -import java.lang.classfile.attribute.SourceFileAttribute; -import java.lang.classfile.attribute.SourceIDAttribute; -import java.lang.classfile.attribute.StackMapTableAttribute; -import java.lang.classfile.attribute.SyntheticAttribute; -import java.lang.classfile.constantpool.Utf8Entry; -import jdk.internal.classfile.impl.AbstractAttributeMapper; -import jdk.internal.classfile.impl.BoundAttribute; -import jdk.internal.classfile.impl.CodeImpl; -import jdk.internal.classfile.impl.AbstractPoolEntry; -import jdk.internal.classfile.impl.StackMapDecoder; +import java.lang.classfile.AttributeMapper.AttributeStability; +import java.lang.classfile.attribute.*; +import jdk.internal.classfile.impl.AbstractAttributeMapper.*; import jdk.internal.javac.PreviewFeature; /** * Attribute mappers for standard classfile attributes. + *

    + * Unless otherwise specified, mappers returned by each method + * do not permit multiple attribute instances in a given location. + *

    + * The most stable {@link AttributeStability#STATELESS STATELESS} mappers are: + *

      + *
    • {@link #deprecated()} + *
    • {@link #moduleResolution()} + *
    • {@link #sourceDebugExtension()} + *
    • {@link #synthetic()} + *
    + * + * The mappers with {@link AttributeStability#CP_REFS CP_REFS} stability are: + *
      + *
    • {@link #annotationDefault()} + *
    • {@link #bootstrapMethods()} + *
    • {@link #code()} + *
    • {@link #compilationId()} + *
    • {@link #constantValue()} + *
    • {@link #enclosingMethod()} + *
    • {@link #exceptions()} + *
    • {@link #innerClasses()} + *
    • {@link #methodParameters()} + *
    • {@link #module()} + *
    • {@link #moduleHashes()} + *
    • {@link #moduleMainClass()} + *
    • {@link #modulePackages()} + *
    • {@link #moduleTarget()} + *
    • {@link #nestHost()} + *
    • {@link #nestMembers()} + *
    • {@link #permittedSubclasses()} + *
    • {@link #record()} + *
    • {@link #runtimeInvisibleAnnotations()} + *
    • {@link #runtimeInvisibleParameterAnnotations()} + *
    • {@link #runtimeVisibleAnnotations()} + *
    • {@link #runtimeVisibleParameterAnnotations()} + *
    • {@link #signature()} + *
    • {@link #sourceFile()} + *
    • {@link #sourceId()} + *
    + * + * The mappers with {@link AttributeStability#LABELS LABELS} stability are: + *
      + *
    • {@link #characterRangeTable()} + *
    • {@link #lineNumberTable()} + *
    • {@link #localVariableTable()} + *
    • {@link #localVariableTypeTable()} + *
    + * + * The {@link AttributeStability#UNSTABLE UNSTABLE} mappers are: + *
      + *
    • {@link #runtimeInvisibleTypeAnnotations()} + *
    • {@link #runtimeVisibleTypeAnnotations()} + *
    * * @see AttributeMapper * * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) -public class Attributes { +public final class Attributes { /** AnnotationDefault */ public static final String NAME_ANNOTATION_DEFAULT = "AnnotationDefault"; @@ -207,836 +204,297 @@ public class Attributes { private Attributes() { } - /** Attribute mapper for the {@code AnnotationDefault} attribute */ - public static final AttributeMapper - ANNOTATION_DEFAULT = new AbstractAttributeMapper<>(NAME_ANNOTATION_DEFAULT) { - @Override - public AnnotationDefaultAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundAnnotationDefaultAttr(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, AnnotationDefaultAttribute attr) { - attr.defaultValue().writeTo(buf); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code BootstrapMethods} attribute */ - public static final AttributeMapper - BOOTSTRAP_METHODS = new AbstractAttributeMapper<>(NAME_BOOTSTRAP_METHODS) { - @Override - public BootstrapMethodsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundBootstrapMethodsAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, BootstrapMethodsAttribute attr) { - buf.writeList(attr.bootstrapMethods()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code CharacterRangeTable} attribute */ - public static final AttributeMapper - CHARACTER_RANGE_TABLE = new AbstractAttributeMapper<>(NAME_CHARACTER_RANGE_TABLE, true) { - @Override - public CharacterRangeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundCharacterRangeTableAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, CharacterRangeTableAttribute attr) { - List ranges = attr.characterRangeTable(); - buf.writeU2(ranges.size()); - for (CharacterRangeInfo info : ranges) { - buf.writeU2(info.startPc()); - buf.writeU2(info.endPc()); - buf.writeInt(info.characterRangeStart()); - buf.writeInt(info.characterRangeEnd()); - buf.writeU2(info.flags()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.LABELS; - } - }; - - /** Attribute mapper for the {@code Code} attribute */ - public static final AttributeMapper - CODE = new AbstractAttributeMapper<>(NAME_CODE) { - @Override - public CodeAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new CodeImpl(e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, CodeAttribute attr) { - throw new UnsupportedOperationException("Code attribute does not support direct write"); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - - /** Attribute mapper for the {@code CompilationID} attribute */ - public static final AttributeMapper - COMPILATION_ID = new AbstractAttributeMapper<>(NAME_COMPILATION_ID, true) { - @Override - public CompilationIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundCompilationIDAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, CompilationIDAttribute attr) { - buf.writeIndex(attr.compilationId()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code ConstantValue} attribute */ - public static final AttributeMapper - CONSTANT_VALUE = new AbstractAttributeMapper<>(NAME_CONSTANT_VALUE) { - @Override - public ConstantValueAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundConstantValueAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ConstantValueAttribute attr) { - buf.writeIndex(attr.constant()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code Deprecated} attribute */ - public static final AttributeMapper - DEPRECATED = new AbstractAttributeMapper<>(NAME_DEPRECATED, true) { - @Override - public DeprecatedAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundDeprecatedAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, DeprecatedAttribute attr) { - // empty - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.STATELESS; - } - }; - - /** Attribute mapper for the {@code EnclosingMethod} attribute */ - public static final AttributeMapper - ENCLOSING_METHOD = new AbstractAttributeMapper<>(NAME_ENCLOSING_METHOD) { - @Override - public EnclosingMethodAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundEnclosingMethodAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, EnclosingMethodAttribute attr) { - buf.writeIndex(attr.enclosingClass()); - buf.writeIndexOrZero(attr.enclosingMethod().orElse(null)); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code Exceptions} attribute */ - public static final AttributeMapper - EXCEPTIONS = new AbstractAttributeMapper<>(NAME_EXCEPTIONS) { - @Override - public ExceptionsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundExceptionsAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ExceptionsAttribute attr) { - buf.writeListIndices(attr.exceptions()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code InnerClasses} attribute */ - public static final AttributeMapper - INNER_CLASSES = new AbstractAttributeMapper<>(NAME_INNER_CLASSES) { - @Override - public InnerClassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundInnerClassesAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, InnerClassesAttribute attr) { - List classes = attr.classes(); - buf.writeU2(classes.size()); - for (InnerClassInfo ic : classes) { - buf.writeIndex(ic.innerClass()); - buf.writeIndexOrZero(ic.outerClass().orElse(null)); - buf.writeIndexOrZero(ic.innerName().orElse(null)); - buf.writeU2(ic.flagsMask()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code LineNumberTable} attribute */ - public static final AttributeMapper - LINE_NUMBER_TABLE = new AbstractAttributeMapper<>(NAME_LINE_NUMBER_TABLE, true) { - @Override - public LineNumberTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundLineNumberTableAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, LineNumberTableAttribute attr) { - List lines = attr.lineNumbers(); - buf.writeU2(lines.size()); - for (LineNumberInfo line : lines) { - buf.writeU2(line.startPc()); - buf.writeU2(line.lineNumber()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.LABELS; - } - }; - - /** Attribute mapper for the {@code LocalVariableTable} attribute */ - public static final AttributeMapper - LOCAL_VARIABLE_TABLE = new AbstractAttributeMapper<>(NAME_LOCAL_VARIABLE_TABLE, true) { - @Override - public LocalVariableTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundLocalVariableTableAttribute(e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, LocalVariableTableAttribute attr) { - List infos = attr.localVariables(); - buf.writeU2(infos.size()); - for (LocalVariableInfo info : infos) { - buf.writeU2(info.startPc()); - buf.writeU2(info.length()); - buf.writeIndex(info.name()); - buf.writeIndex(info.type()); - buf.writeU2(info.slot()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.LABELS; - } - }; - - /** Attribute mapper for the {@code LocalVariableTypeTable} attribute */ - public static final AttributeMapper - LOCAL_VARIABLE_TYPE_TABLE = new AbstractAttributeMapper<>(NAME_LOCAL_VARIABLE_TYPE_TABLE, true) { - @Override - public LocalVariableTypeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundLocalVariableTypeTableAttribute(e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, LocalVariableTypeTableAttribute attr) { - List infos = attr.localVariableTypes(); - buf.writeU2(infos.size()); - for (LocalVariableTypeInfo info : infos) { - buf.writeU2(info.startPc()); - buf.writeU2(info.length()); - buf.writeIndex(info.name()); - buf.writeIndex(info.signature()); - buf.writeU2(info.slot()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.LABELS; - } - }; - - /** Attribute mapper for the {@code MethodParameters} attribute */ - public static final AttributeMapper - METHOD_PARAMETERS = new AbstractAttributeMapper<>(NAME_METHOD_PARAMETERS) { - @Override - public MethodParametersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundMethodParametersAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, MethodParametersAttribute attr) { - List parameters = attr.parameters(); - buf.writeU1(parameters.size()); - for (MethodParameterInfo info : parameters) { - buf.writeIndexOrZero(info.name().orElse(null)); - buf.writeU2(info.flagsMask()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code Module} attribute */ - public static final AttributeMapper - MODULE = new AbstractAttributeMapper<>(NAME_MODULE) { - @Override - public ModuleAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModuleAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModuleAttribute attr) { - buf.writeIndex(attr.moduleName()); - buf.writeU2(attr.moduleFlagsMask()); - buf.writeIndexOrZero(attr.moduleVersion().orElse(null)); - buf.writeU2(attr.requires().size()); - for (ModuleRequireInfo require : attr.requires()) { - buf.writeIndex(require.requires()); - buf.writeU2(require.requiresFlagsMask()); - buf.writeIndexOrZero(require.requiresVersion().orElse(null)); - } - buf.writeU2(attr.exports().size()); - for (ModuleExportInfo export : attr.exports()) { - buf.writeIndex(export.exportedPackage()); - buf.writeU2(export.exportsFlagsMask()); - buf.writeListIndices(export.exportsTo()); - } - buf.writeU2(attr.opens().size()); - for (ModuleOpenInfo open : attr.opens()) { - buf.writeIndex(open.openedPackage()); - buf.writeU2(open.opensFlagsMask()); - buf.writeListIndices(open.opensTo()); - } - buf.writeListIndices(attr.uses()); - buf.writeU2(attr.provides().size()); - for (ModuleProvideInfo provide : attr.provides()) { - buf.writeIndex(provide.provides()); - buf.writeListIndices(provide.providesWith()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code ModuleHashes} attribute */ - public static final AttributeMapper - MODULE_HASHES = new AbstractAttributeMapper<>(NAME_MODULE_HASHES) { - @Override - public ModuleHashesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModuleHashesAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModuleHashesAttribute attr) { - buf.writeIndex(attr.algorithm()); - List hashes = attr.hashes(); - buf.writeU2(hashes.size()); - for (ModuleHashInfo hash : hashes) { - buf.writeIndex(hash.moduleName()); - buf.writeU2(hash.hash().length); - buf.writeBytes(hash.hash()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code ModuleMainClass} attribute */ - public static final AttributeMapper - MODULE_MAIN_CLASS = new AbstractAttributeMapper<>(NAME_MODULE_MAIN_CLASS) { - @Override - public ModuleMainClassAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModuleMainClassAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModuleMainClassAttribute attr) { - buf.writeIndex(attr.mainClass()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code ModulePackages} attribute */ - public static final AttributeMapper - MODULE_PACKAGES = new AbstractAttributeMapper<>(NAME_MODULE_PACKAGES) { - @Override - public ModulePackagesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModulePackagesAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModulePackagesAttribute attr) { - buf.writeListIndices(attr.packages()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code ModuleResolution} attribute */ - public static final AttributeMapper - MODULE_RESOLUTION = new AbstractAttributeMapper<>(NAME_MODULE_RESOLUTION) { - @Override - public ModuleResolutionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModuleResolutionAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModuleResolutionAttribute attr) { - buf.writeU2(attr.resolutionFlags()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.STATELESS; - } - }; - - /** Attribute mapper for the {@code ModuleTarget} attribute */ - public static final AttributeMapper - MODULE_TARGET = new AbstractAttributeMapper<>(NAME_MODULE_TARGET) { - @Override - public ModuleTargetAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundModuleTargetAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, ModuleTargetAttribute attr) { - buf.writeIndex(attr.targetPlatform()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code NestHost} attribute */ - public static final AttributeMapper - NEST_HOST = new AbstractAttributeMapper<>(NAME_NEST_HOST) { - @Override - public NestHostAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundNestHostAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, NestHostAttribute attr) { - buf.writeIndex(attr.nestHost()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code NestMembers} attribute */ - public static final AttributeMapper - NEST_MEMBERS = new AbstractAttributeMapper<>(NAME_NEST_MEMBERS) { - @Override - public NestMembersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundNestMembersAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, NestMembersAttribute attr) { - buf.writeListIndices(attr.nestMembers()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code PermittedSubclasses} attribute */ - public static final AttributeMapper - PERMITTED_SUBCLASSES = new AbstractAttributeMapper<>(NAME_PERMITTED_SUBCLASSES) { - @Override - public PermittedSubclassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundPermittedSubclassesAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, PermittedSubclassesAttribute attr) { - buf.writeListIndices(attr.permittedSubclasses()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code Record} attribute */ - public static final AttributeMapper - RECORD = new AbstractAttributeMapper<>(NAME_RECORD) { - @Override - public RecordAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundRecordAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, RecordAttribute attr) { - List components = attr.components(); - buf.writeU2(components.size()); - for (RecordComponentInfo info : components) { - buf.writeIndex(info.name()); - buf.writeIndex(info.descriptor()); - buf.writeList(info.attributes()); - } - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code RuntimeInvisibleAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_INVISIBLE_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_INVISIBLE_ANNOTATIONS) { - @Override - public RuntimeInvisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { - return new BoundAttribute.BoundRuntimeInvisibleAnnotationsAttribute(cf, pos); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeInvisibleAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code RuntimeInvisibleParameterAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) { - @Override - public RuntimeInvisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundRuntimeInvisibleParameterAnnotationsAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeInvisibleParameterAnnotationsAttribute attr) { - List> lists = attr.parameterAnnotations(); - buf.writeU1(lists.size()); - for (List list : lists) - buf.writeList(list); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code RuntimeInvisibleTypeAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) { - @Override - public RuntimeInvisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundRuntimeInvisibleTypeAnnotationsAttribute(e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.UNSTABLE; - } - }; - - /** Attribute mapper for the {@code RuntimeVisibleAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_VISIBLE_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_VISIBLE_ANNOTATIONS) { - @Override - public RuntimeVisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { - return new BoundAttribute.BoundRuntimeVisibleAnnotationsAttribute(cf, pos); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeVisibleAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code RuntimeVisibleParameterAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS) { - @Override - public RuntimeVisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundRuntimeVisibleParameterAnnotationsAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeVisibleParameterAnnotationsAttribute attr) { - List> lists = attr.parameterAnnotations(); - buf.writeU1(lists.size()); - for (List list : lists) - buf.writeList(list); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code RuntimeVisibleTypeAnnotations} attribute */ - public static final AttributeMapper - RUNTIME_VISIBLE_TYPE_ANNOTATIONS = new AbstractAttributeMapper<>(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS) { - @Override - public RuntimeVisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundRuntimeVisibleTypeAnnotationsAttribute(e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) { - buf.writeList(attr.annotations()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.UNSTABLE; - } - }; - - /** Attribute mapper for the {@code Signature} attribute */ - public static final AttributeMapper - SIGNATURE = new AbstractAttributeMapper<>(NAME_SIGNATURE) { - @Override - public SignatureAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundSignatureAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, SignatureAttribute attr) { - buf.writeIndex(attr.signature()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code SourceDebugExtension} attribute */ - public static final AttributeMapper - SOURCE_DEBUG_EXTENSION = new AbstractAttributeMapper<>(NAME_SOURCE_DEBUG_EXTENSION) { - @Override - public SourceDebugExtensionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundSourceDebugExtensionAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, SourceDebugExtensionAttribute attr) { - buf.writeBytes(attr.contents()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.STATELESS; - } - }; - - /** Attribute mapper for the {@code SourceFile} attribute */ - public static final AttributeMapper - SOURCE_FILE = new AbstractAttributeMapper<>(NAME_SOURCE_FILE) { - @Override - public SourceFileAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundSourceFileAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, SourceFileAttribute attr) { - buf.writeIndex(attr.sourceFile()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code SourceID} attribute */ - public static final AttributeMapper - SOURCE_ID = new AbstractAttributeMapper<>(NAME_SOURCE_ID) { - @Override - public SourceIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundSourceIDAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, SourceIDAttribute attr) { - buf.writeIndex(attr.sourceId()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.CP_REFS; - } - }; - - /** Attribute mapper for the {@code StackMapTable} attribute */ - public static final AttributeMapper - STACK_MAP_TABLE = new AbstractAttributeMapper<>(NAME_STACK_MAP_TABLE) { - @Override - public StackMapTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundStackMapTableAttribute((CodeImpl)e, cf, this, p); - } - - @Override - protected void writeBody(BufWriter b, StackMapTableAttribute attr) { - StackMapDecoder.writeFrames(b, attr.entries()); - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.LABELS; - } - }; - - - /** Attribute mapper for the {@code Synthetic} attribute */ - public static final AttributeMapper - SYNTHETIC = new AbstractAttributeMapper<>(NAME_SYNTHETIC, true) { - @Override - public SyntheticAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { - return new BoundAttribute.BoundSyntheticAttribute(cf, this, p); - } - - @Override - protected void writeBody(BufWriter buf, SyntheticAttribute attr) { - // empty - } - - @Override - public AttributeMapper.AttributeStability stability() { - return AttributeStability.STATELESS; - } - }; + /** + * {@return Attribute mapper for the {@code AnnotationDefault} attribute} + * @since 23 + */ + public static AttributeMapper annotationDefault() { + return AnnotationDefaultMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code BootstrapMethods} attribute} + * @since 23 + */ + public static AttributeMapper bootstrapMethods() { + return BootstrapMethodsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code CharacterRangeTable} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 + */ + public static AttributeMapper characterRangeTable() { + return CharacterRangeTableMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Code} attribute} + * @since 23 + */ + public static AttributeMapper code() { + return CodeMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code CompilationID} attribute} + * @since 23 + */ + public static AttributeMapper compilationId() { + return CompilationIDMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ConstantValue} attribute} + * @since 23 + */ + public static AttributeMapper constantValue() { + return ConstantValueMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Deprecated} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 + */ + public static AttributeMapper deprecated() { + return DeprecatedMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code EnclosingMethod} attribute} + * @since 23 + */ + public static AttributeMapper enclosingMethod() { + return EnclosingMethodMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Exceptions} attribute} + * @since 23 + */ + public static AttributeMapper exceptions() { + return ExceptionsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code InnerClasses} attribute} + * @since 23 + */ + public static AttributeMapper innerClasses() { + return InnerClassesMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code LineNumberTable} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 + */ + public static AttributeMapper lineNumberTable() { + return LineNumberTableMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code LocalVariableTable} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 + */ + public static AttributeMapper localVariableTable() { + return LocalVariableTableMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code LocalVariableTypeTable} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 + */ + public static AttributeMapper localVariableTypeTable() { + return LocalVariableTypeTableMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code MethodParameters} attribute} + * @since 23 + */ + public static AttributeMapper methodParameters() { + return MethodParametersMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Module} attribute} + * @since 23 + */ + public static AttributeMapper module() { + return ModuleMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ModuleHashes} attribute} + * @since 23 + */ + public static AttributeMapper moduleHashes() { + return ModuleHashesMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ModuleMainClass} attribute} + * @since 23 + */ + public static AttributeMapper moduleMainClass() { + return ModuleMainClassMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ModulePackages} attribute} + * @since 23 + */ + public static AttributeMapper modulePackages() { + return ModulePackagesMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ModuleResolution} attribute} + * @since 23 + */ + public static AttributeMapper moduleResolution() { + return ModuleResolutionMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code ModuleTarget} attribute} + * @since 23 + */ + public static AttributeMapper moduleTarget() { + return ModuleTargetMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code NestHost} attribute} + * @since 23 + */ + public static AttributeMapper nestHost() { + return NestHostMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code NestMembers} attribute} + * @since 23 + */ + public static AttributeMapper nestMembers() { + return NestMembersMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code PermittedSubclasses} attribute} + * @since 23 + */ + public static AttributeMapper permittedSubclasses() { + return PermittedSubclassesMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Record} attribute} + * @since 23 + */ + public static AttributeMapper record() { + return RecordMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeInvisibleAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeInvisibleAnnotations() { + return RuntimeInvisibleAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeInvisibleParameterAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeInvisibleParameterAnnotations() { + return RuntimeInvisibleParameterAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeInvisibleTypeAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeInvisibleTypeAnnotations() { + return RuntimeInvisibleTypeAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeVisibleAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeVisibleAnnotations() { + return RuntimeVisibleAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeVisibleParameterAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeVisibleParameterAnnotations() { + return RuntimeVisibleParameterAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code RuntimeVisibleTypeAnnotations} attribute} + * @since 23 + */ + public static AttributeMapper runtimeVisibleTypeAnnotations() { + return RuntimeVisibleTypeAnnotationsMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code Signature} attribute} + * @since 23 + */ + public static AttributeMapper signature() { + return SignatureMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code SourceDebugExtension} attribute} + * @since 23 + */ + public static AttributeMapper sourceDebugExtension() { + return SourceDebugExtensionMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code SourceFile} attribute} + * @since 23 + */ + public static AttributeMapper sourceFile() { + return SourceFileMapper.INSTANCE; + } + + /** + * {@return Attribute mapper for the {@code SourceID} attribute} + * @since 23 + */ + public static AttributeMapper sourceId() { + return SourceIDMapper.INSTANCE; + } /** - * {@return the attribute mapper for a standard attribute} - * - * @param name the name of the attribute to find + * {@return Attribute mapper for the {@code StackMapTable} attribute} + * @since 23 */ - public static AttributeMapper standardAttribute(Utf8Entry name) { - return _ATTR_MAP.get(name); + public static AttributeMapper stackMapTable() { + return StackMapTableMapper.INSTANCE; } /** - * All standard attribute mappers. + * {@return Attribute mapper for the {@code Synthetic} attribute} + * The mapper permits multiple instances in a given location. + * @since 23 */ - public static final Set> PREDEFINED_ATTRIBUTES = Set.of( - ANNOTATION_DEFAULT, - BOOTSTRAP_METHODS, - CHARACTER_RANGE_TABLE, - CODE, - COMPILATION_ID, - CONSTANT_VALUE, - DEPRECATED, - ENCLOSING_METHOD, - EXCEPTIONS, - INNER_CLASSES, - LINE_NUMBER_TABLE, - LOCAL_VARIABLE_TABLE, - LOCAL_VARIABLE_TYPE_TABLE, - METHOD_PARAMETERS, - MODULE, - MODULE_HASHES, - MODULE_MAIN_CLASS, - MODULE_PACKAGES, - MODULE_RESOLUTION, - MODULE_TARGET, - NEST_HOST, - NEST_MEMBERS, - PERMITTED_SUBCLASSES, - RECORD, - RUNTIME_INVISIBLE_ANNOTATIONS, - RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, - RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, - RUNTIME_VISIBLE_ANNOTATIONS, - RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, - RUNTIME_VISIBLE_TYPE_ANNOTATIONS, - SIGNATURE, - SOURCE_DEBUG_EXTENSION, - SOURCE_FILE, - SOURCE_ID, - STACK_MAP_TABLE, - SYNTHETIC); - - private static final Map> _ATTR_MAP; - //no lambdas here as this is on critical JDK boostrap path - static { - var map = new HashMap>(64); - for (var am : PREDEFINED_ATTRIBUTES) { - map.put(AbstractPoolEntry.rawUtf8EntryFromStandardAttributeName(am.name()), am); - } - _ATTR_MAP = Collections.unmodifiableMap(map); + public static AttributeMapper synthetic() { + return SyntheticMapper.INSTANCE; } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java index 861bcd3b601..9bb3f275ba1 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractAttributeMapper.java @@ -24,35 +24,45 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.Annotation; import java.lang.classfile.Attribute; import java.lang.classfile.AttributeMapper; +import java.lang.classfile.AttributedElement; import java.lang.classfile.BufWriter; +import java.lang.classfile.ClassReader; +import java.lang.classfile.attribute.*; +import java.util.List; -public abstract class AbstractAttributeMapper> +import static java.lang.classfile.Attributes.*; + +public sealed abstract class AbstractAttributeMapper> implements AttributeMapper { private final String name; + private final AttributeMapper.AttributeStability stability; private final boolean allowMultiple; protected abstract void writeBody(BufWriter buf, T attr); - public AbstractAttributeMapper(String name) { - this(name, false); + public AbstractAttributeMapper(String name, AttributeMapper.AttributeStability stability) { + this(name, stability, false); } public AbstractAttributeMapper(String name, + AttributeMapper.AttributeStability stability, boolean allowMultiple) { this.name = name; + this.stability = stability; this.allowMultiple = allowMultiple; } @Override - public String name() { + public final String name() { return name; } @Override - public void writeAttribute(BufWriter buf, T attr) { + public final void writeAttribute(BufWriter buf, T attr) { buf.writeIndex(buf.constantPool().utf8Entry(name)); buf.writeInt(0); int start = buf.size(); @@ -61,6 +71,11 @@ public void writeAttribute(BufWriter buf, T attr) { buf.patchInt(start - 4, 4, written); } + @Override + public AttributeMapper.AttributeStability stability() { + return stability; + } + @Override public boolean allowMultiple() { return allowMultiple; @@ -71,4 +86,739 @@ public String toString() { return String.format("AttributeMapper[name=%s, allowMultiple=%b, stability=%s]", name, allowMultiple, stability()); } + + public static final class AnnotationDefaultMapper extends AbstractAttributeMapper { + public static final AnnotationDefaultMapper INSTANCE = new AnnotationDefaultMapper(); + + private AnnotationDefaultMapper() { + super(NAME_ANNOTATION_DEFAULT, AttributeStability.CP_REFS); + } + + @Override + public AnnotationDefaultAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundAnnotationDefaultAttr(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, AnnotationDefaultAttribute attr) { + attr.defaultValue().writeTo(buf); + } + } + + public static final class BootstrapMethodsMapper extends AbstractAttributeMapper { + public static final BootstrapMethodsMapper INSTANCE = new BootstrapMethodsMapper(); + + private BootstrapMethodsMapper() { + super(NAME_BOOTSTRAP_METHODS, AttributeStability.CP_REFS); + } + + @Override + public BootstrapMethodsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundBootstrapMethodsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, BootstrapMethodsAttribute attr) { + buf.writeList(attr.bootstrapMethods()); + } + } + + public static final class CharacterRangeTableMapper extends AbstractAttributeMapper { + public static final CharacterRangeTableMapper INSTANCE = new CharacterRangeTableMapper(); + + private CharacterRangeTableMapper() { + super(NAME_CHARACTER_RANGE_TABLE, AttributeStability.LABELS, true); + } + + @Override + public CharacterRangeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundCharacterRangeTableAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, CharacterRangeTableAttribute attr) { + List ranges = attr.characterRangeTable(); + buf.writeU2(ranges.size()); + for (CharacterRangeInfo info : ranges) { + buf.writeU2(info.startPc()); + buf.writeU2(info.endPc()); + buf.writeInt(info.characterRangeStart()); + buf.writeInt(info.characterRangeEnd()); + buf.writeU2(info.flags()); + } + } + } + + public static final class CodeMapper extends AbstractAttributeMapper { + public static final CodeMapper INSTANCE = new CodeMapper(); + + private CodeMapper() { + super(NAME_CODE, AttributeStability.CP_REFS); + } + + @Override + public CodeAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new CodeImpl(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, CodeAttribute attr) { + throw new UnsupportedOperationException("Code attribute does not support direct write"); + } + } + + public static final class CompilationIDMapper extends AbstractAttributeMapper { + public static final CompilationIDMapper INSTANCE = new CompilationIDMapper(); + + private CompilationIDMapper() { + super(NAME_COMPILATION_ID, AttributeStability.CP_REFS); + } + + @Override + public CompilationIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundCompilationIDAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, CompilationIDAttribute attr) { + buf.writeIndex(attr.compilationId()); + } + } + + public static final class ConstantValueMapper extends AbstractAttributeMapper { + public static final ConstantValueMapper INSTANCE = new ConstantValueMapper(); + + private ConstantValueMapper() { + super(NAME_CONSTANT_VALUE, AttributeStability.CP_REFS); + } + + @Override + public ConstantValueAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundConstantValueAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ConstantValueAttribute attr) { + buf.writeIndex(attr.constant()); + } + } + + public static final class DeprecatedMapper extends AbstractAttributeMapper { + public static final DeprecatedMapper INSTANCE = new DeprecatedMapper(); + + private DeprecatedMapper() { + super(NAME_DEPRECATED, AttributeStability.STATELESS, true); + } + + @Override + public DeprecatedAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundDeprecatedAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, DeprecatedAttribute attr) { + // empty + } + } + + public static final class EnclosingMethodMapper extends AbstractAttributeMapper { + public static final EnclosingMethodMapper INSTANCE = new EnclosingMethodMapper(); + + private EnclosingMethodMapper() { + super(NAME_ENCLOSING_METHOD, AttributeStability.CP_REFS); + } + + @Override + public EnclosingMethodAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundEnclosingMethodAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, EnclosingMethodAttribute attr) { + buf.writeIndex(attr.enclosingClass()); + buf.writeIndexOrZero(attr.enclosingMethod().orElse(null)); + } + } + + public static final class ExceptionsMapper extends AbstractAttributeMapper { + public static final ExceptionsMapper INSTANCE = new ExceptionsMapper(); + + private ExceptionsMapper() { + super(NAME_EXCEPTIONS, AttributeStability.CP_REFS); + } + + @Override + public ExceptionsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundExceptionsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ExceptionsAttribute attr) { + buf.writeListIndices(attr.exceptions()); + } + } + + public static final class InnerClassesMapper extends AbstractAttributeMapper { + public static final InnerClassesMapper INSTANCE = new InnerClassesMapper(); + + private InnerClassesMapper() { + super(NAME_INNER_CLASSES, AttributeStability.CP_REFS); + } + + @Override + public InnerClassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundInnerClassesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, InnerClassesAttribute attr) { + List classes = attr.classes(); + buf.writeU2(classes.size()); + for (InnerClassInfo ic : classes) { + buf.writeIndex(ic.innerClass()); + buf.writeIndexOrZero(ic.outerClass().orElse(null)); + buf.writeIndexOrZero(ic.innerName().orElse(null)); + buf.writeU2(ic.flagsMask()); + } + } + } + + public static final class LineNumberTableMapper extends AbstractAttributeMapper { + public static final LineNumberTableMapper INSTANCE = new LineNumberTableMapper(); + + private LineNumberTableMapper() { + super(NAME_LINE_NUMBER_TABLE, AttributeStability.LABELS, true); + } + + @Override + public LineNumberTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundLineNumberTableAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, LineNumberTableAttribute attr) { + List lines = attr.lineNumbers(); + buf.writeU2(lines.size()); + for (LineNumberInfo line : lines) { + buf.writeU2(line.startPc()); + buf.writeU2(line.lineNumber()); + } + } + } + + public static final class LocalVariableTableMapper extends AbstractAttributeMapper { + public static final LocalVariableTableMapper INSTANCE = new LocalVariableTableMapper(); + + private LocalVariableTableMapper() { + super(NAME_LOCAL_VARIABLE_TABLE, AttributeStability.LABELS, true); + } + + @Override + public LocalVariableTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundLocalVariableTableAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, LocalVariableTableAttribute attr) { + List infos = attr.localVariables(); + buf.writeU2(infos.size()); + for (LocalVariableInfo info : infos) { + buf.writeU2(info.startPc()); + buf.writeU2(info.length()); + buf.writeIndex(info.name()); + buf.writeIndex(info.type()); + buf.writeU2(info.slot()); + } + } + } + + public static final class LocalVariableTypeTableMapper extends AbstractAttributeMapper { + public static final LocalVariableTypeTableMapper INSTANCE = new LocalVariableTypeTableMapper(); + + private LocalVariableTypeTableMapper() { + super(NAME_LOCAL_VARIABLE_TYPE_TABLE, AttributeStability.LABELS, true); + } + + @Override + public LocalVariableTypeTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundLocalVariableTypeTableAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, LocalVariableTypeTableAttribute attr) { + List infos = attr.localVariableTypes(); + buf.writeU2(infos.size()); + for (LocalVariableTypeInfo info : infos) { + buf.writeU2(info.startPc()); + buf.writeU2(info.length()); + buf.writeIndex(info.name()); + buf.writeIndex(info.signature()); + buf.writeU2(info.slot()); + } + } + } + + public static final class MethodParametersMapper extends AbstractAttributeMapper { + public static final MethodParametersMapper INSTANCE = new MethodParametersMapper(); + + private MethodParametersMapper() { + super(NAME_METHOD_PARAMETERS, AttributeStability.CP_REFS); + } + + @Override + public MethodParametersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundMethodParametersAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, MethodParametersAttribute attr) { + List parameters = attr.parameters(); + buf.writeU1(parameters.size()); + for (MethodParameterInfo info : parameters) { + buf.writeIndexOrZero(info.name().orElse(null)); + buf.writeU2(info.flagsMask()); + } + } + } + + public static final class ModuleMapper extends AbstractAttributeMapper { + public static final ModuleMapper INSTANCE = new ModuleMapper(); + + private ModuleMapper() { + super(NAME_MODULE, AttributeStability.CP_REFS); + } + + @Override + public ModuleAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleAttribute attr) { + buf.writeIndex(attr.moduleName()); + buf.writeU2(attr.moduleFlagsMask()); + buf.writeIndexOrZero(attr.moduleVersion().orElse(null)); + buf.writeU2(attr.requires().size()); + for (ModuleRequireInfo require : attr.requires()) { + buf.writeIndex(require.requires()); + buf.writeU2(require.requiresFlagsMask()); + buf.writeIndexOrZero(require.requiresVersion().orElse(null)); + } + buf.writeU2(attr.exports().size()); + for (ModuleExportInfo export : attr.exports()) { + buf.writeIndex(export.exportedPackage()); + buf.writeU2(export.exportsFlagsMask()); + buf.writeListIndices(export.exportsTo()); + } + buf.writeU2(attr.opens().size()); + for (ModuleOpenInfo open : attr.opens()) { + buf.writeIndex(open.openedPackage()); + buf.writeU2(open.opensFlagsMask()); + buf.writeListIndices(open.opensTo()); + } + buf.writeListIndices(attr.uses()); + buf.writeU2(attr.provides().size()); + for (ModuleProvideInfo provide : attr.provides()) { + buf.writeIndex(provide.provides()); + buf.writeListIndices(provide.providesWith()); + } + } + } + + public static final class ModuleHashesMapper extends AbstractAttributeMapper { + public static final ModuleHashesMapper INSTANCE = new ModuleHashesMapper(); + + private ModuleHashesMapper() { + super(NAME_MODULE_HASHES, AttributeStability.CP_REFS); + } + + @Override + public ModuleHashesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleHashesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleHashesAttribute attr) { + buf.writeIndex(attr.algorithm()); + List hashes = attr.hashes(); + buf.writeU2(hashes.size()); + for (ModuleHashInfo hash : hashes) { + buf.writeIndex(hash.moduleName()); + buf.writeU2(hash.hash().length); + buf.writeBytes(hash.hash()); + } + } + } + + public static final class ModuleMainClassMapper extends AbstractAttributeMapper { + public static final ModuleMainClassMapper INSTANCE = new ModuleMainClassMapper(); + + private ModuleMainClassMapper() { + super(NAME_MODULE_MAIN_CLASS, AttributeStability.CP_REFS); + } + + @Override + public ModuleMainClassAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleMainClassAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleMainClassAttribute attr) { + buf.writeIndex(attr.mainClass()); + } + } + + public static final class ModulePackagesMapper extends AbstractAttributeMapper { + public static final ModulePackagesMapper INSTANCE = new ModulePackagesMapper(); + + private ModulePackagesMapper() { + super(NAME_MODULE_PACKAGES, AttributeStability.CP_REFS); + } + + @Override + public ModulePackagesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModulePackagesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModulePackagesAttribute attr) { + buf.writeListIndices(attr.packages()); + } + } + + public static final class ModuleResolutionMapper extends AbstractAttributeMapper { + public static final ModuleResolutionMapper INSTANCE = new ModuleResolutionMapper(); + + private ModuleResolutionMapper() { + super(NAME_MODULE_RESOLUTION, AttributeStability.STATELESS); + } + + @Override + public ModuleResolutionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleResolutionAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleResolutionAttribute attr) { + buf.writeU2(attr.resolutionFlags()); + } + } + + public static final class ModuleTargetMapper extends AbstractAttributeMapper { + public static final ModuleTargetMapper INSTANCE = new ModuleTargetMapper(); + + private ModuleTargetMapper() { + super(NAME_MODULE_TARGET, AttributeStability.CP_REFS); + } + + @Override + public ModuleTargetAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundModuleTargetAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, ModuleTargetAttribute attr) { + buf.writeIndex(attr.targetPlatform()); + } + } + + public static final class NestHostMapper extends AbstractAttributeMapper { + public static final NestHostMapper INSTANCE = new NestHostMapper(); + + private NestHostMapper() { + super(NAME_NEST_HOST, AttributeStability.CP_REFS); + } + + @Override + public NestHostAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundNestHostAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, NestHostAttribute attr) { + buf.writeIndex(attr.nestHost()); + } + } + + public static final class NestMembersMapper extends AbstractAttributeMapper { + public static final NestMembersMapper INSTANCE = new NestMembersMapper(); + + private NestMembersMapper() { + super(NAME_NEST_MEMBERS, AttributeStability.CP_REFS); + } + + @Override + public NestMembersAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundNestMembersAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, NestMembersAttribute attr) { + buf.writeListIndices(attr.nestMembers()); + } + } + + public static final class PermittedSubclassesMapper extends AbstractAttributeMapper { + public static final PermittedSubclassesMapper INSTANCE = new PermittedSubclassesMapper(); + + private PermittedSubclassesMapper() { + super(NAME_PERMITTED_SUBCLASSES, AttributeStability.CP_REFS); + } + + @Override + public PermittedSubclassesAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundPermittedSubclassesAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, PermittedSubclassesAttribute attr) { + buf.writeListIndices(attr.permittedSubclasses()); + } + } + + public static final class RecordMapper extends AbstractAttributeMapper { + public static final RecordMapper INSTANCE = new RecordMapper(); + + private RecordMapper() { + super(NAME_RECORD, AttributeStability.CP_REFS); + } + + @Override + public RecordAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRecordAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RecordAttribute attr) { + List components = attr.components(); + buf.writeU2(components.size()); + for (RecordComponentInfo info : components) { + buf.writeIndex(info.name()); + buf.writeIndex(info.descriptor()); + buf.writeList(info.attributes()); + } + } + } + + public static final class RuntimeInvisibleAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeInvisibleAnnotationsMapper INSTANCE = new RuntimeInvisibleAnnotationsMapper(); + + private RuntimeInvisibleAnnotationsMapper() { + super(NAME_RUNTIME_INVISIBLE_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeInvisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { + return new BoundAttribute.BoundRuntimeInvisibleAnnotationsAttribute(cf, pos); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeInvisibleAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class RuntimeInvisibleParameterAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeInvisibleParameterAnnotationsMapper INSTANCE = new RuntimeInvisibleParameterAnnotationsMapper(); + + private RuntimeInvisibleParameterAnnotationsMapper() { + super(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeInvisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeInvisibleParameterAnnotationsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeInvisibleParameterAnnotationsAttribute attr) { + List> lists = attr.parameterAnnotations(); + buf.writeU1(lists.size()); + for (List list : lists) + buf.writeList(list); + } + } + + public static final class RuntimeInvisibleTypeAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeInvisibleTypeAnnotationsMapper INSTANCE = new RuntimeInvisibleTypeAnnotationsMapper(); + + private RuntimeInvisibleTypeAnnotationsMapper() { + super(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, AttributeStability.UNSTABLE); + } + + @Override + public RuntimeInvisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeInvisibleTypeAnnotationsAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeInvisibleTypeAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class RuntimeVisibleAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeVisibleAnnotationsMapper INSTANCE = new RuntimeVisibleAnnotationsMapper(); + + private RuntimeVisibleAnnotationsMapper() { + super(NAME_RUNTIME_VISIBLE_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeVisibleAnnotationsAttribute readAttribute(AttributedElement enclosing, ClassReader cf, int pos) { + return new BoundAttribute.BoundRuntimeVisibleAnnotationsAttribute(cf, pos); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeVisibleAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class RuntimeVisibleParameterAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeVisibleParameterAnnotationsMapper INSTANCE = new RuntimeVisibleParameterAnnotationsMapper(); + + private RuntimeVisibleParameterAnnotationsMapper() { + super(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, AttributeStability.CP_REFS); + } + + @Override + public RuntimeVisibleParameterAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeVisibleParameterAnnotationsAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeVisibleParameterAnnotationsAttribute attr) { + List> lists = attr.parameterAnnotations(); + buf.writeU1(lists.size()); + for (List list : lists) + buf.writeList(list); + } + } + + public static final class RuntimeVisibleTypeAnnotationsMapper extends AbstractAttributeMapper { + public static final RuntimeVisibleTypeAnnotationsMapper INSTANCE = new RuntimeVisibleTypeAnnotationsMapper(); + + private RuntimeVisibleTypeAnnotationsMapper() { + super(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS, AttributeStability.UNSTABLE); + } + + @Override + public RuntimeVisibleTypeAnnotationsAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundRuntimeVisibleTypeAnnotationsAttribute(e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, RuntimeVisibleTypeAnnotationsAttribute attr) { + buf.writeList(attr.annotations()); + } + } + + public static final class SignatureMapper extends AbstractAttributeMapper { + public static final SignatureMapper INSTANCE = new SignatureMapper(); + + private SignatureMapper() { + super(NAME_SIGNATURE, AttributeStability.CP_REFS); + } + + @Override + public SignatureAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSignatureAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SignatureAttribute attr) { + buf.writeIndex(attr.signature()); + } + } + + public static final class SourceDebugExtensionMapper extends AbstractAttributeMapper { + public static final SourceDebugExtensionMapper INSTANCE = new SourceDebugExtensionMapper(); + + private SourceDebugExtensionMapper() { + super(NAME_SOURCE_DEBUG_EXTENSION, AttributeStability.STATELESS); + } + + @Override + public SourceDebugExtensionAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSourceDebugExtensionAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SourceDebugExtensionAttribute attr) { + buf.writeBytes(attr.contents()); + } + } + + public static final class SourceFileMapper extends AbstractAttributeMapper { + public static final SourceFileMapper INSTANCE = new SourceFileMapper(); + + private SourceFileMapper() { + super(NAME_SOURCE_FILE, AttributeStability.CP_REFS); + } + + @Override + public SourceFileAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSourceFileAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SourceFileAttribute attr) { + buf.writeIndex(attr.sourceFile()); + } + } + + public static final class SourceIDMapper extends AbstractAttributeMapper { + public static final SourceIDMapper INSTANCE = new SourceIDMapper(); + + private SourceIDMapper() { + super(NAME_SOURCE_ID, AttributeStability.CP_REFS); + } + + @Override + public SourceIDAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSourceIDAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SourceIDAttribute attr) { + buf.writeIndex(attr.sourceId()); + } + } + + public static final class StackMapTableMapper extends AbstractAttributeMapper { + public static final StackMapTableMapper INSTANCE = new StackMapTableMapper(); + + private StackMapTableMapper() { + super(NAME_STACK_MAP_TABLE, AttributeStability.LABELS); + } + + @Override + public StackMapTableAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundStackMapTableAttribute((CodeImpl)e, cf, this, p); + } + + @Override + protected void writeBody(BufWriter b, StackMapTableAttribute attr) { + StackMapDecoder.writeFrames(b, attr.entries()); + } + } + + public static final class SyntheticMapper extends AbstractAttributeMapper { + public static final SyntheticMapper INSTANCE = new SyntheticMapper(); + + private SyntheticMapper() { + super(NAME_SYNTHETIC, AttributeStability.STATELESS, true); + } + + @Override + public SyntheticAttribute readAttribute(AttributedElement e, ClassReader cf, int p) { + return new BoundAttribute.BoundSyntheticAttribute(cf, this, p); + } + + @Override + protected void writeBody(BufWriter buf, SyntheticAttribute attr) { + // empty + } + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java index d572e09040e..69e7f34731f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java @@ -43,6 +43,8 @@ import java.lang.classfile.constantpool.Utf8Entry; import jdk.internal.access.SharedSecrets; +import static java.lang.classfile.Attributes.*; + public abstract sealed class BoundAttribute> extends AbstractElement implements Attribute { @@ -140,7 +142,7 @@ public static List> readAttributes(AttributedElement enclosing, Cla throw new IllegalArgumentException("attribute " + name.stringValue() + " too big to handle"); } - var mapper = Attributes.standardAttribute(name); + var mapper = standardAttribute(name); if (mapper == null) { mapper = customAttributes.apply(name); } @@ -889,7 +891,7 @@ public static final class BoundRuntimeInvisibleAnnotationsAttribute public BoundRuntimeInvisibleAnnotationsAttribute(ClassReader cf, int payloadStart) { - super(cf, Attributes.RUNTIME_INVISIBLE_ANNOTATIONS, payloadStart); + super(cf, Attributes.runtimeInvisibleAnnotations(), payloadStart); } @Override @@ -907,7 +909,7 @@ public static final class BoundRuntimeVisibleAnnotationsAttribute public BoundRuntimeVisibleAnnotationsAttribute(ClassReader cf, int payloadStart) { - super(cf, Attributes.RUNTIME_VISIBLE_ANNOTATIONS, payloadStart); + super(cf, Attributes.runtimeVisibleAnnotations(), payloadStart); } @Override @@ -983,4 +985,88 @@ public byte[] codeArray() { return classReader.readBytes(payloadStart + 8, codeLength()); } } + + /** + * {@return the attribute mapper for a standard attribute} + * + * @param name the name of the attribute to find + */ + public static AttributeMapper standardAttribute(Utf8Entry name) { + // critical bootstrap path, so no lambdas nor method handles here + return switch (name.hashCode()) { + case 0x78147009 -> + name.equalsString(NAME_ANNOTATION_DEFAULT) ? annotationDefault() : null; + case 0x665e3a3a -> + name.equalsString(NAME_BOOTSTRAP_METHODS) ? bootstrapMethods() : null; + case 0xcb7e162 -> + name.equalsString(NAME_CHARACTER_RANGE_TABLE) ? characterRangeTable() : null; + case 0x21e41e7e -> + name.equalsString(NAME_CODE) ? code() : null; + case 0x5a306b41 -> + name.equalsString(NAME_COMPILATION_ID) ? compilationId() : null; + case 0x3e191c7c -> + name.equalsString(NAME_CONSTANT_VALUE) ? constantValue() : null; + case 0x5e88ed0c -> + name.equalsString(NAME_DEPRECATED) ? deprecated() : null; + case 0x7284695e -> + name.equalsString(NAME_ENCLOSING_METHOD) ? enclosingMethod() : null; + case 0x21df25db -> + name.equalsString(NAME_EXCEPTIONS) ? exceptions() : null; + case 0x11392da9 -> + name.equalsString(NAME_INNER_CLASSES) ? innerClasses() : null; + case 0x167536fc -> + name.equalsString(NAME_LINE_NUMBER_TABLE) ? lineNumberTable() : null; + case 0x46939abc -> + name.equalsString(NAME_LOCAL_VARIABLE_TABLE) ? localVariableTable() : null; + case 0x63ee67f4 -> + name.equalsString(NAME_LOCAL_VARIABLE_TYPE_TABLE) ? localVariableTypeTable() : null; + case 0x2b597e15 -> + name.equalsString(NAME_METHOD_PARAMETERS) ? methodParameters() : null; + case 0x19f20ade -> + name.equalsString(NAME_MODULE) ? module() : null; + case 0x47f6395e -> + name.equalsString(NAME_MODULE_HASHES) ? moduleHashes() : null; + case 0x54db809 -> + name.equalsString(NAME_MODULE_MAIN_CLASS) ? moduleMainClass() : null; + case 0x1abd1c2c -> + name.equalsString(NAME_MODULE_PACKAGES) ? modulePackages() : null; + case 0x6ba46dd -> + name.equalsString(NAME_MODULE_RESOLUTION) ? moduleResolution() : null; + case 0x46f7d91d -> + name.equalsString(NAME_MODULE_TARGET) ? moduleTarget() : null; + case 0x5137f53 -> + name.equalsString(NAME_NEST_HOST) ? nestHost() : null; + case 0x4a8fa3b6 -> + name.equalsString(NAME_NEST_MEMBERS) ? nestMembers() : null; + case 0x55c73cb6 -> + name.equalsString(NAME_PERMITTED_SUBCLASSES) ? permittedSubclasses() : null; + case 0x3fe76d4e -> + name.equalsString(NAME_RECORD) ? record() : null; + case 0x180d6925 -> + name.equalsString(NAME_RUNTIME_INVISIBLE_ANNOTATIONS) ? runtimeInvisibleAnnotations() : null; + case 0x7be22752 -> + name.equalsString(NAME_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS) ? runtimeInvisibleParameterAnnotations() : null; + case 0x5299824 -> + name.equalsString(NAME_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) ? runtimeInvisibleTypeAnnotations() : null; + case 0x3534786e -> + name.equalsString(NAME_RUNTIME_VISIBLE_ANNOTATIONS) ? runtimeVisibleAnnotations() : null; + case 0xb4b4ac6 -> + name.equalsString(NAME_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS) ? runtimeVisibleParameterAnnotations() : null; + case 0x6926482 -> + name.equalsString(NAME_RUNTIME_VISIBLE_TYPE_ANNOTATIONS) ? runtimeVisibleTypeAnnotations() : null; + case 0x16a42b7c -> + name.equalsString(NAME_SIGNATURE) ? signature() : null; + case 0x400ab245 -> + name.equalsString(NAME_SOURCE_DEBUG_EXTENSION) ? sourceDebugExtension() : null; + case 0x2af490d4 -> + name.equalsString(NAME_SOURCE_FILE) ? sourceFile() : null; + case 0x303e0c58 -> + name.equalsString(NAME_SOURCE_ID) ? sourceId() : null; + case 0x19c7d0cd -> + name.equalsString(NAME_STACK_MAP_TABLE) ? stackMapTable() : null; + case 0x3dc79b7a -> + name.equalsString(NAME_SYNTHETIC) ? synthetic() : null; + default -> null; + }; + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java index 8604ec5e597..65e9a269265 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassImpl.java @@ -24,32 +24,36 @@ */ package jdk.internal.classfile.impl; -import java.util.Collection; import java.util.List; import java.util.Optional; -import java.util.Set; import java.util.function.Consumer; -import java.util.stream.Collectors; - -import java.lang.classfile.ClassBuilder; import java.lang.classfile.constantpool.ClassEntry; import java.lang.reflect.AccessFlag; import java.lang.classfile.AccessFlags; import java.lang.classfile.Attribute; -import java.lang.classfile.AttributeMapper; import java.lang.classfile.Attributes; import java.lang.classfile.ClassElement; import java.lang.classfile.ClassModel; import java.lang.classfile.ClassReader; -import java.lang.classfile.ClassTransform; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassFileVersion; +import java.lang.classfile.CustomAttribute; import java.lang.classfile.constantpool.ConstantPool; -import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.FieldModel; import java.lang.classfile.Interfaces; import java.lang.classfile.MethodModel; import java.lang.classfile.Superclass; +import java.lang.classfile.attribute.InnerClassesAttribute; +import java.lang.classfile.attribute.ModuleAttribute; +import java.lang.classfile.attribute.ModuleHashesAttribute; +import java.lang.classfile.attribute.ModuleMainClassAttribute; +import java.lang.classfile.attribute.ModulePackagesAttribute; +import java.lang.classfile.attribute.ModuleResolutionAttribute; +import java.lang.classfile.attribute.ModuleTargetAttribute; +import java.lang.classfile.attribute.RuntimeInvisibleAnnotationsAttribute; +import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import java.lang.classfile.attribute.SourceDebugExtensionAttribute; +import java.lang.classfile.attribute.SourceFileAttribute; import jdk.internal.access.SharedSecrets; public final class ClassImpl @@ -202,28 +206,21 @@ public String toString() { } private boolean verifyModuleAttributes() { - if (findAttribute(Attributes.MODULE).isEmpty()) + if (findAttribute(Attributes.module()).isEmpty()) return false; - Set> found = attributes().stream() - .map(Attribute::attributeMapper) - .collect(Collectors.toSet()); - - found.removeAll(allowedModuleAttributes); - found.retainAll(Attributes.PREDEFINED_ATTRIBUTES); - return found.isEmpty(); - } - - private static final Set> allowedModuleAttributes - = Set.of(Attributes.MODULE, - Attributes.MODULE_HASHES, - Attributes.MODULE_MAIN_CLASS, - Attributes.MODULE_PACKAGES, - Attributes.MODULE_RESOLUTION, - Attributes.MODULE_TARGET, - Attributes.INNER_CLASSES, - Attributes.SOURCE_FILE, - Attributes.SOURCE_DEBUG_EXTENSION, - Attributes.RUNTIME_VISIBLE_ANNOTATIONS, - Attributes.RUNTIME_INVISIBLE_ANNOTATIONS); + return attributes().stream().allMatch(a -> + a instanceof ModuleAttribute + || a instanceof ModulePackagesAttribute + || a instanceof ModuleHashesAttribute + || a instanceof ModuleMainClassAttribute + || a instanceof ModuleResolutionAttribute + || a instanceof ModuleTargetAttribute + || a instanceof InnerClassesAttribute + || a instanceof SourceFileAttribute + || a instanceof SourceDebugExtensionAttribute + || a instanceof RuntimeVisibleAnnotationsAttribute + || a instanceof RuntimeInvisibleAnnotationsAttribute + || a instanceof CustomAttribute); + } } 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 4878ad56ae8..d7c1f7b28fd 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 @@ -290,7 +290,7 @@ BootstrapMethodsAttribute bootstrapMethodsAttribute() { if (bootstrapMethodsAttribute == null) { bootstrapMethodsAttribute - = containedClass.findAttribute(Attributes.BOOTSTRAP_METHODS) + = containedClass.findAttribute(Attributes.bootstrapMethods()) .orElse(new UnboundAttribute.EmptyBootstrapAttribute()); } @@ -324,7 +324,7 @@ ClassModel getContainedClass() { boolean writeBootstrapMethods(BufWriter buf) { Optional a - = containedClass.findAttribute(Attributes.BOOTSTRAP_METHODS); + = containedClass.findAttribute(Attributes.bootstrapMethods()); if (a.isEmpty()) return false; a.get().writeTo(buf); 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 4eba39989f6..ec6ba32801a 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 @@ -230,7 +230,7 @@ private void inflateLabel(int bci) { private void inflateLineNumbers() { for (Attribute a : attributes()) { - if (a.attributeMapper() == Attributes.LINE_NUMBER_TABLE) { + if (a.attributeMapper() == Attributes.lineNumberTable()) { BoundLineNumberTableAttribute attr = (BoundLineNumberTableAttribute) a; if (lineNumbers == null) lineNumbers = new int[codeLength + 1]; @@ -252,7 +252,7 @@ private void inflateLineNumbers() { } private void inflateJumpTargets() { - Optional a = findAttribute(Attributes.STACK_MAP_TABLE); + Optional a = findAttribute(Attributes.stackMapTable()); if (a.isEmpty()) { if (classReader.readU2(6) <= ClassFile.JAVA_6_VERSION) { //fallback to jump targets inflation without StackMapTableAttribute @@ -325,8 +325,8 @@ else if (frameType < 128) { } private void inflateTypeAnnotations() { - findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).ifPresent(RuntimeVisibleTypeAnnotationsAttribute::annotations); - findAttribute(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS).ifPresent(RuntimeInvisibleTypeAnnotationsAttribute::annotations); + findAttribute(Attributes.runtimeVisibleTypeAnnotations()).ifPresent(RuntimeVisibleTypeAnnotationsAttribute::annotations); + findAttribute(Attributes.runtimeInvisibleTypeAnnotations()).ifPresent(RuntimeInvisibleTypeAnnotationsAttribute::annotations); } private void generateCatchTargets(Consumer consumer) { @@ -345,7 +345,7 @@ public void accept(int s, int e, int h, int c) { private void generateDebugElements(Consumer consumer) { for (Attribute a : attributes()) { - if (a.attributeMapper() == Attributes.CHARACTER_RANGE_TABLE) { + if (a.attributeMapper() == Attributes.characterRangeTable()) { var attr = (BoundCharacterRangeTableAttribute) a; int cnt = classReader.readU2(attr.payloadStart); int p = attr.payloadStart + 2; @@ -357,7 +357,7 @@ private void generateDebugElements(Consumer consumer) { consumer.accept(instruction); } } - else if (a.attributeMapper() == Attributes.LOCAL_VARIABLE_TABLE) { + else if (a.attributeMapper() == Attributes.localVariableTable()) { var attr = (BoundLocalVariableTableAttribute) a; int cnt = classReader.readU2(attr.payloadStart); int p = attr.payloadStart + 2; @@ -369,7 +369,7 @@ else if (a.attributeMapper() == Attributes.LOCAL_VARIABLE_TABLE) { consumer.accept(instruction); } } - else if (a.attributeMapper() == Attributes.LOCAL_VARIABLE_TYPE_TABLE) { + else if (a.attributeMapper() == Attributes.localVariableTypeTable()) { var attr = (BoundLocalVariableTypeTableAttribute) a; int cnt = classReader.readU2(attr.payloadStart); int p = attr.payloadStart + 2; @@ -381,10 +381,10 @@ else if (a.attributeMapper() == Attributes.LOCAL_VARIABLE_TYPE_TABLE) { consumer.accept(instruction); } } - else if (a.attributeMapper() == Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS) { + else if (a.attributeMapper() == Attributes.runtimeVisibleTypeAnnotations()) { consumer.accept((BoundRuntimeVisibleTypeAnnotationsAttribute) a); } - else if (a.attributeMapper() == Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) { + else if (a.attributeMapper() == Attributes.runtimeInvisibleTypeAnnotations()) { consumer.accept((BoundRuntimeInvisibleTypeAnnotationsAttribute) a); } } 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 9f68177351f..b961a12031f 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 @@ -230,7 +230,7 @@ private void buildContent() { if (context.debugElementsOption() == ClassFile.DebugElementsOption.PASS_DEBUG) { if (!characterRanges.isEmpty()) { - Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.CHARACTER_RANGE_TABLE) { + Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.characterRangeTable()) { @Override public void writeBody(BufWriter b) { @@ -262,7 +262,7 @@ public void writeBody(BufWriter b) { } if (!localVariables.isEmpty()) { - Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.LOCAL_VARIABLE_TABLE) { + Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTable()) { @Override public void writeBody(BufWriter b) { int pos = b.size(); @@ -285,7 +285,7 @@ public void writeBody(BufWriter b) { } if (!localVariableTypes.isEmpty()) { - Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.LOCAL_VARIABLE_TYPE_TABLE) { + Attribute a = new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTypeTable()) { @Override public void writeBody(BufWriter b) { int pos = b.size(); @@ -312,7 +312,7 @@ public void writeBody(BufWriter b) { attributes.withAttribute(lineNumberWriter); } - content = new UnboundAttribute.AdHocAttribute<>(Attributes.CODE) { + content = new UnboundAttribute.AdHocAttribute<>(Attributes.code()) { private void writeCounters(boolean codeMatch, BufWriterImpl buf) { if (codeMatch) { @@ -368,7 +368,7 @@ public void writeBody(BufWriter b) { if (codeAndExceptionsMatch(codeLength)) { switch (context.stackMapsOption()) { case STACK_MAPS_WHEN_REQUIRED -> { - attributes.withAttribute(original.findAttribute(Attributes.STACK_MAP_TABLE).orElse(null)); + attributes.withAttribute(original.findAttribute(Attributes.stackMapTable()).orElse(null)); writeCounters(true, buf); } case GENERATE_STACK_MAPS -> @@ -401,7 +401,7 @@ private static class DedupLineNumberTableAttribute extends UnboundAttribute.AdHo private int lastPc, lastLine, writtenLine; public DedupLineNumberTableAttribute(ConstantPoolBuilder constantPool, ClassFileImpl context) { - super(Attributes.LINE_NUMBER_TABLE); + super(Attributes.lineNumberTable()); buf = new BufWriterImpl(constantPool, context); lastPc = -1; writtenLine = -1; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java index 0baaa5865ae..9a96e586c55 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/MethodImpl.java @@ -118,7 +118,7 @@ public void writeTo(BufWriter b) { @Override public Optional code() { - return findAttribute(Attributes.CODE).map(a -> (CodeModel) a); + return findAttribute(Attributes.code()).map(a -> (CodeModel) a); } @Override 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 db2b4f030a3..8deac9e3f95 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 @@ -144,7 +144,7 @@ public boolean writeBootstrapMethods(BufWriter buf) { } else { Attribute a - = new UnboundAttribute.AdHocAttribute<>(Attributes.BOOTSTRAP_METHODS) { + = new UnboundAttribute.AdHocAttribute<>(Attributes.bootstrapMethods()) { @Override public void writeBody(BufWriter b) { 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 17fcc5046a1..4a8677e876f 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 @@ -380,7 +380,7 @@ 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.STACK_MAP_TABLE) { + return frames.isEmpty() ? null : new UnboundAttribute.AdHocAttribute<>(Attributes.stackMapTable()) { @Override public void writeBody(BufWriter b) { b.writeU2(frames.size()); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java index bdb293493bf..70b58e423f6 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/UnboundAttribute.java @@ -149,7 +149,7 @@ public static final class UnboundConstantValueAttribute private final ConstantValueEntry entry; public UnboundConstantValueAttribute(ConstantValueEntry entry) { - super(Attributes.CONSTANT_VALUE); + super(Attributes.constantValue()); this.entry = entry; } @@ -164,7 +164,7 @@ public static final class UnboundDeprecatedAttribute extends UnboundAttribute implements DeprecatedAttribute { public UnboundDeprecatedAttribute() { - super(Attributes.DEPRECATED); + super(Attributes.deprecated()); } } @@ -172,7 +172,7 @@ public static final class UnboundSyntheticAttribute extends UnboundAttribute implements SyntheticAttribute { public UnboundSyntheticAttribute() { - super(Attributes.SYNTHETIC); + super(Attributes.synthetic()); } } @@ -182,7 +182,7 @@ public static final class UnboundSignatureAttribute private final Utf8Entry signature; public UnboundSignatureAttribute(Utf8Entry signature) { - super(Attributes.SIGNATURE); + super(Attributes.signature()); this.signature = signature; } @@ -198,7 +198,7 @@ public static final class UnboundExceptionsAttribute private final List exceptions; public UnboundExceptionsAttribute(List exceptions) { - super(Attributes.EXCEPTIONS); + super(Attributes.exceptions()); this.exceptions = List.copyOf(exceptions); } @@ -214,7 +214,7 @@ public static final class UnboundAnnotationDefaultAttribute private final AnnotationValue annotationDefault; public UnboundAnnotationDefaultAttribute(AnnotationValue annotationDefault) { - super(Attributes.ANNOTATION_DEFAULT); + super(Attributes.annotationDefault()); this.annotationDefault = annotationDefault; } @@ -229,7 +229,7 @@ public static final class UnboundSourceFileAttribute extends UnboundAttribute entries; public UnboundStackMapTableAttribute(List entries) { - super(Attributes.STACK_MAP_TABLE); + super(Attributes.stackMapTable()); this.entries = List.copyOf(entries); } @@ -261,7 +261,7 @@ public static final class UnboundInnerClassesAttribute private final List innerClasses; public UnboundInnerClassesAttribute(List innerClasses) { - super(Attributes.INNER_CLASSES); + super(Attributes.innerClasses()); this.innerClasses = List.copyOf(innerClasses); } @@ -277,7 +277,7 @@ public static final class UnboundRecordAttribute private final List components; public UnboundRecordAttribute(List components) { - super(Attributes.RECORD); + super(Attributes.record()); this.components = List.copyOf(components); } @@ -294,7 +294,7 @@ public static final class UnboundEnclosingMethodAttribute private final NameAndTypeEntry method; public UnboundEnclosingMethodAttribute(ClassEntry classEntry, NameAndTypeEntry method) { - super(Attributes.ENCLOSING_METHOD); + super(Attributes.enclosingMethod()); this.classEntry = classEntry; this.method = method; } @@ -316,7 +316,7 @@ public static final class UnboundMethodParametersAttribute private final List parameters; public UnboundMethodParametersAttribute(List parameters) { - super(Attributes.METHOD_PARAMETERS); + super(Attributes.methodParameters()); this.parameters = List.copyOf(parameters); } @@ -332,7 +332,7 @@ public static final class UnboundModuleTargetAttribute final Utf8Entry moduleTarget; public UnboundModuleTargetAttribute(Utf8Entry moduleTarget) { - super(Attributes.MODULE_TARGET); + super(Attributes.moduleTarget()); this.moduleTarget = moduleTarget; } @@ -348,7 +348,7 @@ public static final class UnboundModuleMainClassAttribute final ClassEntry mainClass; public UnboundModuleMainClassAttribute(ClassEntry mainClass) { - super(Attributes.MODULE_MAIN_CLASS); + super(Attributes.moduleMainClass()); this.mainClass = mainClass; } @@ -365,7 +365,7 @@ public static final class UnboundModuleHashesAttribute private final List hashes; public UnboundModuleHashesAttribute(Utf8Entry algorithm, List hashes) { - super(Attributes.MODULE_HASHES); + super(Attributes.moduleHashes()); this.algorithm = algorithm; this.hashes = List.copyOf(hashes); } @@ -387,7 +387,7 @@ public static final class UnboundModulePackagesAttribute private final Collection packages; public UnboundModulePackagesAttribute(Collection packages) { - super(Attributes.MODULE_PACKAGES); + super(Attributes.modulePackages()); this.packages = List.copyOf(packages); } @@ -403,7 +403,7 @@ public static final class UnboundModuleResolutionAttribute private final int resolutionFlags; public UnboundModuleResolutionAttribute(int flags) { - super(Attributes.MODULE_RESOLUTION); + super(Attributes.moduleResolution()); resolutionFlags = flags; } @@ -419,7 +419,7 @@ public static final class UnboundPermittedSubclassesAttribute private final List permittedSubclasses; public UnboundPermittedSubclassesAttribute(List permittedSubclasses) { - super(Attributes.PERMITTED_SUBCLASSES); + super(Attributes.permittedSubclasses()); this.permittedSubclasses = List.copyOf(permittedSubclasses); } @@ -435,7 +435,7 @@ public static final class UnboundNestMembersAttribute private final List memberEntries; public UnboundNestMembersAttribute(List memberEntries) { - super(Attributes.NEST_MEMBERS); + super(Attributes.nestMembers()); this.memberEntries = List.copyOf(memberEntries); } @@ -451,7 +451,7 @@ public static final class UnboundNestHostAttribute private final ClassEntry hostEntry; public UnboundNestHostAttribute(ClassEntry hostEntry) { - super(Attributes.NEST_HOST); + super(Attributes.nestHost()); this.hostEntry = hostEntry; } @@ -467,7 +467,7 @@ public static final class UnboundCompilationIDAttribute private final Utf8Entry idEntry; public UnboundCompilationIDAttribute(Utf8Entry idEntry) { - super(Attributes.COMPILATION_ID); + super(Attributes.compilationId()); this.idEntry = idEntry; } @@ -483,7 +483,7 @@ public static final class UnboundSourceIDAttribute private final Utf8Entry idEntry; public UnboundSourceIDAttribute(Utf8Entry idEntry) { - super(Attributes.SOURCE_ID); + super(Attributes.sourceId()); this.idEntry = idEntry; } @@ -499,7 +499,7 @@ public static final class UnboundSourceDebugExtensionAttribute private final byte[] contents; public UnboundSourceDebugExtensionAttribute(byte[] contents) { - super(Attributes.SOURCE_DEBUG_EXTENSION); + super(Attributes.sourceDebugExtension()); this.contents = contents; } @@ -515,7 +515,7 @@ public static final class UnboundCharacterRangeTableAttribute private final List ranges; public UnboundCharacterRangeTableAttribute(List ranges) { - super(Attributes.CHARACTER_RANGE_TABLE); + super(Attributes.characterRangeTable()); this.ranges = List.copyOf(ranges); } @@ -531,7 +531,7 @@ public static final class UnboundLineNumberTableAttribute private final List lines; public UnboundLineNumberTableAttribute(List lines) { - super(Attributes.LINE_NUMBER_TABLE); + super(Attributes.lineNumberTable()); this.lines = List.copyOf(lines); } @@ -547,7 +547,7 @@ public static final class UnboundLocalVariableTableAttribute private final List locals; public UnboundLocalVariableTableAttribute(List locals) { - super(Attributes.LOCAL_VARIABLE_TABLE); + super(Attributes.localVariableTable()); this.locals = List.copyOf(locals); } @@ -563,7 +563,7 @@ public static final class UnboundLocalVariableTypeTableAttribute private final List locals; public UnboundLocalVariableTypeTableAttribute(List locals) { - super(Attributes.LOCAL_VARIABLE_TYPE_TABLE); + super(Attributes.localVariableTypeTable()); this.locals = List.copyOf(locals); } @@ -579,7 +579,7 @@ public static final class UnboundRuntimeVisibleAnnotationsAttribute private final List elements; public UnboundRuntimeVisibleAnnotationsAttribute(List elements) { - super(Attributes.RUNTIME_VISIBLE_ANNOTATIONS); + super(Attributes.runtimeVisibleAnnotations()); this.elements = List.copyOf(elements); } @@ -595,7 +595,7 @@ public static final class UnboundRuntimeInvisibleAnnotationsAttribute private final List elements; public UnboundRuntimeInvisibleAnnotationsAttribute(List elements) { - super(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS); + super(Attributes.runtimeInvisibleAnnotations()); this.elements = List.copyOf(elements); } @@ -611,7 +611,7 @@ public static final class UnboundRuntimeVisibleParameterAnnotationsAttribute private final List> elements; public UnboundRuntimeVisibleParameterAnnotationsAttribute(List> elements) { - super(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS); + super(Attributes.runtimeVisibleParameterAnnotations()); this.elements = List.copyOf(elements); } @@ -627,7 +627,7 @@ public static final class UnboundRuntimeInvisibleParameterAnnotationsAttribute private final List> elements; public UnboundRuntimeInvisibleParameterAnnotationsAttribute(List> elements) { - super(Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS); + super(Attributes.runtimeInvisibleParameterAnnotations()); this.elements = List.copyOf(elements); } @@ -643,7 +643,7 @@ public static final class UnboundRuntimeVisibleTypeAnnotationsAttribute private final List elements; public UnboundRuntimeVisibleTypeAnnotationsAttribute(List elements) { - super(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); + super(Attributes.runtimeVisibleTypeAnnotations()); this.elements = List.copyOf(elements); } @@ -659,7 +659,7 @@ public static final class UnboundRuntimeInvisibleTypeAnnotationsAttribute private final List elements; public UnboundRuntimeInvisibleTypeAnnotationsAttribute(List elements) { - super(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + super(Attributes.runtimeInvisibleTypeAnnotations()); this.elements = List.copyOf(elements); } @@ -845,7 +845,7 @@ public UnboundModuleAttribute(ModuleEntry moduleName, Collection uses, Collection provides) { - super(Attributes.MODULE); + super(Attributes.module()); this.moduleName = moduleName; this.moduleFlags = moduleFlags; this.moduleVersion = moduleVersion; @@ -921,7 +921,7 @@ public static final class EmptyBootstrapAttribute extends UnboundAttribute implements BootstrapMethodsAttribute { public EmptyBootstrapAttribute() { - super(Attributes.BOOTSTRAP_METHODS); + super(Attributes.bootstrapMethods()); } @Override 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 7bff7e6f06d..0e969272c40 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 @@ -214,7 +214,7 @@ public static void dumpMethod(SplitConstantPool cp, var cc = ClassFile.of(); var clm = cc.parse(cc.build(cp.classEntry(cls), cp, clb -> clb.withMethod(methodName, methodDesc, acc, mb -> - ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.CODE) { + ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override public void writeBody(BufWriter b) { b.writeU2(-1);//max stack diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java index 6be4a611e97..fefc6b20cb2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationWrapper.java @@ -142,12 +142,12 @@ List exceptionTable() { } List localVariableTable() { - var attro = c.findAttribute(Attributes.LOCAL_VARIABLE_TABLE); + var attro = c.findAttribute(Attributes.localVariableTable()); return attro.map(lvta -> lvta.localVariables()).orElse(List.of()); } byte[] stackMapTableRawData() { - var attro = c.findAttribute(Attributes.STACK_MAP_TABLE); + var attro = c.findAttribute(Attributes.stackMapTable()); return attro.map(attr -> ((BoundAttribute) attr).contents()).orElse(null); } diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java b/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java index a4cfc59eb20..b28078916c5 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java @@ -284,7 +284,7 @@ public void accept(ClassElement cle) { case MethodModel mm -> { if (isPublic(mm.flags())) { Set exceptionSet = new HashSet<>(); - mm.findAttribute(Attributes.EXCEPTIONS).ifPresent(ea -> + mm.findAttribute(Attributes.exceptions()).ifPresent(ea -> ea.exceptions().forEach(e -> exceptionSet.add(e.asInternalName()))); // treat type descriptor as a proxy for signature because signature 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 23bec4e7298..839ac2fd041 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 @@ -478,7 +478,7 @@ public void write(Attribute a, CodeAttribute lr) { println("Record:"); indent(+1); for (var componentInfo : attr.components()) { - var sigAttr = componentInfo.findAttribute(Attributes.SIGNATURE); + var sigAttr = componentInfo.findAttribute(Attributes.signature()); print(getJavaName( new ClassWriter.SignaturePrinter(options.verbose).print( sigAttr.map(SignatureAttribute::asTypeSignature) 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 c5ac15ee7da..798d2f2d3a8 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 @@ -141,7 +141,7 @@ public boolean write(ClassModel cm) { } } - cm.findAttribute(Attributes.SOURCE_FILE).ifPresent(sfa -> + cm.findAttribute(Attributes.sourceFile()).ifPresent(sfa -> println("Compiled from \"" + sfa.sourceFile().stringValue() + "\"")); if (options.sysInfo || options.verbose) { @@ -151,7 +151,7 @@ public boolean write(ClassModel cm) { writeModifiers(getClassModifiers(cm.flags().flagsMask())); if ((classModel.flags().flagsMask() & ACC_MODULE) != 0) { - var attr = classModel.findAttribute(Attributes.MODULE); + var attr = classModel.findAttribute(Attributes.module()); if (attr.isPresent()) { var modAttr = attr.get(); if ((modAttr.moduleFlagsMask() & ACC_OPEN) != 0) { @@ -178,7 +178,7 @@ public boolean write(ClassModel cm) { } try { - var sigAttr = classModel.findAttribute(Attributes.SIGNATURE).orElse(null); + var sigAttr = classModel.findAttribute(Attributes.signature()).orElse(null); if (sigAttr == null) { // use info from class file header if ((classModel.flags().flagsMask() & ACC_INTERFACE) == 0 @@ -399,13 +399,13 @@ protected void writeField(FieldModel f) { writeModifiers(flags.flags().stream().filter(fl -> fl.sourceModifier()) .map(fl -> Modifier.toString(fl.mask())).toList()); print(() -> sigPrinter.print( - f.findAttribute(Attributes.SIGNATURE) + f.findAttribute(Attributes.signature()) .map(SignatureAttribute::asTypeSignature) .orElseGet(() -> Signature.of(f.fieldTypeSymbol())))); print(" "); print(() -> f.fieldName().stringValue()); if (options.showConstants) { - var a = f.findAttribute(Attributes.CONSTANT_VALUE); + var a = f.findAttribute(Attributes.constantValue()); if (a.isPresent()) { print(" = "); var cv = a.get(); @@ -480,7 +480,7 @@ protected void writeMethod(MethodModel m) { writeModifiers(modifiers); try { - var sigAttr = m.findAttribute(Attributes.SIGNATURE); + var sigAttr = m.findAttribute(Attributes.signature()); MethodSignature d; if (sigAttr.isEmpty()) { d = MethodSignature.parseFrom(m.methodType().stringValue()); @@ -507,7 +507,7 @@ protected void writeMethod(MethodModel m) { break; } - var e_attr = m.findAttribute(Attributes.EXCEPTIONS); + var e_attr = m.findAttribute(Attributes.exceptions()); // if there are generic exceptions, there must be erased exceptions if (e_attr.isPresent()) { var exceptions = e_attr.get(); @@ -559,9 +559,9 @@ protected void writeMethod(MethodModel m) { } if (options.showLineAndLocalVariableTables) { - code.findAttribute(Attributes.LINE_NUMBER_TABLE) + code.findAttribute(Attributes.lineNumberTable()) .ifPresent(a -> attrWriter.write(a, code)); - code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE) + code.findAttribute(Attributes.localVariableTable()) .ifPresent(a -> attrWriter.write(a, code)); } } @@ -589,7 +589,7 @@ void writeModifiers(Collection items) { public static final int ACC_STATIC_PHASE = 0x0040; void writeDirectives() { - var attr = classModel.findAttribute(Attributes.MODULE); + var attr = classModel.findAttribute(Attributes.module()); if (attr.isEmpty()) return; diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java index 1c32fff24e0..ac8ab164e62 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/JavapTask.java @@ -674,7 +674,7 @@ protected int writeClass(ClassWriter classWriter, String className) if (options.showInnerClasses) { ClassModel cm = cfInfo.cm; - var a = cm.findAttribute(java.lang.classfile.Attributes.INNER_CLASSES); + var a = cm.findAttribute(java.lang.classfile.Attributes.innerClasses()); if (a.isPresent()) { var inners = a.get(); try { diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTableWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTableWriter.java index d6b57ca4c48..f19d8fce4bb 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTableWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTableWriter.java @@ -80,7 +80,7 @@ protected LocalVariableTableWriter(Context context) { public void reset(CodeModel attr) { codeAttr = attr; pcMap = new HashMap<>(); - var lvt = attr.findAttribute(Attributes.LOCAL_VARIABLE_TABLE); + var lvt = attr.findAttribute(Attributes.localVariableTable()); if (lvt.isEmpty()) return; diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java index f9ac8c70e0f..04e7b3fd0e0 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java @@ -80,7 +80,7 @@ protected LocalVariableTypeTableWriter(Context context) { public void reset(CodeModel attr) { codeAttr = attr; pcMap = new HashMap<>(); - var lvt = attr.findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE); + var lvt = attr.findAttribute(Attributes.localVariableTypeTable()); if (lvt.isEmpty()) return; diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/SourceWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/SourceWriter.java index 1d06727ff63..884c0fa9f80 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/SourceWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/SourceWriter.java @@ -105,7 +105,7 @@ public boolean hasSource() { private void setLineMap(CodeModel attr) { SortedMap> map = new TreeMap<>(); SortedSet allLines = new TreeSet<>(); - for (var t : attr.findAttributes(Attributes.LINE_NUMBER_TABLE)) { + for (var t : attr.findAttributes(Attributes.lineNumberTable())) { for (var e: t.lineNumbers()) { int start_pc = e.startPc(); int line = e.lineNumber(); @@ -145,7 +145,7 @@ private String readSource(ClassModel cf) { // InnerClasses and EnclosingMethod attributes. try { String className = cf.thisClass().asInternalName(); - var sf = cf.findAttribute(Attributes.SOURCE_FILE); + var sf = cf.findAttribute(Attributes.sourceFile()); if (sf.isEmpty()) { report(messages.getMessage("err.no.SourceFile.attribute")); return null; 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 9a83fddbb87..a1d939bcc4f 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 @@ -62,7 +62,7 @@ public void reset(CodeAttribute code) { } void setStackMap(CodeAttribute code) { - StackMapTableAttribute attr = code.findAttribute(Attributes.STACK_MAP_TABLE) + StackMapTableAttribute attr = code.findAttribute(Attributes.stackMapTable()) .orElse(null); if (attr == null) { map = null; diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/TypeAnnotationWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/TypeAnnotationWriter.java index a0236955cfc..d5e19bc4241 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/TypeAnnotationWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/TypeAnnotationWriter.java @@ -76,10 +76,10 @@ public void reset(CodeAttribute attr) { pcMap = new HashMap<>(); codeAttribute = attr; check(NoteKind.VISIBLE, - m.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS) + m.findAttribute(Attributes.runtimeVisibleTypeAnnotations()) .map(a -> a.annotations())); check(NoteKind.INVISIBLE, - m.findAttribute(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS) + m.findAttribute(Attributes.runtimeInvisibleTypeAnnotations()) .map(a -> a.annotations())); } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java index 422845150f0..c0ac835f4b6 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/Dependencies.java @@ -597,7 +597,7 @@ private void scan(MethodTypeDesc mtd) { void scanAttributes(AttributedElement attrs) { try { - var sa = attrs.findAttribute(Attributes.SIGNATURE).orElse(null); + var sa = attrs.findAttribute(Attributes.signature()).orElse(null); if (sa != null) { switch (attrs) { case ClassModel _ -> scan(sa.asClassSignature()); @@ -606,14 +606,14 @@ void scanAttributes(AttributedElement attrs) { } } - var rvaa = attrs.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + var rvaa = attrs.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (rvaa != null) { for (var anno : rvaa.annotations()) { scan(anno.classSymbol()); } } - var rvpaa = attrs.findAttribute(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS).orElse(null); + var rvpaa = attrs.findAttribute(Attributes.runtimeVisibleParameterAnnotations()).orElse(null); if (rvpaa != null) { for (var parameter : rvpaa.parameterAnnotations()) { for (var anno : parameter) { @@ -622,7 +622,7 @@ void scanAttributes(AttributedElement attrs) { } } - var exceptions = attrs.findAttribute(Attributes.EXCEPTIONS).orElse(null); + var exceptions = attrs.findAttribute(Attributes.exceptions()).orElse(null); if (exceptions != null) { for (var e : exceptions.exceptions()) { addClass(e); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index ae077b3b3f4..00973fd78c2 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -678,7 +678,7 @@ public void getOopMapAtTest() throws Exception { Map methodMap = buildMethodMap(type); ClassModel cf = readClassfile(c); for (MethodModel cm : cf.methods()) { - cm.findAttribute(Attributes.CODE).ifPresent(codeAttr -> { + cm.findAttribute(Attributes.code()).ifPresent(codeAttr -> { String key = cm.methodName().stringValue() + ":" + cm.methodType().stringValue(); HotSpotResolvedJavaMethod m = (HotSpotResolvedJavaMethod) Objects.requireNonNull(methodMap.get(key)); boolean isMethodWithManyArgs = c == getClass() && m.getName().equals("methodWithManyArgs"); diff --git a/test/jdk/java/lang/StackWalker/TestBCI.java b/test/jdk/java/lang/StackWalker/TestBCI.java index 3cba0505e9c..4d5e6a6eaf4 100644 --- a/test/jdk/java/lang/StackWalker/TestBCI.java +++ b/test/jdk/java/lang/StackWalker/TestBCI.java @@ -134,7 +134,7 @@ static class MethodInfo { this.name = m.methodName().stringValue(); this.desc = m.methodTypeSymbol(); m.code().orElseThrow(() -> new IllegalArgumentException("Missing Code in " + m)) - .findAttribute(Attributes.LINE_NUMBER_TABLE) + .findAttribute(Attributes.lineNumberTable()) .orElseThrow(() -> new IllegalArgumentException("Missing LineNumberTable in " + m)) .lineNumbers().forEach(entry -> bciToLineNumbers.computeIfAbsent(entry.startPc(), _ -> new TreeSet<>()) diff --git a/test/jdk/java/lang/invoke/lambda/LambdaAsm.java b/test/jdk/java/lang/invoke/lambda/LambdaAsm.java index ebca93d639a..8369ea2bcd3 100644 --- a/test/jdk/java/lang/invoke/lambda/LambdaAsm.java +++ b/test/jdk/java/lang/invoke/lambda/LambdaAsm.java @@ -125,7 +125,7 @@ static int checkMethod(ClassModel cf, String mthd) throws Exception { for (var m : cf.methods()) { String mname = m.methodName().stringValue(); if (mname.equals(mthd)) { - for (var a : m.findAttributes(Attributes.CODE)) { + for (var a : m.findAttributes(Attributes.code())) { count++; checkMethod(cf.thisClass().asInternalName(), mname, cf.constantPool(), a); diff --git a/test/jdk/jdk/classfile/AdvancedTransformationsTest.java b/test/jdk/jdk/classfile/AdvancedTransformationsTest.java index 9b4609fe8bc..2ef7dca11ae 100644 --- a/test/jdk/jdk/classfile/AdvancedTransformationsTest.java +++ b/test/jdk/jdk/classfile/AdvancedTransformationsTest.java @@ -120,9 +120,9 @@ void testRemapClass() throws Exception { ClassDesc.ofDescriptor(RawBytecodeHelper.class.descriptorString()), ClassDesc.of("remapped.RemappedBytecode"))) .orElse(ClassHierarchyResolver.defaultResolver()) )).verify(remapped)); - remapped.fields().forEach(f -> f.findAttribute(Attributes.SIGNATURE).ifPresent(sa -> + remapped.fields().forEach(f -> f.findAttribute(Attributes.signature()).ifPresent(sa -> verifySignature(f.fieldTypeSymbol(), sa.asTypeSignature()))); - remapped.methods().forEach(m -> m.findAttribute(Attributes.SIGNATURE).ifPresent(sa -> { + remapped.methods().forEach(m -> m.findAttribute(Attributes.signature()).ifPresent(sa -> { var md = m.methodTypeSymbol(); var ms = sa.asMethodSignature(); verifySignature(md.returnType(), ms.result()); @@ -173,7 +173,7 @@ void testRemapModule() throws Exception { cc.parse( cc.buildModule( ModuleAttribute.of(ModuleDesc.of("MyModule"), mab -> - mab.uses(foo).provides(foo, foo)))))).findAttribute(Attributes.MODULE).get(); + mab.uses(foo).provides(foo, foo)))))).findAttribute(Attributes.module()).get(); assertEquals(ma.uses().get(0).asSymbol(), bar); var provides = ma.provides().get(0); assertEquals(provides.provides().asSymbol(), bar); diff --git a/test/jdk/jdk/classfile/AnnotationModelTest.java b/test/jdk/jdk/classfile/AnnotationModelTest.java index ed647784219..25d02b8172f 100644 --- a/test/jdk/jdk/classfile/AnnotationModelTest.java +++ b/test/jdk/jdk/classfile/AnnotationModelTest.java @@ -54,7 +54,7 @@ class AnnotationModelTest { @Test void readAnnos() { var model = ClassFile.of().parse(fileBytes); - var annotations = model.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).get().annotations(); + var annotations = model.findAttribute(Attributes.runtimeVisibleAnnotations()).get().annotations(); assertEquals(annotations.size(), 3); } diff --git a/test/jdk/jdk/classfile/AttributesTest.java b/test/jdk/jdk/classfile/AttributesTest.java new file mode 100644 index 00000000000..0d156dd5860 --- /dev/null +++ b/test/jdk/jdk/classfile/AttributesTest.java @@ -0,0 +1,55 @@ +/* + * 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 8331291 + * @summary Testing Attributes API. + * @run junit AttributesTest + */ +import java.lang.classfile.AttributeMapper; +import java.lang.classfile.Attributes; +import java.lang.classfile.constantpool.Utf8Entry; +import java.lang.reflect.Field; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +import jdk.internal.classfile.impl.BoundAttribute; +import jdk.internal.classfile.impl.TemporaryConstantPool; + +class AttributesTest { + + @Test + void testAttributesMapping() throws Exception { + var cp = TemporaryConstantPool.INSTANCE; + for (Field f : Attributes.class.getDeclaredFields()) { + if (f.getName().startsWith("NAME_") && f.getType() == String.class) { + Utf8Entry attrName = cp.utf8Entry((String)f.get(null)); + AttributeMapper mapper = BoundAttribute.standardAttribute(attrName); + assertNotNull(mapper, attrName.stringValue() + " 0x" + Integer.toHexString(attrName.hashCode())); + assertEquals(attrName.stringValue(), mapper.name()); + } + } + } +} diff --git a/test/jdk/jdk/classfile/BoundAttributeTest.java b/test/jdk/jdk/classfile/BoundAttributeTest.java index 8a25146bab9..103bcffa898 100644 --- a/test/jdk/jdk/classfile/BoundAttributeTest.java +++ b/test/jdk/jdk/classfile/BoundAttributeTest.java @@ -61,7 +61,7 @@ void testReadMethodParametersAttributeWithoutParameterName() { }); ClassModel model = cc.parse(raw); MethodParametersAttribute methodParametersAttribute = model.methods().get(0) - .findAttribute(Attributes.METHOD_PARAMETERS) + .findAttribute(Attributes.methodParameters()) .orElseThrow(() -> new AssertionFailedError("Attribute not present")); // MethodParametersAttribute#parameters() materializes the parameters List parameters = assertDoesNotThrow(methodParametersAttribute::parameters); diff --git a/test/jdk/jdk/classfile/CorpusTest.java b/test/jdk/jdk/classfile/CorpusTest.java index b13657e2072..21e275a837d 100644 --- a/test/jdk/jdk/classfile/CorpusTest.java +++ b/test/jdk/jdk/classfile/CorpusTest.java @@ -83,7 +83,7 @@ static void splitTableAttributes(String sourceClassFile, String targetClassFile) var dcob = (DirectCodeBuilder)cob; var curPc = dcob.curPc(); switch (coe) { - case LineNumber ln -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.LINE_NUMBER_TABLE) { + case LineNumber ln -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.lineNumberTable()) { @Override public void writeBody(BufWriter b) { b.writeU2(1); @@ -91,14 +91,14 @@ public void writeBody(BufWriter b) { b.writeU2(ln.line()); } }); - case LocalVariable lv -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.LOCAL_VARIABLE_TABLE) { + case LocalVariable lv -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTable()) { @Override public void writeBody(BufWriter b) { b.writeU2(1); lv.writeTo(b); } }); - case LocalVariableType lvt -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.LOCAL_VARIABLE_TYPE_TABLE) { + case LocalVariableType lvt -> dcob.writeAttribute(new UnboundAttribute.AdHocAttribute<>(Attributes.localVariableTypeTable()) { @Override public void writeBody(BufWriter b) { b.writeU2(1); diff --git a/test/jdk/jdk/classfile/FilterDeadLabelsTest.java b/test/jdk/jdk/classfile/FilterDeadLabelsTest.java index be527d7bc11..810f02d5f19 100644 --- a/test/jdk/jdk/classfile/FilterDeadLabelsTest.java +++ b/test/jdk/jdk/classfile/FilterDeadLabelsTest.java @@ -66,9 +66,9 @@ void testFilterDeadLabels() { }))).methods().get(0).code().get(); assertTrue(code.exceptionHandlers().isEmpty()); - code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).ifPresent(a -> assertTrue(a.localVariables().isEmpty())); - code.findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE).ifPresent(a -> assertTrue(a.localVariableTypes().isEmpty())); - code.findAttribute(Attributes.CHARACTER_RANGE_TABLE).ifPresent(a -> assertTrue(a.characterRangeTable().isEmpty())); + code.findAttribute(Attributes.localVariableTable()).ifPresent(a -> assertTrue(a.localVariables().isEmpty())); + code.findAttribute(Attributes.localVariableTypeTable()).ifPresent(a -> assertTrue(a.localVariableTypes().isEmpty())); + code.findAttribute(Attributes.characterRangeTable()).ifPresent(a -> assertTrue(a.characterRangeTable().isEmpty())); } @ParameterizedTest diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index a94a56ce33f..40ae8a5fb1f 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -127,7 +127,7 @@ void testInvalidLookupSwitch() { assertThrows(IllegalArgumentException.class, () -> ClassFile.of().parse(ClassFile.of().build(ClassDesc.of("LookupSwitchClass"), cb -> cb.withMethod( "lookupSwitchMethod", MethodTypeDesc.of(ConstantDescs.CD_void), 0, mb -> - ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.CODE) { + ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override public void writeBody(BufWriter b) { b.writeU2(-1);//max stack @@ -152,7 +152,7 @@ void testInvalidTableSwitch() { assertThrows(IllegalArgumentException.class, () -> ClassFile.of().parse(ClassFile.of().build(ClassDesc.of("TableSwitchClass"), cb -> cb.withMethod( "tableSwitchMethod", MethodTypeDesc.of(ConstantDescs.CD_void), 0, mb -> - ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.CODE) { + ((DirectMethodBuilder)mb).writeAttribute(new UnboundAttribute.AdHocAttribute(Attributes.code()) { @Override public void writeBody(BufWriter b) { b.writeU2(-1);//max stack diff --git a/test/jdk/jdk/classfile/LowJCovAttributeTest.java b/test/jdk/jdk/classfile/LowJCovAttributeTest.java index 9bc1e29155e..858b9c90416 100644 --- a/test/jdk/jdk/classfile/LowJCovAttributeTest.java +++ b/test/jdk/jdk/classfile/LowJCovAttributeTest.java @@ -94,8 +94,8 @@ private void testRead0() { } } for (MethodModel m : classLow.methods()) { - m.findAttribute(Attributes.CODE).ifPresent(code -> - ((CodeModel) code).findAttribute(Attributes.CHARACTER_RANGE_TABLE).ifPresent(attr -> { + m.findAttribute(Attributes.code()).ifPresent(code -> + ((CodeModel) code).findAttribute(Attributes.characterRangeTable()).ifPresent(attr -> { for (CharacterRangeInfo cr : attr.characterRangeTable()) { printf(" %d-%d -> %d/%d-%d/%d (%x)%n", cr.startPc(), cr.endPc(), cr.characterRangeStart() >> 10, cr.characterRangeStart() & 0x3FF, @@ -156,7 +156,7 @@ private void println() { // } // writeAndCompareAttributes(classLow, cp); // for (MethodLow m : classLow.methodsLow()) { -// m.findAttribute(Attributes.CODE).ifPresent(code -> +// m.findAttribute(Attributes.code()).ifPresent(code -> // writeAndCompareAttributes(code, cp)); // } // } diff --git a/test/jdk/jdk/classfile/LvtTest.java b/test/jdk/jdk/classfile/LvtTest.java index 35ec8dfcfa3..7c60d75823a 100644 --- a/test/jdk/jdk/classfile/LvtTest.java +++ b/test/jdk/jdk/classfile/LvtTest.java @@ -174,7 +174,7 @@ void testCreateLoadLVT() throws Exception { var c = cc.parse(bytes); var main = c.methods().get(1); - var lvt = main.code().get().findAttribute(Attributes.LOCAL_VARIABLE_TABLE).get(); + var lvt = main.code().get().findAttribute(Attributes.localVariableTable()).get(); var lvs = lvt.localVariables(); assertEquals(lvs.size(), 3); @@ -278,7 +278,7 @@ void testCreateLoadLVTT() throws Exception { }); var c = cc.parse(bytes); var main = c.methods().get(1); - var lvtt = main.code().get().findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE).get(); + var lvtt = main.code().get().findAttribute(Attributes.localVariableTypeTable()).get(); var lvts = lvtt.localVariableTypes(); /* From javap: diff --git a/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java b/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java index 825394bff0a..0ac9de70472 100644 --- a/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java +++ b/test/jdk/jdk/classfile/MassAdaptCopyPrimitiveMatchCodeTest.java @@ -120,7 +120,7 @@ void copy(String name, byte[] bytes) throws Exception { cb.with(e); }); //TODO: work-around to compiler bug generating multiple constant pool entries within records - if (cm.findAttribute(Attributes.RECORD).isPresent()) { + if (cm.findAttribute(Attributes.record()).isPresent()) { System.err.printf("MassAdaptCopyPrimitiveMatchCodeTest: Ignored because it is a record%n - %s%n", name); return; } diff --git a/test/jdk/jdk/classfile/ModuleBuilderTest.java b/test/jdk/jdk/classfile/ModuleBuilderTest.java index 68dd16ab03a..38e2dfef35a 100644 --- a/test/jdk/jdk/classfile/ModuleBuilderTest.java +++ b/test/jdk/jdk/classfile/ModuleBuilderTest.java @@ -89,7 +89,7 @@ public ModuleBuilderTest() { .with(ModuleMainClassAttribute.of(ClassDesc.of("overwritten.main.Class")))); moduleModel = cc.parse(modInfo); attr = ((ModuleAttribute) moduleModel.attributes().stream() - .filter(a -> a.attributeMapper() == Attributes.MODULE) + .filter(a -> a.attributeMapper() == Attributes.module()) .findFirst() .orElseThrow()); } @@ -103,7 +103,7 @@ void testCreateModuleInfo() { // Verify var cm = cc.parse(modBytes); - var attr =cm.findAttribute(Attributes.MODULE).get(); + var attr =cm.findAttribute(Attributes.module()).get(); assertEquals(attr.moduleName().name().stringValue(), modName.name()); assertEquals(attr.moduleFlagsMask(), 0); assertEquals(attr.moduleVersion().get().stringValue(), modVsn); @@ -181,13 +181,13 @@ void testVerifyProvides() { @Test void verifyPackages() { - ModulePackagesAttribute a = moduleModel.findAttribute(Attributes.MODULE_PACKAGES).orElseThrow(); + ModulePackagesAttribute a = moduleModel.findAttribute(Attributes.modulePackages()).orElseThrow(); assertEquals(a.packages().stream().map(pe -> pe.asSymbol().name()).toList(), List.of("foo.bar.baz", "quux")); } @Test void verifyMainclass() { - ModuleMainClassAttribute a = moduleModel.findAttribute(Attributes.MODULE_MAIN_CLASS).orElseThrow(); + ModuleMainClassAttribute a = moduleModel.findAttribute(Attributes.moduleMainClass()).orElseThrow(); assertEquals(a.mainClass().asInternalName(), "overwritten/main/Class"); } diff --git a/test/jdk/jdk/classfile/SignaturesTest.java b/test/jdk/jdk/classfile/SignaturesTest.java index f4da2405dcd..4bba69735da 100644 --- a/test/jdk/jdk/classfile/SignaturesTest.java +++ b/test/jdk/jdk/classfile/SignaturesTest.java @@ -133,7 +133,7 @@ void testParseAndPrintSignatures() throws Exception { .filter(p -> Files.isRegularFile(p) && p.toString().endsWith(".class")).forEach(path -> { try { var cm = ClassFile.of().parse(path); - cm.findAttribute(Attributes.SIGNATURE).ifPresent(csig -> { + cm.findAttribute(Attributes.signature()).ifPresent(csig -> { assertEquals( ClassSignature.parseFrom(csig.signature().stringValue()).signatureString(), csig.signature().stringValue(), @@ -141,7 +141,7 @@ void testParseAndPrintSignatures() throws Exception { csc.incrementAndGet(); }); for (var m : cm.methods()) { - m.findAttribute(Attributes.SIGNATURE).ifPresent(msig -> { + m.findAttribute(Attributes.signature()).ifPresent(msig -> { assertEquals( MethodSignature.parseFrom(msig.signature().stringValue()).signatureString(), msig.signature().stringValue(), @@ -150,7 +150,7 @@ void testParseAndPrintSignatures() throws Exception { }); } for (var f : cm.fields()) { - f.findAttribute(Attributes.SIGNATURE).ifPresent(fsig -> { + f.findAttribute(Attributes.signature()).ifPresent(fsig -> { assertEquals( Signature.parseFrom(fsig.signature().stringValue()).signatureString(), fsig.signature().stringValue(), @@ -158,8 +158,8 @@ void testParseAndPrintSignatures() throws Exception { fsc.incrementAndGet(); }); } - cm.findAttribute(Attributes.RECORD).ifPresent(reca - -> reca.components().forEach(rc -> rc.findAttribute(Attributes.SIGNATURE).ifPresent(rsig -> { + cm.findAttribute(Attributes.record()).ifPresent(reca + -> reca.components().forEach(rc -> rc.findAttribute(Attributes.signature()).ifPresent(rsig -> { assertEquals( Signature.parseFrom(rsig.signature().stringValue()).signatureString(), rsig.signature().stringValue(), @@ -182,7 +182,7 @@ static class Observer extends ArrayList.Inner>{} @Test void testClassSignatureClassDesc() throws IOException { var observerCf = ClassFile.of().parse(Path.of(System.getProperty("test.classes"), "SignaturesTest$Observer.class")); - var sig = observerCf.findAttribute(Attributes.SIGNATURE).orElseThrow().asClassSignature(); + var sig = observerCf.findAttribute(Attributes.signature()).orElseThrow().asClassSignature(); var arrayListSig = sig.superclassSignature(); // ArrayList var arrayListTypeArg = (TypeArg.Bounded) arrayListSig.typeArgs().getFirst(); // Outer.Inner assertEquals(TypeArg.Bounded.WildcardIndicator.NONE, arrayListTypeArg.wildcardIndicator()); diff --git a/test/jdk/jdk/classfile/TestRecordComponent.java b/test/jdk/jdk/classfile/TestRecordComponent.java index a4d173e2c67..95d56ffae8d 100644 --- a/test/jdk/jdk/classfile/TestRecordComponent.java +++ b/test/jdk/jdk/classfile/TestRecordComponent.java @@ -93,7 +93,7 @@ void testChagne() throws Exception { cb.with(ce); }; ClassModel newModel = cc.parse(cc.transform(cm, xform)); - RecordAttribute ra = newModel.findAttribute(Attributes.RECORD).orElseThrow(); + RecordAttribute ra = newModel.findAttribute(Attributes.record()).orElseThrow(); assertEquals(ra.components().size(), 2, "Should have two components"); assertEquals(ra.components().get(0).name().stringValue(), "fooXYZ"); assertEquals(ra.components().get(1).name().stringValue(), "barXYZ"); @@ -110,7 +110,7 @@ void testOptions() throws Exception { count.addAndGet(rm.components().size()); }}); assertEquals(count.get(), 2); - assertEquals(cm.findAttribute(Attributes.RECORD).orElseThrow().components().size(), 2); + assertEquals(cm.findAttribute(Attributes.record()).orElseThrow().components().size(), 2); count.set(0); } diff --git a/test/jdk/jdk/classfile/examples/AnnotationsExamples.java b/test/jdk/jdk/classfile/examples/AnnotationsExamples.java index d9c39748965..846645d93a9 100644 --- a/test/jdk/jdk/classfile/examples/AnnotationsExamples.java +++ b/test/jdk/jdk/classfile/examples/AnnotationsExamples.java @@ -54,8 +54,9 @@ public byte[] addAnno(ClassModel m) { * Find classes with annotations of a certain type */ public void findAnnotation(ClassModel m) { - if (m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).isPresent()) { - RuntimeVisibleAnnotationsAttribute a = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).get(); + var rvaa = m.findAttribute(Attributes.runtimeVisibleAnnotations()); + if (rvaa.isPresent()) { + RuntimeVisibleAnnotationsAttribute a = rvaa.get(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/FunctionalInterface;")) System.out.println(m.thisClass().asInternalName()); @@ -68,9 +69,9 @@ public void findAnnotation(ClassModel m) { */ public void swapAnnotation(ClassModel m) { ClassModel m2 = m; - - if (m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).isPresent()) { - RuntimeVisibleAnnotationsAttribute a = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).get(); + var rvaa = m.findAttribute(Attributes.runtimeVisibleAnnotations()); + if (rvaa.isPresent()) { + RuntimeVisibleAnnotationsAttribute a = rvaa.get(); var cc = ClassFile.of(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/annotation/Documented;")) { @@ -78,9 +79,9 @@ public void swapAnnotation(ClassModel m) { } } } - - if (m2.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).isPresent()) { - RuntimeVisibleAnnotationsAttribute a = m2.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).get(); + rvaa = m2.findAttribute(Attributes.runtimeVisibleAnnotations()); + if (rvaa.isPresent()) { + RuntimeVisibleAnnotationsAttribute a = rvaa.get(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/annotation/Documented;")) throw new RuntimeException(); @@ -112,9 +113,9 @@ public void swapAnnotation(ClassModel m) { */ public void addAnnotation(ClassModel m) { ClassModel m2 = m; - - if (m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).isPresent()) { - RuntimeVisibleAnnotationsAttribute a = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).get(); + var rvaa = m.findAttribute(Attributes.runtimeVisibleAnnotations()); + if (rvaa.isPresent()) { + RuntimeVisibleAnnotationsAttribute a = rvaa.get(); var cc = ClassFile.of(); for (Annotation ann : a.annotations()) { if (ann.className().stringValue().equals("Ljava/lang/FunctionalInterface;")) { @@ -135,7 +136,7 @@ public void addAnnotation(ClassModel m) { } } - int size = m2.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElseThrow().annotations().size(); + int size = m2.findAttribute(Attributes.runtimeVisibleAnnotations()).orElseThrow().annotations().size(); if (size !=2) { StringBuilder sb = new StringBuilder(); ClassPrinter.toJson(m2, ClassPrinter.Verbosity.TRACE_ALL, sb::append); diff --git a/test/jdk/jdk/classfile/examples/ModuleExamples.java b/test/jdk/jdk/classfile/examples/ModuleExamples.java index 69e71aaeb5c..d4f4ff9a695 100644 --- a/test/jdk/jdk/classfile/examples/ModuleExamples.java +++ b/test/jdk/jdk/classfile/examples/ModuleExamples.java @@ -54,14 +54,14 @@ public void examineModule() throws IOException { ClassModel cm = ClassFile.of().parse(JRT.getPath("modules/java.base/module-info.class")); System.out.println("Is JVMS $4.7 compatible module-info: " + cm.isModuleInfo()); - ModuleAttribute ma = cm.findAttribute(Attributes.MODULE).orElseThrow(); + ModuleAttribute ma = cm.findAttribute(Attributes.module()).orElseThrow(); System.out.println("Module name: " + ma.moduleName().name().stringValue()); System.out.println("Exports: " + ma.exports()); - ModuleMainClassAttribute mmca = cm.findAttribute(Attributes.MODULE_MAIN_CLASS).orElse(null); + ModuleMainClassAttribute mmca = cm.findAttribute(Attributes.moduleMainClass()).orElse(null); System.out.println("Does the module have a MainClassAttribute?: " + (mmca != null)); - ModulePackagesAttribute mmp = cm.findAttribute(Attributes.MODULE_PACKAGES).orElseThrow(); + ModulePackagesAttribute mmp = cm.findAttribute(Attributes.modulePackages()).orElseThrow(); System.out.println("Packages?: " + mmp.packages()); } diff --git a/test/jdk/jdk/classfile/helpers/ClassRecord.java b/test/jdk/jdk/classfile/helpers/ClassRecord.java index b348a51f23e..a62ef172367 100644 --- a/test/jdk/jdk/classfile/helpers/ClassRecord.java +++ b/test/jdk/jdk/classfile/helpers/ClassRecord.java @@ -243,75 +243,75 @@ public static AttributesRecord ofStreamingElements(Supplier (Attribute) e) .collect(toMap(Attribute::attributeName, e -> e)); return new AttributesRecord( - mapAttr(attrs, ANNOTATION_DEFAULT, a -> ElementValueRecord.ofElementValue(a.defaultValue())), + mapAttr(attrs, annotationDefault(), a -> ElementValueRecord.ofElementValue(a.defaultValue())), cp == null ? null : IntStream.range(0, cp.bootstrapMethodCount()).mapToObj(i -> BootstrapMethodRecord.ofBootstrapMethodEntry(cp.bootstrapMethodEntry(i))).collect(toSetOrNull()), - mapAttr(attrs, CODE, a -> CodeRecord.ofStreamingElements(a.maxStack(), a.maxLocals(), a.codeLength(), a::elementStream, a, new CodeNormalizerHelper(a.codeArray()), cf)), - mapAttr(attrs, COMPILATION_ID, a -> a.compilationId().stringValue()), - mapAttr(attrs, CONSTANT_VALUE, a -> ConstantPoolEntryRecord.ofCPEntry(a.constant())), - mapAttr(attrs, DEPRECATED, a -> DefinedValue.DEFINED), - mapAttr(attrs, ENCLOSING_METHOD, a -> EnclosingMethodRecord.ofEnclosingMethodAttribute(a)), - mapAttr(attrs, EXCEPTIONS, a -> new HashSet<>(a.exceptions().stream().map(e -> e.asInternalName()).toList())), - mapAttr(attrs, INNER_CLASSES, a -> a.classes().stream().collect(toMap(ic -> ic.innerClass().asInternalName(), ic -> InnerClassRecord.ofInnerClassInfo(ic)))), - mapAttr(attrs, METHOD_PARAMETERS, a -> a.parameters().stream().map(mp -> MethodParameterRecord.ofMethodParameter(mp)).toList()), - mapAttr(attrs, MODULE, a -> ModuleRecord.ofModuleAttribute(a)), - mapAttr(attrs, MODULE_HASHES, a -> ModuleHashesRecord.ofModuleHashesAttribute(a)), - mapAttr(attrs, MODULE_MAIN_CLASS, a -> a.mainClass().asInternalName()), - mapAttr(attrs, MODULE_PACKAGES, a -> a.packages().stream().map(p -> p.name().stringValue()).collect(toSet())), - mapAttr(attrs, MODULE_RESOLUTION, a -> a.resolutionFlags()), - mapAttr(attrs, MODULE_TARGET, a -> a.targetPlatform().stringValue()), - mapAttr(attrs, NEST_HOST, a -> a.nestHost().asInternalName()), - mapAttr(attrs, NEST_MEMBERS, a -> a.nestMembers().stream().map(m -> m.asInternalName()).collect(toSet())), - mapAttr(attrs, PERMITTED_SUBCLASSES, a -> new HashSet<>(a.permittedSubclasses().stream().map(e -> e.asInternalName()).toList())), - mapAttr(attrs, RECORD, a -> a.components().stream().map(rc -> RecordComponentRecord.ofRecordComponent(rc, cf)).toList()), + mapAttr(attrs, code(), a -> CodeRecord.ofStreamingElements(a.maxStack(), a.maxLocals(), a.codeLength(), a::elementStream, a, new CodeNormalizerHelper(a.codeArray()), cf)), + mapAttr(attrs, compilationId(), a -> a.compilationId().stringValue()), + mapAttr(attrs, constantValue(), a -> ConstantPoolEntryRecord.ofCPEntry(a.constant())), + mapAttr(attrs, Attributes.deprecated(), a -> DefinedValue.DEFINED), + mapAttr(attrs, enclosingMethod(), a -> EnclosingMethodRecord.ofEnclosingMethodAttribute(a)), + mapAttr(attrs, exceptions(), a -> new HashSet<>(a.exceptions().stream().map(e -> e.asInternalName()).toList())), + mapAttr(attrs, innerClasses(), a -> a.classes().stream().collect(toMap(ic -> ic.innerClass().asInternalName(), ic -> InnerClassRecord.ofInnerClassInfo(ic)))), + mapAttr(attrs, methodParameters(), a -> a.parameters().stream().map(mp -> MethodParameterRecord.ofMethodParameter(mp)).toList()), + mapAttr(attrs, module(), a -> ModuleRecord.ofModuleAttribute(a)), + mapAttr(attrs, moduleHashes(), a -> ModuleHashesRecord.ofModuleHashesAttribute(a)), + mapAttr(attrs, moduleMainClass(), a -> a.mainClass().asInternalName()), + mapAttr(attrs, modulePackages(), a -> a.packages().stream().map(p -> p.name().stringValue()).collect(toSet())), + mapAttr(attrs, moduleResolution(), a -> a.resolutionFlags()), + mapAttr(attrs, moduleTarget(), a -> a.targetPlatform().stringValue()), + mapAttr(attrs, nestHost(), a -> a.nestHost().asInternalName()), + mapAttr(attrs, nestMembers(), a -> a.nestMembers().stream().map(m -> m.asInternalName()).collect(toSet())), + mapAttr(attrs, permittedSubclasses(), a -> new HashSet<>(a.permittedSubclasses().stream().map(e -> e.asInternalName()).toList())), + mapAttr(attrs, record(), a -> a.components().stream().map(rc -> RecordComponentRecord.ofRecordComponent(rc, cf)).toList()), elements.get().filter(e -> e instanceof RuntimeVisibleAnnotationsAttribute).map(e -> (RuntimeVisibleAnnotationsAttribute) e).flatMap(a -> a.annotations().stream()) .map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), elements.get().filter(e -> e instanceof RuntimeInvisibleAnnotationsAttribute).map(e -> (RuntimeInvisibleAnnotationsAttribute) e).flatMap(a -> a.annotations().stream()) .map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), - mapAttr(attrs, RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), - mapAttr(attrs, RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), - mapAttr(attrs, RUNTIME_VISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), - mapAttr(attrs, RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), - mapAttr(attrs, SIGNATURE, a -> a.signature().stringValue()), - mapAttr(attrs, SOURCE_DEBUG_EXTENSION, a -> new String(a.contents(), StandardCharsets.UTF_8)), - mapAttr(attrs, SOURCE_FILE, a -> a.sourceFile().stringValue()), - mapAttr(attrs, SOURCE_ID, a -> a.sourceId().stringValue()), - mapAttr(attrs, SYNTHETIC, a -> DefinedValue.DEFINED) + mapAttr(attrs, runtimeVisibleParameterAnnotations(), a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), + mapAttr(attrs, runtimeInvisibleParameterAnnotations(), a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), + mapAttr(attrs, runtimeVisibleTypeAnnotations(), a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), + mapAttr(attrs, runtimeInvisibleTypeAnnotations(), a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), + mapAttr(attrs, signature(), a -> a.signature().stringValue()), + mapAttr(attrs, sourceDebugExtension(), a -> new String(a.contents(), StandardCharsets.UTF_8)), + mapAttr(attrs, sourceFile(), a -> a.sourceFile().stringValue()), + mapAttr(attrs, sourceId(), a -> a.sourceId().stringValue()), + mapAttr(attrs, synthetic(), a -> DefinedValue.DEFINED) ); } public static AttributesRecord ofAttributes(AttributeFinder af, CompatibilityFilter... cf) { return new AttributesRecord( - af.findAndMap(Attributes.ANNOTATION_DEFAULT, a -> ElementValueRecord.ofElementValue(a.defaultValue())), - af.findAndMap(Attributes.BOOTSTRAP_METHODS, a -> a.bootstrapMethods().stream().map(bm -> BootstrapMethodRecord.ofBootstrapMethodEntry(bm)).collect(toSet())), - af.findAndMap(Attributes.CODE, a -> CodeRecord.ofCodeAttribute(a, cf)), - af.findAndMap(Attributes.COMPILATION_ID, a -> a.compilationId().stringValue()), - af.findAndMap(Attributes.CONSTANT_VALUE, a -> ConstantPoolEntryRecord.ofCPEntry(a.constant())), - af.findAndMap(Attributes.DEPRECATED, a -> DefinedValue.DEFINED), - af.findAndMap(Attributes.ENCLOSING_METHOD, a -> EnclosingMethodRecord.ofEnclosingMethodAttribute(a)), - af.findAndMap(Attributes.EXCEPTIONS, a -> a.exceptions().stream().map(e -> e.asInternalName()).collect(toSet())), - af.findAndMap(Attributes.INNER_CLASSES, a -> a.classes().stream().collect(toMap(ic -> ic.innerClass().asInternalName(), ic -> InnerClassRecord.ofInnerClassInfo(ic)))), - af.findAndMap(Attributes.METHOD_PARAMETERS, a -> a.parameters().stream().map(mp -> MethodParameterRecord.ofMethodParameter(mp)).toList()), - af.findAndMap(Attributes.MODULE, a -> ModuleRecord.ofModuleAttribute(a)), - af.findAndMap(Attributes.MODULE_HASHES, a -> ModuleHashesRecord.ofModuleHashesAttribute(a)), - af.findAndMap(Attributes.MODULE_MAIN_CLASS, a -> a.mainClass().asInternalName()), - af.findAndMap(Attributes.MODULE_PACKAGES, a -> a.packages().stream().map(p -> p.name().stringValue()).collect(toSet())), - af.findAndMap(Attributes.MODULE_RESOLUTION, a -> a.resolutionFlags()), - af.findAndMap(Attributes.MODULE_TARGET, a -> a.targetPlatform().stringValue()), - af.findAndMap(Attributes.NEST_HOST, a -> a.nestHost().asInternalName()), - af.findAndMap(Attributes.NEST_MEMBERS, a -> a.nestMembers().stream().map(m -> m.asInternalName()).collect(toSet())), - af.findAndMap(Attributes.PERMITTED_SUBCLASSES, a -> a.permittedSubclasses().stream().map(e -> e.asInternalName()).collect(toSet())), - af.findAndMap(RECORD, a -> a.components().stream().map(rc -> RecordComponentRecord.ofRecordComponent(rc, cf)).toList()), - af.findAll(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).flatMap(a -> a.annotations().stream()).map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), - af.findAll(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).flatMap(a -> a.annotations().stream()).map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), - af.findAndMap(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS, a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), - af.findAndMap(Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS, a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), - af.findAndMap(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), - af.findAndMap(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), - af.findAndMap(Attributes.SIGNATURE, a -> a.signature().stringValue()), - af.findAndMap(Attributes.SOURCE_DEBUG_EXTENSION, a -> new String(a.contents(), StandardCharsets.UTF_8)), - af.findAndMap(Attributes.SOURCE_FILE, a -> a.sourceFile().stringValue()), - af.findAndMap(Attributes.SOURCE_ID, a -> a.sourceId().stringValue()), - af.findAndMap(Attributes.SYNTHETIC, a -> DefinedValue.DEFINED)); + af.findAndMap(annotationDefault(), a -> ElementValueRecord.ofElementValue(a.defaultValue())), + af.findAndMap(bootstrapMethods(), a -> a.bootstrapMethods().stream().map(bm -> BootstrapMethodRecord.ofBootstrapMethodEntry(bm)).collect(toSet())), + af.findAndMap(code(), a -> CodeRecord.ofCodeAttribute(a, cf)), + af.findAndMap(compilationId(), a -> a.compilationId().stringValue()), + af.findAndMap(constantValue(), a -> ConstantPoolEntryRecord.ofCPEntry(a.constant())), + af.findAndMap(Attributes.deprecated(), a -> DefinedValue.DEFINED), + af.findAndMap(enclosingMethod(), a -> EnclosingMethodRecord.ofEnclosingMethodAttribute(a)), + af.findAndMap(exceptions(), a -> a.exceptions().stream().map(e -> e.asInternalName()).collect(toSet())), + af.findAndMap(innerClasses(), a -> a.classes().stream().collect(toMap(ic -> ic.innerClass().asInternalName(), ic -> InnerClassRecord.ofInnerClassInfo(ic)))), + af.findAndMap(methodParameters(), a -> a.parameters().stream().map(mp -> MethodParameterRecord.ofMethodParameter(mp)).toList()), + af.findAndMap(module(), a -> ModuleRecord.ofModuleAttribute(a)), + af.findAndMap(moduleHashes(), a -> ModuleHashesRecord.ofModuleHashesAttribute(a)), + af.findAndMap(moduleMainClass(), a -> a.mainClass().asInternalName()), + af.findAndMap(modulePackages(), a -> a.packages().stream().map(p -> p.name().stringValue()).collect(toSet())), + af.findAndMap(moduleResolution(), a -> a.resolutionFlags()), + af.findAndMap(moduleTarget(), a -> a.targetPlatform().stringValue()), + af.findAndMap(nestHost(), a -> a.nestHost().asInternalName()), + af.findAndMap(nestMembers(), a -> a.nestMembers().stream().map(m -> m.asInternalName()).collect(toSet())), + af.findAndMap(permittedSubclasses(), a -> a.permittedSubclasses().stream().map(e -> e.asInternalName()).collect(toSet())), + af.findAndMap(record(), a -> a.components().stream().map(rc -> RecordComponentRecord.ofRecordComponent(rc, cf)).toList()), + af.findAll(runtimeVisibleAnnotations()).flatMap(a -> a.annotations().stream()).map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), + af.findAll(runtimeInvisibleAnnotations()).flatMap(a -> a.annotations().stream()).map(AnnotationRecord::ofAnnotation).collect(toSetOrNull()), + af.findAndMap(runtimeVisibleParameterAnnotations(), a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), + af.findAndMap(runtimeInvisibleParameterAnnotations(), a -> a.parameterAnnotations().stream().map(list -> list.stream().map(AnnotationRecord::ofAnnotation).collect(toSet())).toList()), + af.findAndMap(runtimeVisibleTypeAnnotations(), a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), + af.findAndMap(runtimeInvisibleTypeAnnotations(), a -> a.annotations().stream().map(TypeAnnotationRecord::ofTypeAnnotation).collect(toSet())), + af.findAndMap(signature(), a -> a.signature().stringValue()), + af.findAndMap(sourceDebugExtension(), a -> new String(a.contents(), StandardCharsets.UTF_8)), + af.findAndMap(sourceFile(), a -> a.sourceFile().stringValue()), + af.findAndMap(sourceId(), a -> a.sourceId().stringValue()), + af.findAndMap(synthetic(), a -> DefinedValue.DEFINED)); } } @@ -353,12 +353,12 @@ static CodeAttributesRecord ofStreamingElements(Supplier a.characterRangeTable().stream()).map(cr -> CharacterRangeRecord.ofCharacterRange(cr, code)).collect(toSetOrNull()), - af.findAll(Attributes.LINE_NUMBER_TABLE).flatMap(a -> a.lineNumbers().stream()).map(ln -> new LineNumberRecord(ln.lineNumber(), code.targetIndex(ln.startPc()))).collect(toSetOrNull()), - af.findAll(Attributes.LOCAL_VARIABLE_TABLE).flatMap(a -> a.localVariables().stream()).map(lv -> LocalVariableRecord.ofLocalVariableInfo(lv, code)).collect(toSetOrNull()), - af.findAll(Attributes.LOCAL_VARIABLE_TYPE_TABLE).flatMap(a -> a.localVariableTypes().stream()).map(lv -> LocalVariableTypeRecord.ofLocalVariableTypeInfo(lv, code)).collect(toSetOrNull()), - af.findAndMap(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(ann -> TypeAnnotationRecord.ofTypeAnnotation(ann, lr, code)).collect(toSet())), - af.findAndMap(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, a -> a.annotations().stream().map(ann -> TypeAnnotationRecord.ofTypeAnnotation(ann, lr, code)).collect(toSet()))); + af.findAll(Attributes.characterRangeTable()).flatMap(a -> a.characterRangeTable().stream()).map(cr -> CharacterRangeRecord.ofCharacterRange(cr, code)).collect(toSetOrNull()), + af.findAll(Attributes.lineNumberTable()).flatMap(a -> a.lineNumbers().stream()).map(ln -> new LineNumberRecord(ln.lineNumber(), code.targetIndex(ln.startPc()))).collect(toSetOrNull()), + af.findAll(Attributes.localVariableTable()).flatMap(a -> a.localVariables().stream()).map(lv -> LocalVariableRecord.ofLocalVariableInfo(lv, code)).collect(toSetOrNull()), + af.findAll(Attributes.localVariableTypeTable()).flatMap(a -> a.localVariableTypes().stream()).map(lv -> LocalVariableTypeRecord.ofLocalVariableTypeInfo(lv, code)).collect(toSetOrNull()), + af.findAndMap(Attributes.runtimeVisibleTypeAnnotations(), a -> a.annotations().stream().map(ann -> TypeAnnotationRecord.ofTypeAnnotation(ann, lr, code)).collect(toSet())), + af.findAndMap(Attributes.runtimeInvisibleTypeAnnotations(), a -> a.annotations().stream().map(ann -> TypeAnnotationRecord.ofTypeAnnotation(ann, lr, code)).collect(toSet()))); } } diff --git a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java index 85fac494066..0c9b771c3ef 100644 --- a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java +++ b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java @@ -76,7 +76,7 @@ static byte[] transform(ClassModel clm) { // first pass transforms bound to unbound instructions cob3.transforming(new CodeRebuildingTransform(), cob4 -> { com.forEachElement(cob4::with); - com.findAttribute(Attributes.STACK_MAP_TABLE).ifPresent(cob4::with); + com.findAttribute(Attributes.stackMapTable()).ifPresent(cob4::with); })))); case AnnotationDefaultAttribute a -> mb.with(AnnotationDefaultAttribute.of(transformAnnotationValue(a.defaultValue()))); case DeprecatedAttribute a -> mb.with(DeprecatedAttribute.of()); diff --git a/test/jdk/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java b/test/jdk/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java index a313aab2552..2d5175dcf3f 100644 --- a/test/jdk/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java +++ b/test/jdk/jdk/internal/reflect/CallerSensitive/CallerSensitiveFinder.java @@ -164,7 +164,7 @@ public List run(Stream classes)throws IOException, InterruptedExce private static final String CALLER_SENSITIVE_ANNOTATION = "Ljdk/internal/reflect/CallerSensitive;"; private static boolean isCallerSensitive(MethodModel m) { - var attr = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + var attr = m.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (attr != null) { for (var ann : attr.annotations()) { if (ann.className().equalsString(CALLER_SENSITIVE_ANNOTATION)) { diff --git a/test/jdk/jdk/internal/reflect/CallerSensitive/CheckCSMs.java b/test/jdk/jdk/internal/reflect/CallerSensitive/CheckCSMs.java index 0a8a0ccfaea..6dff95000f0 100644 --- a/test/jdk/jdk/internal/reflect/CallerSensitive/CheckCSMs.java +++ b/test/jdk/jdk/internal/reflect/CallerSensitive/CheckCSMs.java @@ -238,7 +238,7 @@ private static boolean csmWithCallerParameter(ClassModel cf, MethodModel csm, Me private static boolean isCallerSensitive(MethodModel m) throws IllegalArgumentException { - var attr = m.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + var attr = m.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (attr != null) { for (var ann : attr.annotations()) { if (ann.className().equalsString(CALLER_SENSITIVE_ANNOTATION)) { @@ -250,7 +250,7 @@ private static boolean isCallerSensitive(MethodModel m) } private static boolean isCallerSensitiveAdapter(MethodModel m) { - var attr = m.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); + var attr = m.findAttribute(Attributes.runtimeInvisibleAnnotations()).orElse(null); if (attr != null) { for (var ann : attr.annotations()) { diff --git a/test/jdk/tools/jlink/plugins/StripJavaDebugAttributesPluginTest.java b/test/jdk/tools/jlink/plugins/StripJavaDebugAttributesPluginTest.java index 79a52f57288..0bcb19e087c 100644 --- a/test/jdk/tools/jlink/plugins/StripJavaDebugAttributesPluginTest.java +++ b/test/jdk/tools/jlink/plugins/StripJavaDebugAttributesPluginTest.java @@ -137,16 +137,16 @@ private > void checkDebugAttributes(byte[] strippedClassF ClassModel classFile = ClassFile.of().parse(strippedClassFile); for (MethodModel method : classFile.methods()) { String methodName = method.methodName().stringValue(); - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); - if (code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElse(null) != null) { + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); + if (code.findAttribute(Attributes.lineNumberTable()).orElse(null) != null) { throw new AssertionError("Debug attribute was not removed: " + "LINE_NUMBER_TABLE" + " from method " + classFile.thisClass().asInternalName() + "#" + methodName); } - if (code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).orElse(null) != null) { + if (code.findAttribute(Attributes.localVariableTable()).orElse(null) != null) { throw new AssertionError("Debug attribute was not removed: " + "LOCAL_VARIABLE_TABLE" + " from method " + classFile.thisClass().asInternalName() + "#" + methodName); } - if (code.findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE).orElse(null) != null) { + if (code.findAttribute(Attributes.localVariableTypeTable()).orElse(null) != null) { throw new AssertionError("Debug attribute was not removed: " + "LOCAL_VARIABLE_TYPE_TABLE" + " from method " + classFile.thisClass().asInternalName() + "#" + methodName); } diff --git a/test/langtools/tools/javac/4241573/T4241573.java b/test/langtools/tools/javac/4241573/T4241573.java index 93164bad57f..9989ff83454 100644 --- a/test/langtools/tools/javac/4241573/T4241573.java +++ b/test/langtools/tools/javac/4241573/T4241573.java @@ -109,7 +109,7 @@ void verifySourceFileAttribute(File f) { System.err.println("verify: " + f); try { ClassModel cf = ClassFile.of().parse(f.toPath()); - SourceFileAttribute sfa = cf.findAttribute(Attributes.SOURCE_FILE).orElseThrow(); + SourceFileAttribute sfa = cf.findAttribute(Attributes.sourceFile()).orElseThrow(); String found = sfa.sourceFile().stringValue(); String expect = f.getName().replaceAll("([$.].*)?\\.class", ".java"); if (!expect.equals(found)) { diff --git a/test/langtools/tools/javac/7003595/T7003595.java b/test/langtools/tools/javac/7003595/T7003595.java index 94fb0c4b09c..c5c12259c14 100644 --- a/test/langtools/tools/javac/7003595/T7003595.java +++ b/test/langtools/tools/javac/7003595/T7003595.java @@ -163,7 +163,7 @@ void verifyBytecode(JavaSource source) { throw new Error("Classfile not found: " + filename); } - InnerClassesAttribute innerClasses = cf.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute innerClasses = cf.findAttribute(Attributes.innerClasses()).orElse(null); ArrayList foundInnerSig = new ArrayList<>(); if (innerClasses != null) { diff --git a/test/langtools/tools/javac/8009170/RedundantByteCodeInArrayTest.java b/test/langtools/tools/javac/8009170/RedundantByteCodeInArrayTest.java index a9821e75ac0..8f2ed91039c 100644 --- a/test/langtools/tools/javac/8009170/RedundantByteCodeInArrayTest.java +++ b/test/langtools/tools/javac/8009170/RedundantByteCodeInArrayTest.java @@ -56,7 +56,7 @@ void checkClassFile(File file) //lets get all the methods in the class file. for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString("arrMethod")) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = method.findAttribute(Attributes.code()).orElse(null); assert code != null; if (code.maxLocals() > 4) throw new AssertionError("Too many locals for method arrMethod"); diff --git a/test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java b/test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java index 7769b1caf32..fb78132e4f1 100644 --- a/test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java +++ b/test/langtools/tools/javac/AnonymousClass/AnonymousClassFlags.java @@ -125,7 +125,7 @@ static void assertInnerFlags(ClassModel classFile, String name, int expected) { } private static int lookupInnerFlags(ClassModel classFile, String innerName) { - InnerClassesAttribute inners = classFile.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute inners = classFile.findAttribute(Attributes.innerClasses()).orElse(null); if (inners == null) { throw new AssertionError("InnerClasses attribute missing in class " + classFile.thisClass().asInternalName()); } diff --git a/test/langtools/tools/javac/MethodParameters/ClassFileVisitor.java b/test/langtools/tools/javac/MethodParameters/ClassFileVisitor.java index 61025606414..3e2d151808f 100644 --- a/test/langtools/tools/javac/MethodParameters/ClassFileVisitor.java +++ b/test/langtools/tools/javac/MethodParameters/ClassFileVisitor.java @@ -95,7 +95,7 @@ void visitClass(final String cname, final File cfile, final StringBuilder sb) th isStatic = false; isAnon = false; - classFile.findAttribute(Attributes.INNER_CLASSES).ifPresent(this::visitInnerClasses); + classFile.findAttribute(Attributes.innerClasses()).ifPresent(this::visitInnerClasses); isAnon = isInner & isAnon; sb.append(isStatic ? "static " : "") diff --git a/test/langtools/tools/javac/MethodParameters/LegacyOutputTest/LegacyOutputTest.java b/test/langtools/tools/javac/MethodParameters/LegacyOutputTest/LegacyOutputTest.java index 3f613be7e82..dad79da509e 100644 --- a/test/langtools/tools/javac/MethodParameters/LegacyOutputTest/LegacyOutputTest.java +++ b/test/langtools/tools/javac/MethodParameters/LegacyOutputTest/LegacyOutputTest.java @@ -86,7 +86,7 @@ List getParameterNames(String release) throws Exception { } ClassModel classFile = ClassFile.of().parse(Paths.get("Test.class")); MethodModel method = getMethod(classFile, "f"); - MethodParametersAttribute attribute = method.findAttribute(Attributes.METHOD_PARAMETERS).orElse(null); + MethodParametersAttribute attribute = method.findAttribute(Attributes.methodParameters()).orElse(null); if (attribute == null) { return null; } diff --git a/test/langtools/tools/javac/MethodParametersTest.java b/test/langtools/tools/javac/MethodParametersTest.java index 5c7a891cdb0..8ce73671d1f 100644 --- a/test/langtools/tools/javac/MethodParametersTest.java +++ b/test/langtools/tools/javac/MethodParametersTest.java @@ -175,8 +175,8 @@ void modifyBaz(boolean flip) throws Exception { if (!baz.methods().get(0).methodName().equalsString("")) throw new Exception("Classfile Baz badly formed: method has name " + baz.methods().get(0).methodName().stringValue()); - MethodParametersAttribute mpattr = baz.methods().get(0).findAttribute(Attributes.METHOD_PARAMETERS).orElse(null); - CodeAttribute cattr = baz.methods().get(0).findAttribute(Attributes.CODE).orElse(null);; + MethodParametersAttribute mpattr = baz.methods().get(0).findAttribute(Attributes.methodParameters()).orElse(null); + CodeAttribute cattr = baz.methods().get(0).findAttribute(Attributes.code()).orElse(null);; if (null == mpattr) throw new Exception("Classfile Baz badly formed: no method parameters info"); if (null == cattr) diff --git a/test/langtools/tools/javac/RequiredParameterFlags/ImplicitParameters.java b/test/langtools/tools/javac/RequiredParameterFlags/ImplicitParameters.java index 64db03abdae..0eb4d1b8a42 100644 --- a/test/langtools/tools/javac/RequiredParameterFlags/ImplicitParameters.java +++ b/test/langtools/tools/javac/RequiredParameterFlags/ImplicitParameters.java @@ -195,7 +195,7 @@ public void testCompactConstructor(ClassModel classFile) { } private void checkParameters(MethodModel method, int... parametersFlags) { - MethodParametersAttribute methodParameters = method.findAttribute(Attributes.METHOD_PARAMETERS).orElseThrow(); + MethodParametersAttribute methodParameters = method.findAttribute(Attributes.methodParameters()).orElseThrow(); Assert.checkNonNull(methodParameters, "MethodParameters attribute must be present"); List table = methodParameters.parameters(); Assert.check(table.size() == parametersFlags.length, () -> "Expected " + parametersFlags.length diff --git a/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java b/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java index 72576a7fcb8..8ec49a17c4d 100644 --- a/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java +++ b/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java @@ -24,13 +24,12 @@ import jdk.test.lib.compiler.CompilerUtils; import toolbox.ToolBox; -import java.lang.classfile.Attributes; import java.lang.classfile.BootstrapMethodEntry; import java.lang.classfile.ClassFile; import java.lang.classfile.ClassModel; import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeModel; import java.lang.classfile.MethodModel; -import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.constantpool.MethodHandleEntry; import java.lang.classfile.instruction.InvokeDynamicInstruction; import java.nio.file.Path; @@ -87,7 +86,7 @@ public static boolean hasStringConcatFactoryCall(Path file, String methodName) t for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString(methodName)) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeModel code = method.code().orElseThrow(); for (CodeElement i : code.elementList()) { if (i instanceof InvokeDynamicInstruction indy) { BootstrapMethodEntry bsmSpec = indy.invokedynamic().bootstrap(); diff --git a/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java b/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java index 60d54944168..174e9721f3f 100644 --- a/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java +++ b/test/langtools/tools/javac/StringConcat/WellKnownTypeSignatures.java @@ -104,7 +104,7 @@ public static void readIndyTypes() throws Exception { for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString("main")) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement i : code.elementList()) { if (i instanceof InvokeDynamicInstruction) { InvokeDynamicInstruction indy = (InvokeDynamicInstruction) i; diff --git a/test/langtools/tools/javac/StringConcat/access/Test.java b/test/langtools/tools/javac/StringConcat/access/Test.java index 93ee3ec7c3f..c4aa54618ea 100644 --- a/test/langtools/tools/javac/StringConcat/access/Test.java +++ b/test/langtools/tools/javac/StringConcat/access/Test.java @@ -182,7 +182,7 @@ public static void readIndyTypes() throws Exception { for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString("main")) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement i : code.elementList()) { if (i instanceof InvokeDynamicInstruction) { InvokeDynamicEntry indyInfo = ((InvokeDynamicInstruction) i).invokedynamic(); diff --git a/test/langtools/tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java b/test/langtools/tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java index 53adfe17d18..bb486b32382 100644 --- a/test/langtools/tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java +++ b/test/langtools/tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java @@ -63,9 +63,9 @@ > void checkClassFile(final Path cfilePath) throws Except ClassModel classFile = ClassFile.of().parse(cfilePath); for (MethodModel method : classFile.methods()) { if ((method.flags().flagsMask() & ClassFile.ACC_BRIDGE) != 0) { - Assert.checkNonNull(method.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS), + Assert.checkNonNull(method.findAttribute(Attributes.runtimeVisibleAnnotations()), "Annotations hasn't been copied to bridge method"); - Assert.checkNonNull(method.findAttribute(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS), + Assert.checkNonNull(method.findAttribute(Attributes.runtimeVisibleParameterAnnotations()), "Annotations hasn't been copied to bridge method"); } } diff --git a/test/langtools/tools/javac/T6970173/DebugPointerAtBadPositionTest.java b/test/langtools/tools/javac/T6970173/DebugPointerAtBadPositionTest.java index 350d03c8c3b..56813905ca5 100644 --- a/test/langtools/tools/javac/T6970173/DebugPointerAtBadPositionTest.java +++ b/test/langtools/tools/javac/T6970173/DebugPointerAtBadPositionTest.java @@ -94,8 +94,8 @@ void checkClassFile(final File cfile, String methodToFind) throws Exception { for (MethodModel m : classFile.methods()) { if (m.methodName().equalsString(methodToFind)) { methodFound = true; - CodeAttribute code = m.findAttribute(Attributes.CODE).orElseThrow(); - LineNumberTableAttribute lnt = code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElseThrow(); + CodeAttribute code = m.findAttribute(Attributes.code()).orElseThrow(); + LineNumberTableAttribute lnt = code.findAttribute(Attributes.lineNumberTable()).orElseThrow(); Assert.check(lnt.lineNumbers().size() == expectedLNT.length, foundLNTLengthDifferentThanExpMsg); int i = 0; diff --git a/test/langtools/tools/javac/T7008643/InlinedFinallyConfuseDebuggersTest.java b/test/langtools/tools/javac/T7008643/InlinedFinallyConfuseDebuggersTest.java index 5f764424713..839c835c800 100644 --- a/test/langtools/tools/javac/T7008643/InlinedFinallyConfuseDebuggersTest.java +++ b/test/langtools/tools/javac/T7008643/InlinedFinallyConfuseDebuggersTest.java @@ -101,8 +101,8 @@ void checkClassFile(final File cfile, String methodToFind) throws Exception { for (MethodModel m : classFile.methods()) { if (m.methodName().equalsString(methodToFind)) { methodFound = true; - CodeAttribute code = m.findAttribute(Attributes.CODE).orElseThrow(); - LineNumberTableAttribute lnt = code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElseThrow(); + CodeAttribute code = m.findAttribute(Attributes.code()).orElseThrow(); + LineNumberTableAttribute lnt = code.findAttribute(Attributes.lineNumberTable()).orElseThrow(); Assert.check(lnt.lineNumbers().size() == expectedLNT.length, "The LineNumberTable found has a length different to the expected one"); int i = 0; diff --git a/test/langtools/tools/javac/T7053059/DoubleCastTest.java b/test/langtools/tools/javac/T7053059/DoubleCastTest.java index 84c39a6cb16..2aaf5d40f39 100644 --- a/test/langtools/tools/javac/T7053059/DoubleCastTest.java +++ b/test/langtools/tools/javac/T7053059/DoubleCastTest.java @@ -68,7 +68,7 @@ public static void main(String... cmdline) throws Exception { static void check(MethodModel m) throws Exception { boolean last_is_cast = false; ClassEntry last_ref = null; - CodeAttribute ea = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute ea = m.findAttribute(Attributes.code()).orElseThrow(); for (int i = 0; i < ea.elementList().size(); ++i) { CodeElement ce = ea.elementList().get(i); if (ce instanceof TypeCheckInstruction ins && ins.opcode() == Opcode.CHECKCAST) { diff --git a/test/langtools/tools/javac/T7093325.java b/test/langtools/tools/javac/T7093325.java index 948d775c578..0a8fac0692b 100644 --- a/test/langtools/tools/javac/T7093325.java +++ b/test/langtools/tools/javac/T7093325.java @@ -167,7 +167,7 @@ void verifyBytecode(Result> result) { return; } - CodeAttribute code = test_method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = test_method.findAttribute(Attributes.code()).orElse(null); if (code == null) { fail("Code attribute not found in method test()"); diff --git a/test/langtools/tools/javac/T7165659/InnerClassAttrMustNotHaveStrictFPFlagTest.java b/test/langtools/tools/javac/T7165659/InnerClassAttrMustNotHaveStrictFPFlagTest.java index fc4aae5a0ae..d7b823d94ec 100644 --- a/test/langtools/tools/javac/T7165659/InnerClassAttrMustNotHaveStrictFPFlagTest.java +++ b/test/langtools/tools/javac/T7165659/InnerClassAttrMustNotHaveStrictFPFlagTest.java @@ -48,7 +48,7 @@ private void run() throws Exception { void analyzeClassFile(File path) throws Exception { ClassModel classFile = ClassFile.of().parse(path.toPath()); - InnerClassesAttribute innerClasses = classFile.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute innerClasses = classFile.findAttribute(Attributes.innerClasses()).orElse(null); assert innerClasses != null; for (InnerClassInfo classInfo : innerClasses.classes()) { Assert.check(classInfo.flagsMask() != ClassFile.ACC_STRICT, diff --git a/test/langtools/tools/javac/T8019486/WrongLNTForLambdaTest.java b/test/langtools/tools/javac/T8019486/WrongLNTForLambdaTest.java index 7c334d35f7c..24c9b81c964 100644 --- a/test/langtools/tools/javac/T8019486/WrongLNTForLambdaTest.java +++ b/test/langtools/tools/javac/T8019486/WrongLNTForLambdaTest.java @@ -163,8 +163,8 @@ void checkClassFile(final File cfile, String methodToFind, int[][] expectedLNT) for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString(methodToFind)) { methodFound = true; - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); - LineNumberTableAttribute lnt = code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElseThrow(); + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); + LineNumberTableAttribute lnt = code.findAttribute(Attributes.lineNumberTable()).orElseThrow(); Assert.check(lnt.lineNumbers().size() == expectedLNT.length, "The LineNumberTable found has a length different to the expected one"); int i = 0; diff --git a/test/langtools/tools/javac/T8022186/DeadCodeGeneratedForEmptyTryTest.java b/test/langtools/tools/javac/T8022186/DeadCodeGeneratedForEmptyTryTest.java index d3b6851f87b..8dd87820423 100644 --- a/test/langtools/tools/javac/T8022186/DeadCodeGeneratedForEmptyTryTest.java +++ b/test/langtools/tools/javac/T8022186/DeadCodeGeneratedForEmptyTryTest.java @@ -64,7 +64,7 @@ void checkClassFile(final Path path) throws Exception { constantPool = classFile.constantPool(); for (MethodModel method: classFile.methods()) { if (method.methodName().equalsString("methodToLookFor")) { - CodeAttribute codeAtt = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAtt = method.findAttribute(Attributes.code()).orElseThrow(); codeAtt.elementList().stream() .filter(ce -> ce instanceof Instruction) .forEach(ins -> checkIndirectRefToString((Instruction) ins)); diff --git a/test/langtools/tools/javac/T8024039/NoDeadCodeGenerationOnTrySmtTest.java b/test/langtools/tools/javac/T8024039/NoDeadCodeGenerationOnTrySmtTest.java index 27d01bbf27b..36afea59094 100644 --- a/test/langtools/tools/javac/T8024039/NoDeadCodeGenerationOnTrySmtTest.java +++ b/test/langtools/tools/javac/T8024039/NoDeadCodeGenerationOnTrySmtTest.java @@ -106,7 +106,7 @@ void checkClassFile(final File cfile, String[] methodsToFind) throws Exception { for (MethodModel m : classFile.methods()) { if (m.methodName().equalsString(methodToFind)) { numberOfmethodsFound++; - CodeAttribute code = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code = m.findAttribute(Attributes.code()).orElseThrow(); Assert.check(code.exceptionHandlers().size() == expectedExceptionTable.length, "The ExceptionTable found has a length different to the expected one"); int i = 0; diff --git a/test/langtools/tools/javac/T8028504/DontGenerateLVTForGNoneOpTest.java b/test/langtools/tools/javac/T8028504/DontGenerateLVTForGNoneOpTest.java index 90352ba6702..150b0fc8c7c 100644 --- a/test/langtools/tools/javac/T8028504/DontGenerateLVTForGNoneOpTest.java +++ b/test/langtools/tools/javac/T8028504/DontGenerateLVTForGNoneOpTest.java @@ -52,9 +52,9 @@ void run() throws Exception { void checkClassFile(final File cfile) throws Exception { ClassModel classFile = ClassFile.of().parse(cfile.toPath()); for (MethodModel method : classFile.methods()) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = method.findAttribute(Attributes.code()).orElse(null); if (code != null) { - if (code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).orElse(null) != null) { + if (code.findAttribute(Attributes.localVariableTable()).orElse(null) != null) { throw new AssertionError("LVT shouldn't be generated for g:none"); } } diff --git a/test/langtools/tools/javac/T8180141/MissingLNTEntryForBreakContinueTest.java b/test/langtools/tools/javac/T8180141/MissingLNTEntryForBreakContinueTest.java index 5ca65bf9ad8..1a095ab5301 100644 --- a/test/langtools/tools/javac/T8180141/MissingLNTEntryForBreakContinueTest.java +++ b/test/langtools/tools/javac/T8180141/MissingLNTEntryForBreakContinueTest.java @@ -92,8 +92,8 @@ void testFor(String id, String statement) throws Throwable { ClassModel classFile = ClassFile.of().parse(file.toPath()); for (MethodModel m : classFile.methods()) { if (m.methodName().equalsString("foo")) { - CodeAttribute code = m.findAttribute(Attributes.CODE).orElseThrow(); - LineNumberTableAttribute lnt = code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElseThrow(); + CodeAttribute code = m.findAttribute(Attributes.code()).orElseThrow(); + LineNumberTableAttribute lnt = code.findAttribute(Attributes.lineNumberTable()).orElseThrow(); checkLNT(lnt, MyAttr.lineNumber); } } diff --git a/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java b/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java index 504057ed7be..1cd9ee211e0 100644 --- a/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java +++ b/test/langtools/tools/javac/T8180660/MissingLNTEntryForFinalizerTest.java @@ -88,8 +88,8 @@ void test() throws Throwable { ClassModel classFile = ClassFile.of().parse(file.toPath()); for (MethodModel m : classFile.methods()) { if (m.methodName().equalsString("foo")) { - CodeAttribute code = m.findAttribute(Attributes.CODE).orElseThrow(); - LineNumberTableAttribute lnt = code.findAttribute(Attributes.LINE_NUMBER_TABLE).orElseThrow(); + CodeAttribute code = m.findAttribute(Attributes.code()).orElseThrow(); + LineNumberTableAttribute lnt = code.findAttribute(Attributes.lineNumberTable()).orElseThrow(); checkLNT(lnt, MyAttr.lineNumber); } } diff --git a/test/langtools/tools/javac/T8210435/NoLocalsMustBeReservedForDCEedVarsTest.java b/test/langtools/tools/javac/T8210435/NoLocalsMustBeReservedForDCEedVarsTest.java index 69819dd845e..35ccb627b44 100644 --- a/test/langtools/tools/javac/T8210435/NoLocalsMustBeReservedForDCEedVarsTest.java +++ b/test/langtools/tools/javac/T8210435/NoLocalsMustBeReservedForDCEedVarsTest.java @@ -68,7 +68,7 @@ void run() throws Exception { ClassModel classFile = ClassFile.of().parse(cfile.toPath()); for (MethodModel method: classFile.methods()) { if (method.methodName().stringValue().equals("foo")) { - CodeAttribute codeAttr = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute codeAttr = method.findAttribute(Attributes.code()).orElse(null); assert codeAttr != null; Assert.check(codeAttr.maxLocals() == 0, "max locals found " + codeAttr.maxLocals()); } diff --git a/test/langtools/tools/javac/T8222949/TestConstantDynamic.java b/test/langtools/tools/javac/T8222949/TestConstantDynamic.java index 79e1fbb047f..d6f728eda5a 100644 --- a/test/langtools/tools/javac/T8222949/TestConstantDynamic.java +++ b/test/langtools/tools/javac/T8222949/TestConstantDynamic.java @@ -186,7 +186,7 @@ void verifyBytecode(Result> res) { fail("Test method not found"); return; } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { fail("Code attribute for test() method not found"); return; @@ -216,7 +216,7 @@ void verifyBytecode(Result> res) { return; } - BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); if (bsm_attr.bootstrapMethods().size() != 1) { fail("Bad number of method specifiers " + "in BootstrapMethods attribute"); @@ -251,7 +251,7 @@ void verifyBytecode(Result> res) { return; } - LineNumberTableAttribute lnt = ea.findAttribute(Attributes.LINE_NUMBER_TABLE).orElse(null); + LineNumberTableAttribute lnt = ea.findAttribute(Attributes.lineNumberTable()).orElse(null); if (lnt == null) { fail("No LineNumberTable attribute"); diff --git a/test/langtools/tools/javac/TryWithResources/TwrSimpleClose.java b/test/langtools/tools/javac/TryWithResources/TwrSimpleClose.java index 45e30cd4516..4c1e3a48275 100644 --- a/test/langtools/tools/javac/TryWithResources/TwrSimpleClose.java +++ b/test/langtools/tools/javac/TryWithResources/TwrSimpleClose.java @@ -101,7 +101,7 @@ void run(String trySpec, int expectedCloseCount) throws Exception { ClassModel cf = ClassFile.of().parse(new ByteArrayInputStream(data).readAllBytes()); for (MethodModel m : cf.methods()) { - CodeAttribute codeAttr = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAttr = m.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement ce : codeAttr.elementList()) { if (ce instanceof InvokeInstruction ins && ins.opcode() == Opcode.INVOKEVIRTUAL) { MemberRefEntry method = ins.method(); diff --git a/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java b/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java index 30d8a579b40..0bc65af8aa1 100644 --- a/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java +++ b/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java @@ -63,21 +63,21 @@ public static void main(String... args) throws Exception { if (methodName.equals("toString") || methodName.equals("hashCode") || methodName.equals("equals") || methodName.equals("main")) { // ignore } else if (methodName.equals("")) { - var paAnnos = mm.findAttribute(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS).orElseThrow().parameterAnnotations(); + var paAnnos = mm.findAttribute(Attributes.runtimeVisibleParameterAnnotations()).orElseThrow().parameterAnnotations(); Assert.check(paAnnos.size() > 0); for (var pa : paAnnos) { Assert.check(pa.size() == 1); Assert.check(Objects.equals(pa.get(0).classSymbol().descriptorString(), "LParameterAnnotation;")); } } else { - var annos = mm.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElseThrow().annotations(); + var annos = mm.findAttribute(Attributes.runtimeVisibleAnnotations()).orElseThrow().annotations(); Assert.check(annos.size() == 1); Assert.check(Objects.equals(annos.get(0).classSymbol().descriptorString(), "LMethodAnnotation;")); } } Assert.check(cm.fields().size() > 0); for (FieldModel fm : cm.fields()) { - var annos = fm.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElseThrow().annotations(); + var annos = fm.findAttribute(Attributes.runtimeVisibleAnnotations()).orElseThrow().annotations(); Assert.check(annos.size() == 1); Assert.check(Objects.equals(annos.getFirst().classSymbol().descriptorString(), "LFieldAnnotation;")); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java index 2f6ac3a4717..6d2aabaee80 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java @@ -197,15 +197,15 @@ void checkFields(ClassModel classFile, int... positions) { // utility methods void findAnnotations(ClassModel cm, AttributedElement m, List annos) { - findAnnotations(cm, m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, annos); - findAnnotations(cm, m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, annos); + findAnnotations(cm, m, Attributes.runtimeVisibleTypeAnnotations(), annos); + findAnnotations(cm, m, Attributes.runtimeInvisibleTypeAnnotations(), annos); } > void findAnnotations(ClassModel cf, AttributedElement m, AttributeMapper attrName, List annos) { Attribute attr = m.findAttribute(attrName).orElse(null); addAnnos(annos, attr); if (m instanceof MethodModel) { - CodeAttribute cattr = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cattr = m.findAttribute(Attributes.code()).orElse(null); if (cattr != null) { attr = cattr.findAttribute(attrName).orElse(null); addAnnos(annos, attr); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/VariablesDeclaredWithVarTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/VariablesDeclaredWithVarTest.java index ffd45ddfca4..7384f4bd5d7 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/VariablesDeclaredWithVarTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/VariablesDeclaredWithVarTest.java @@ -110,15 +110,15 @@ void checkClassFile(final File cfile, int... taPositions) throws Exception { } void findAnnotations(ClassModel cf, MethodModel m, List annos) { - findAnnotations(cf, m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, annos); - findAnnotations(cf, m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, annos); + findAnnotations(cf, m, Attributes.runtimeVisibleTypeAnnotations(), annos); + findAnnotations(cf, m, Attributes.runtimeInvisibleTypeAnnotations(), annos); } > void findAnnotations(ClassModel cf, AttributedElement m, AttributeMapper attrName, List annos) { Attribute attr = m.findAttribute(attrName).orElse(null); addAnnos(annos, attr); if (m instanceof MethodModel) { - CodeAttribute cattr = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cattr = m.findAttribute(Attributes.code()).orElse(null); if (cattr != null) { attr = cattr.findAttribute(attrName).orElse(null); addAnnos(annos, attr); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java index bf2bfd2a370..64c33ed9fd9 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/AnonymousClassTest.java @@ -100,7 +100,7 @@ public static void main(String args[]) throws Exception { static void testAnonymousClassDeclaration() throws Exception { ClassModel cm = ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest$1.class")); RuntimeVisibleTypeAnnotationsAttribute rvta = - cm.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).orElse(null); + cm.findAttribute(Attributes.runtimeVisibleTypeAnnotations()).orElse(null); assert rvta != null; assertEquals( Set.of( @@ -115,7 +115,7 @@ static void testTopLevelMethod() throws Exception { ClassModel cm = ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest.class")); MethodModel method = findMethod(cm, "f"); Set annotations = getRuntimeVisibleTypeAnnotations(method); - CodeAttribute cAttr = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr = method.findAttribute(Attributes.code()).orElse(null); assertEquals( Set.of("@LAnonymousClassTest$TA;(0) NEW, offset=0, location=[INNER_TYPE]"), annotations.stream().map(a -> annotationDebugString(cm, cAttr, a)).collect(toSet())); @@ -126,7 +126,7 @@ static void testInnerClassMethod() throws Exception { ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest$Inner.class")); MethodModel method = findMethod(cm, "g"); Set annotations = getRuntimeVisibleTypeAnnotations(method); - CodeAttribute cAttr = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr = method.findAttribute(Attributes.code()).orElse(null); // The annotation needs two INNER_TYPE type path entries to apply to // AnonymousClassTest$Inner$1. assertEquals( @@ -141,7 +141,7 @@ static void testQualifiedSuperType() throws Exception { ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest.class")); MethodModel method = findMethod(cm, "g"); Set annotations = getRuntimeVisibleTypeAnnotations(method); - CodeAttribute cAttr = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr = method.findAttribute(Attributes.code()).orElse(null); // Only @TA(4) is propagated to the anonymous class declaration. assertEquals( Set.of("@LAnonymousClassTest$TA;(4) NEW, offset=0, location=[INNER_TYPE]"), @@ -152,7 +152,7 @@ static void testQualifiedSuperType() throws Exception { ClassModel cm = ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest$2.class")); RuntimeVisibleTypeAnnotationsAttribute rvta = - cm.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).orElse(null); + cm.findAttribute(Attributes.runtimeVisibleTypeAnnotations()).orElse(null); assert rvta != null; assertEquals( Set.of( @@ -168,14 +168,14 @@ static void testInstanceAndClassInit() throws Exception { ClassModel cm = ClassFile.of().parse(Paths.get(ToolBox.testClasses, "AnonymousClassTest.class")); MethodModel method = findMethod(cm, ""); Set annotations = getRuntimeVisibleTypeAnnotations(method); - CodeAttribute cAttr1 = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr1 = method.findAttribute(Attributes.code()).orElse(null); assertEquals( Set.of("@LAnonymousClassTest$TA;(5) NEW, offset=4, location=[INNER_TYPE]"), annotations.stream().map(a -> annotationDebugString(cm, cAttr1, a)).collect(toSet()) ); method = findMethod(cm, ""); annotations = getRuntimeVisibleTypeAnnotations(method); - CodeAttribute cAttr2 = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr2 = method.findAttribute(Attributes.code()).orElse(null); assertEquals( Set.of("@LAnonymousClassTest$TA;(6) NEW, offset=16, location=[INNER_TYPE]"), annotations.stream().map(a -> annotationDebugString(cm, cAttr2, a)).collect(toSet()) ); @@ -184,14 +184,14 @@ static void testInstanceAndClassInit() throws Exception { // Returns the Method's RuntimeVisibleTypeAnnotations, and asserts that there are no RVTIs // erroneously associated with the Method instead of its Code attribute. private static Set getRuntimeVisibleTypeAnnotations(MethodModel method) { - if (method.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).orElse(null) != null) { + if (method.findAttribute(Attributes.runtimeVisibleTypeAnnotations()).orElse(null) != null) { throw new AssertionError( "expected no RuntimeVisibleTypeAnnotations attribute on enclosing method"); } - CodeAttribute code = method.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = method.findAttribute(Attributes.code()).orElse(null); assert code != null; RuntimeVisibleTypeAnnotationsAttribute rvta = - code.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).orElse(null); + code.findAttribute(Attributes.runtimeVisibleTypeAnnotations()).orElse(null); assert rvta != null; return new HashSet<>(rvta.annotations()); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java index 4926e15b258..11abffa8c91 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/ClassfileTestHelper.java @@ -88,10 +88,10 @@ void test(MethodModel mm ) { // 'local' determines whether to look for annotations in code attribute or not. void test(AttributedElement m, Boolean local) { - test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, local); - test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, local); - test(m, Attributes.RUNTIME_VISIBLE_ANNOTATIONS, local); - test(m, Attributes.RUNTIME_INVISIBLE_ANNOTATIONS, local); + test(m, Attributes.runtimeVisibleTypeAnnotations(), local); + test(m, Attributes.runtimeInvisibleTypeAnnotations(), local); + test(m, Attributes.runtimeVisibleAnnotations(), local); + test(m, Attributes.runtimeInvisibleAnnotations(), local); } // Test the result of MethodModel.findAttribute according to expectations @@ -164,7 +164,7 @@ > Attribute extractAnnotation(AttributedElement m, Att CodeAttribute cAttr; Attribute attr = null; if (local) { - cAttr = m.findAttribute(Attributes.CODE).orElse(null); + cAttr = m.findAttribute(Attributes.code()).orElse(null); if (cAttr != null) { attr = cAttr.findAttribute(annName).orElse(null); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java index 13082ba9dad..ffab642c1d5 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/NoTargetAnnotations.java @@ -71,8 +71,8 @@ ClassModel getClassFile(String name) throws IOException { void testDeclaration(AttributedElement m) { - testDecl(m, Attributes.RUNTIME_VISIBLE_ANNOTATIONS); - testDecl(m, Attributes.RUNTIME_INVISIBLE_ANNOTATIONS); + testDecl(m, Attributes.runtimeVisibleAnnotations()); + testDecl(m, Attributes.runtimeInvisibleAnnotations()); } // test the result of AttributedElement.findAttribute according to expectations diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestAnonInnerClasses.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestAnonInnerClasses.java index 59ed653927b..fc232d06b64 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestAnonInnerClasses.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestAnonInnerClasses.java @@ -63,10 +63,10 @@ public class TestAnonInnerClasses extends ClassfileTestHelper { File testSrc = new File(System.getProperty("test.src")); AttributeMapper [] AnnoAttributes = new AttributeMapper[]{ - Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, - Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, - Attributes.RUNTIME_VISIBLE_ANNOTATIONS, - Attributes.RUNTIME_INVISIBLE_ANNOTATIONS + Attributes.runtimeVisibleTypeAnnotations(), + Attributes.runtimeInvisibleTypeAnnotations(), + Attributes.runtimeVisibleAnnotations(), + Attributes.runtimeInvisibleAnnotations() }; // template for source files @@ -175,7 +175,7 @@ > void test(AttributedElement m) { ((MethodModel) m).methodName().stringValue() : ((FieldModel) m).fieldName().stringValue(); attr = m.findAttribute(AnnoType).orElse(null); //fetch index annotations from code attribute. - CAttr = m.findAttribute(Attributes.CODE).orElse(null); + CAttr = m.findAttribute(Attributes.code()).orElse(null); if (CAttr != null) { cattr = CAttr.findAttribute(AnnoType).orElse(null); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java index 741747a9b4c..048c1836664 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TestNewCastArray.java @@ -88,7 +88,7 @@ > void test(String clazz, AttributedElement m, AttributeM memberName = mm.methodName().stringValue(); if(codeattr) { //fetch index of and code attribute and annotations from code attribute. - cAttr = mm.findAttribute(Attributes.CODE).orElse(null); + cAttr = mm.findAttribute(Attributes.code()).orElse(null); if(cAttr != null) { attr = cAttr.findAttribute(name).orElse(null); } @@ -99,7 +99,7 @@ > void test(String clazz, AttributedElement m, AttributeM case FieldModel fm -> { memberName = fm.fieldName().stringValue(); if(codeattr) { - cAttr = fm.findAttribute(Attributes.CODE).orElse(null); + cAttr = fm.findAttribute(Attributes.code()).orElse(null); if(cAttr != null) { attr = cAttr.findAttribute(name).orElse(null); } @@ -207,14 +207,14 @@ public void run() { assert cm != null; if(clazz.startsWith("Test1")) { for (FieldModel fm: cm.fields()) - test(clazz, fm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, false); + test(clazz, fm, Attributes.runtimeVisibleTypeAnnotations(), false); for (MethodModel mm: cm.methods()) - test(clazz, mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, false); + test(clazz, mm, Attributes.runtimeVisibleTypeAnnotations(), false); } else { for (FieldModel fm: cm.fields()) - test(clazz, fm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, true); + test(clazz, fm, Attributes.runtimeVisibleTypeAnnotations(), true); for (MethodModel mm: cm.methods()) - test(clazz, mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, true); + test(clazz, mm, Attributes.runtimeVisibleTypeAnnotations(), true); } } report(); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TypeAnnotationPropagationTest.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TypeAnnotationPropagationTest.java index ae92d7aae04..9f7873bb2c0 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TypeAnnotationPropagationTest.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/TypeAnnotationPropagationTest.java @@ -58,9 +58,9 @@ public void run() throws Exception { } assert f != null; - CodeAttribute cattr = f.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cattr = f.findAttribute(Attributes.code()).orElse(null); assert cattr != null; - RuntimeVisibleTypeAnnotationsAttribute attr = cattr.findAttribute(Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS).orElse(null); + RuntimeVisibleTypeAnnotationsAttribute attr = cattr.findAttribute(Attributes.runtimeVisibleTypeAnnotations()).orElse(null); assert attr != null; List annosPosition = ((TypeAnnotation.LocalVarTarget) attr.annotations().get(0).targetInfo()).table(); diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java b/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java index 7e35a081de7..e2e69a01a49 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/referenceinfos/ReferenceInfoUtil.java @@ -37,8 +37,8 @@ public static List extendedAnnotationsOf(ClassModel cm) { /////////////////// Extract type annotations ////////////////// private static void findAnnotations(ClassModel cm, List annos) { - findAnnotations(cm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, annos); - findAnnotations(cm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, annos); + findAnnotations(cm, Attributes.runtimeVisibleTypeAnnotations(), annos); + findAnnotations(cm, Attributes.runtimeInvisibleTypeAnnotations(), annos); for (FieldModel f : cm.fields()) { findAnnotations(f, annos); @@ -49,8 +49,8 @@ private static void findAnnotations(ClassModel cm, List annos) { } private static void findAnnotations(AttributedElement ae, List annos) { - findAnnotations(ae, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS, annos); - findAnnotations(ae, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS, annos); + findAnnotations(ae, Attributes.runtimeVisibleTypeAnnotations(), annos); + findAnnotations(ae, Attributes.runtimeInvisibleTypeAnnotations(), annos); } // test the result of Attributes.getIndex according to expectations @@ -78,7 +78,7 @@ private static > void findAnnotations(AttributedElement m } else throw new AssertionError(); } if (m instanceof MethodModel mm) { - CodeAttribute cAttr = mm.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute cAttr = mm.findAttribute(Attributes.code()).orElse(null); if (cAttr != null) { Attribute attr2 = cAttr.findAttribute(attrName).orElse(null);; if (attr2 != null) { diff --git a/test/langtools/tools/javac/cast/intersection/DuplicatedCheckcastTest.java b/test/langtools/tools/javac/cast/intersection/DuplicatedCheckcastTest.java index e8e947d408c..544314832e8 100644 --- a/test/langtools/tools/javac/cast/intersection/DuplicatedCheckcastTest.java +++ b/test/langtools/tools/javac/cast/intersection/DuplicatedCheckcastTest.java @@ -100,7 +100,7 @@ private void duplicateCheckCastHelper(String source, String expected1, String ex ArrayList checkCastList = new ArrayList<>(); for (MethodModel method : cf.methods()) { if (method.methodName().equalsString("test")) { - CodeAttribute code_attribute = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = method.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement ce : code_attribute.elementList()) { if (ce instanceof Instruction instruction && Opcode.CHECKCAST == instruction.opcode()) { checkCastList.add(instruction); diff --git a/test/langtools/tools/javac/classfiles/InnerClasses/SyntheticClasses.java b/test/langtools/tools/javac/classfiles/InnerClasses/SyntheticClasses.java index bab02ade067..eca1b840b3a 100644 --- a/test/langtools/tools/javac/classfiles/InnerClasses/SyntheticClasses.java +++ b/test/langtools/tools/javac/classfiles/InnerClasses/SyntheticClasses.java @@ -47,14 +47,14 @@ private void run() throws IOException { for (File classFile : Objects.requireNonNull(testClasses.listFiles(f -> f.getName().endsWith(".class")))) { ClassModel cf = ClassFile.of().parse(classFile.toPath()); if (cf.thisClass().asInternalName().matches(".*\\$[0-9]+")) { - EnclosingMethodAttribute encl = cf.findAttribute(Attributes.ENCLOSING_METHOD).orElse(null); + EnclosingMethodAttribute encl = cf.findAttribute(Attributes.enclosingMethod()).orElse(null); if (encl != null) { if (encl.enclosingMethodName().isPresent()) throw new IllegalStateException("Invalid EnclosingMethod.method: " + encl.enclosingMethodName().get().stringValue() + "."); } } - InnerClassesAttribute attr = cf.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute attr = cf.findAttribute(Attributes.innerClasses()).orElse(null); if (attr != null) { for (InnerClassInfo info : attr.classes()) { if (cf.majorVersion() < 51) diff --git a/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultTest.java b/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultTest.java index d099c4940f9..d9a3320ecc2 100644 --- a/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/AnnotationDefault/AnnotationDefaultTest.java @@ -77,7 +77,7 @@ private void test(String template, Map replacements, boolean has String methodName = method.methodName().stringValue(); printf("Testing method : %s\n", methodName); AnnotationDefaultAttribute attr = - method.findAttribute(Attributes.ANNOTATION_DEFAULT).orElse(null); + method.findAttribute(Attributes.annotationDefault()).orElse(null); if (hasDefault && !checkNotNull(attr, "Attribute is not null") || !hasDefault && checkNull(attr, "Attribute is null")) { diff --git a/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java b/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java index d34d3a7db05..b555014bebe 100644 --- a/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/EnclosingMethod/EnclosingMethodTest.java @@ -163,7 +163,7 @@ private void testEnclosingMethodAttribute() { checkEquals(countEnclosingMethodAttributes(classFile), 1l, "number of the EnclosingMethod attribute in the class is one : " + clazz); - EnclosingMethodAttribute attr = classFile.findAttribute(Attributes.ENCLOSING_METHOD).orElse(null); + EnclosingMethodAttribute attr = classFile.findAttribute(Attributes.enclosingMethod()).orElse(null); if (!checkNotNull(attr, "the EnclosingMethod attribute is not null : " + className)) { // stop checking, attr is null. test case failed diff --git a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java index f9227dde4df..be4a5aaea91 100644 --- a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java @@ -72,15 +72,15 @@ protected void test(List testCases) throws Exception { classFile = ClassFile.of().parse(input.readAllBytes()); } for (MethodModel m : classFile.methods()) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElse(null); assert code_attribute != null; assertEquals( - countAttributes(Attributes.LINE_NUMBER_TABLE, code_attribute), + countAttributes(Attributes.lineNumberTable(), code_attribute), 1, "Can be more than one LNT attribute, but javac should generate only one."); - LineNumberTableAttribute tableAttribute = code_attribute.findAttribute(Attributes.LINE_NUMBER_TABLE).orElse(null); + LineNumberTableAttribute tableAttribute = code_attribute.findAttribute(Attributes.lineNumberTable()).orElse(null); assert tableAttribute != null; checkAttribute(testCase, tableAttribute, code_attribute.codeLength()); Set methodCoveredLines = diff --git a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java index dade8e98430..934a0ef09e7 100644 --- a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java +++ b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java @@ -24,10 +24,10 @@ public static void main(String[] args) throws IOException { Set expectedLineNumbers = new HashSet<>(Arrays.asList(49, 50, 47, 48)); for (MethodModel m : someTestIn.methods()) { if (m.methodName().equalsString("method")) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElse(null); assert code_attribute != null; for (Attribute at : code_attribute.attributes()) { - if (Attributes.LINE_NUMBER_TABLE.equals(at)) { + if (Attributes.lineNumberTable().equals(at)) { assert at instanceof LineNumberTableAttribute; LineNumberTableAttribute att = (LineNumberTableAttribute) at; Set actualLinesNumbers = Arrays.stream(att.lineNumbers().toArray(new LineNumberInfo[0])) diff --git a/test/langtools/tools/javac/classfiles/attributes/LocalVariableTable/LocalVariableTestBase.java b/test/langtools/tools/javac/classfiles/attributes/LocalVariableTable/LocalVariableTestBase.java index 9d2e19c86ba..7bda1500b3e 100644 --- a/test/langtools/tools/javac/classfiles/attributes/LocalVariableTable/LocalVariableTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/LocalVariableTable/LocalVariableTestBase.java @@ -104,7 +104,7 @@ public void test(String methodName, Map expectedLocals2Types, Ma String mName = m.methodName().stringValue(); if (methodName.equals(mName)) { System.out.println("Testing local variable table in method " + mName); - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElse(null); assert code_attribute != null; List variableTables = getVariableTables(code_attribute); generalLocalVariableTableCheck(variableTables); diff --git a/test/langtools/tools/javac/classfiles/attributes/Module/ModuleTestBase.java b/test/langtools/tools/javac/classfiles/attributes/Module/ModuleTestBase.java index 8f7e5c04250..490e585e06a 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Module/ModuleTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/Module/ModuleTestBase.java @@ -70,7 +70,7 @@ protected void run() throws Exception { protected void testModuleAttribute(Path modulePath, ModuleDescriptor moduleDescriptor) throws Exception { ClassModel classFile = ClassFile.of().parse(modulePath.resolve("module-info.class")); - ModuleAttribute moduleAttribute = classFile.findAttribute(Attributes.MODULE).orElse(null); + ModuleAttribute moduleAttribute = classFile.findAttribute(Attributes.module()).orElse(null); assert moduleAttribute != null; testModuleName(moduleDescriptor, moduleAttribute); testModuleFlags(moduleDescriptor, moduleAttribute); diff --git a/test/langtools/tools/javac/classfiles/attributes/Signature/Driver.java b/test/langtools/tools/javac/classfiles/attributes/Signature/Driver.java index 4e565cde423..72f7d2a6b9b 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Signature/Driver.java +++ b/test/langtools/tools/javac/classfiles/attributes/Signature/Driver.java @@ -134,7 +134,7 @@ public void test() throws TestFailedException { // test class signature testAttribute( className, - () -> classFile.findAttribute(Attributes.SIGNATURE).orElse(null), + () -> classFile.findAttribute(Attributes.signature()).orElse(null), getClassExpectedSignature(className, clazz).get(className)); testFields(getExpectedFieldSignatures(clazz), classFile); @@ -173,7 +173,7 @@ private void testMethods(Map expectedSignatures, Clas } testAttribute( methodName, - () -> method.findAttribute(Attributes.SIGNATURE).orElse(null), + () -> method.findAttribute(Attributes.signature()).orElse(null), expectedSignatures.get(methodName)); foundMethods.add(methodName); } @@ -204,7 +204,7 @@ private void testFields(Map expectedSignatures, Class printf("Testing field %s\n", fieldName); testAttribute( fieldName, - () -> field.findAttribute(Attributes.SIGNATURE).orElse(null), + () -> field.findAttribute(Attributes.signature()).orElse(null), expectedSignatures.get(fieldName)); foundFields.add(fieldName); } diff --git a/test/langtools/tools/javac/classfiles/attributes/SourceFile/NoSourceFileAttribute.java b/test/langtools/tools/javac/classfiles/attributes/SourceFile/NoSourceFileAttribute.java index af9e603c964..d4a4972f135 100644 --- a/test/langtools/tools/javac/classfiles/attributes/SourceFile/NoSourceFileAttribute.java +++ b/test/langtools/tools/javac/classfiles/attributes/SourceFile/NoSourceFileAttribute.java @@ -48,7 +48,7 @@ public static void main(String[] args) throws Exception { public void test() throws IOException { assertNull( - ClassFile.of().parse(getClassFile(NoSourceFileAttribute.class).toPath()).findAttribute(Attributes.SOURCE_FILE).orElse(null), + ClassFile.of().parse(getClassFile(NoSourceFileAttribute.class).toPath()).findAttribute(Attributes.sourceFile()).orElse(null), "Classfile should have no SourceFile attribute when compiled without debug information."); } } diff --git a/test/langtools/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java b/test/langtools/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java index f827873588e..52d53f9dce4 100644 --- a/test/langtools/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/SourceFile/SourceFileTestBase.java @@ -108,7 +108,7 @@ private void assertAttributePresent(ClassModel classFile, String fileName) throw SourceFileAttribute attribute = sourceFileAttributes.get(0); - assertEquals(attribute.attributeName(), Attributes.SOURCE_FILE.name(), "Incorrect attribute name"); + assertEquals(attribute.attributeName(), Attributes.sourceFile().name(), "Incorrect attribute name"); assertEquals(attribute.sourceFile().stringValue(), fileName, "Incorrect source file name"); assertEquals(((BoundAttribute)attribute).payloadLen(), 2, "Incorrect attribute length"); diff --git a/test/langtools/tools/javac/classfiles/attributes/Synthetic/SyntheticTestDriver.java b/test/langtools/tools/javac/classfiles/attributes/Synthetic/SyntheticTestDriver.java index 406df68a7fe..4db2585355e 100644 --- a/test/langtools/tools/javac/classfiles/attributes/Synthetic/SyntheticTestDriver.java +++ b/test/langtools/tools/javac/classfiles/attributes/Synthetic/SyntheticTestDriver.java @@ -118,7 +118,7 @@ public void test(int expectedNumberOfSyntheticClasses) throws TestFailedExceptio foundClasses.add(className); if (testAttribute( classFile, - () -> classFile.findAttribute(Attributes.SYNTHETIC).orElse(null), + () -> classFile.findAttribute(Attributes.synthetic()).orElse(null), classFile.flags()::flags, expectedClasses.keySet(), className, @@ -136,7 +136,7 @@ public void test(int expectedNumberOfSyntheticClasses) throws TestFailedExceptio foundMethods.add(methodName); if (testAttribute( classFile, - () -> method.findAttribute(Attributes.SYNTHETIC).orElse(null), + () -> method.findAttribute(Attributes.synthetic()).orElse(null), method.flags()::flags, expectedMethods, methodName, @@ -162,7 +162,7 @@ public void test(int expectedNumberOfSyntheticClasses) throws TestFailedExceptio foundFields.add(fieldName); if (testAttribute( classFile, - () -> field.findAttribute(Attributes.SYNTHETIC).orElse(null), + () -> field.findAttribute(Attributes.synthetic()).orElse(null), field.flags()::flags, expectedFields, fieldName, diff --git a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsTestBase.java b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsTestBase.java index a36a84e5e8f..970628be575 100644 --- a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeAnnotationsTestBase.java @@ -96,11 +96,11 @@ private void testAttributes( Map actualInvisible = collectAnnotations( member, attributedElement, - Attributes.RUNTIME_INVISIBLE_ANNOTATIONS); + Attributes.runtimeInvisibleAnnotations()); Map actualVisible = collectAnnotations( member, attributedElement, - Attributes.RUNTIME_VISIBLE_ANNOTATIONS); + Attributes.runtimeVisibleAnnotations()); checkEquals(actualInvisible.keySet(), member.getRuntimeInvisibleAnnotations(), "RuntimeInvisibleAnnotations"); diff --git a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java index baf3a599095..ef9bd07cd69 100644 --- a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsForLambdaTest.java @@ -104,10 +104,10 @@ public void test() throws TestFailedException { protected void testAttributes( TestCase.TestMethodInfo testMethod, MethodModel method) { - RuntimeInvisibleParameterAnnotationsAttribute invAttr = method.findAttribute(Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS).orElse(null); - checkNull(invAttr, String.format("%s should be null", Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS)); - RuntimeVisibleParameterAnnotationsAttribute vAttr = method.findAttribute(Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS).orElse(null); - checkNull(vAttr, String.format("%s should be null", Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS)); + RuntimeInvisibleParameterAnnotationsAttribute invAttr = method.findAttribute(Attributes.runtimeInvisibleParameterAnnotations()).orElse(null); + checkNull(invAttr, String.format("%s should be null", Attributes.runtimeInvisibleParameterAnnotations())); + RuntimeVisibleParameterAnnotationsAttribute vAttr = method.findAttribute(Attributes.runtimeVisibleParameterAnnotations()).orElse(null); + checkNull(vAttr, String.format("%s should be null", Attributes.runtimeVisibleParameterAnnotations())); } public String generateLambdaSource(TestCase.TestMethodInfo method) { diff --git a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTestBase.java b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTestBase.java index 04b1ba2dd54..b8c90faf52b 100644 --- a/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/annotations/RuntimeParameterAnnotationsTestBase.java @@ -67,12 +67,12 @@ protected void testAttributes( classFile, testMethod, method, - Attributes.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS); + Attributes.runtimeInvisibleParameterAnnotations()); List> actualVisible = collectAnnotations( classFile, testMethod, method, - Attributes.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS); + Attributes.runtimeVisibleParameterAnnotations()); List parameters = testMethod.parameters; for (int i = 0; i < parameters.size(); ++i) { diff --git a/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedPackageTest.java b/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedPackageTest.java index 3f3a5f2a984..b3e7339b240 100644 --- a/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedPackageTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedPackageTest.java @@ -84,7 +84,7 @@ private void test(String package_info, String src) { new String[]{"package-info.java", package_info}, new String[]{"notDeprecated.java", src}) .getClasses().get(CLASS_NAME)); - DeprecatedAttribute attr = cm.findAttribute(Attributes.DEPRECATED).orElse(null); + DeprecatedAttribute attr = cm.findAttribute(Attributes.deprecated()).orElse(null); checkNull(attr, "Class can not have deprecated attribute : " + CLASS_NAME); } catch (Exception e) { addFailure(e); diff --git a/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedTest.java b/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedTest.java index ebe77e69056..425760ea137 100644 --- a/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/deprecated/DeprecatedTest.java @@ -243,7 +243,7 @@ private void test(String src) { .findFirst().orElse(null); echo("Testing outer class : " + outerClassName); ClassModel cf = readClassFile(classes.get(outerClassName)); - DeprecatedAttribute attr = cf.findAttribute(Attributes.DEPRECATED).orElse(null); + DeprecatedAttribute attr = cf.findAttribute(Attributes.deprecated()).orElse(null); testAttribute(outerClassName, attr, cf); testInnerClasses(cf, classes); testMethods(cf); @@ -255,13 +255,13 @@ private void test(String src) { private void testInnerClasses(ClassModel cf, Map classes) throws IOException { - InnerClassesAttribute innerAttr = cf.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute innerAttr = cf.findAttribute(Attributes.innerClasses()).orElse(null); assert innerAttr != null; for (InnerClassInfo innerClass : innerAttr.classes()) { String innerClassName = innerClass.innerClass().name().stringValue(); echo("Testing inner class : " + innerClassName); ClassModel innerCf = readClassFile(classes.get(innerClassName)); - DeprecatedAttribute attr = innerCf.findAttribute(Attributes.DEPRECATED).orElse(null); + DeprecatedAttribute attr = innerCf.findAttribute(Attributes.deprecated()).orElse(null); assert innerClass.innerName().isPresent(); String innerClassSimpleName = innerClass.innerName().get().stringValue(); testAttribute(innerClassSimpleName, attr, innerCf); @@ -276,7 +276,7 @@ private void testMethods(ClassModel cf) { for (MethodModel m : cf.methods()) { String methodName = m.methodName().stringValue(); echo("Testing method : " + methodName); - DeprecatedAttribute attr = m.findAttribute(Attributes.DEPRECATED).orElse(null); + DeprecatedAttribute attr = m.findAttribute(Attributes.deprecated()).orElse(null); testAttribute(methodName, attr, cf); } } @@ -285,7 +285,7 @@ private void testFields(ClassModel cm) { for (FieldModel f : cm.fields()) { String fieldName = f.fieldName().stringValue(); echo("Testing field : " + fieldName); - DeprecatedAttribute attr = f.findAttribute(Attributes.DEPRECATED).orElse(null); + DeprecatedAttribute attr = f.findAttribute(Attributes.deprecated()).orElse(null); testAttribute(fieldName, attr, cm); } } diff --git a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesHierarchyTest.java b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesHierarchyTest.java index eb7e6f2e2df..124f46acded 100644 --- a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesHierarchyTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesHierarchyTest.java @@ -98,7 +98,7 @@ private void test() throws TestFailedException { continue; } ClassModel cf = readClassFile(currentClassName); - InnerClassesAttribute attr = cf.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute attr = cf.findAttribute(Attributes.innerClasses()).orElse(null); checkNotNull(attr, "Class should not contain " + "inner classes attribute : " + currentClassName); checkTrue(innerClasses.containsKey(currentClassName), diff --git a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesIndexTest.java b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesIndexTest.java index 826365a8011..96f2efc6ea6 100644 --- a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesIndexTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesIndexTest.java @@ -69,7 +69,7 @@ public void test() throws TestFailedException { try { addTestCase("Source is InnerClassesIndexTest.java"); ClassModel classFile = readClassFile(InnerClassesIndexTest.class); - InnerClassesAttribute attr = classFile.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute attr = classFile.findAttribute(Attributes.innerClasses()).orElse(null); Set foundClasses = new HashSet<>(); assert attr != null; diff --git a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesTestBase.java b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesTestBase.java index ca818817b6d..26972de3544 100644 --- a/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesTestBase.java +++ b/test/langtools/tools/javac/classfiles/attributes/innerclasses/InnerClassesTestBase.java @@ -195,7 +195,7 @@ private void test(String classToTest, TestCase test, String...skipClasses) { Map> class2Flags = test.getFlags(); ClassModel cm = readClassFile(compile(getCompileOptions(), test.getSource()) .getClasses().get(classToTest)); - InnerClassesAttribute innerClasses = cm.findAttribute(Attributes.INNER_CLASSES).orElse(null); + InnerClassesAttribute innerClasses = cm.findAttribute(Attributes.innerClasses()).orElse(null); int count = 0; for (Attribute a : cm.attributes()) { if (a instanceof InnerClassesAttribute) { diff --git a/test/langtools/tools/javac/classfiles/attributes/innerclasses/NoInnerClassesTest.java b/test/langtools/tools/javac/classfiles/attributes/innerclasses/NoInnerClassesTest.java index 540bd09a18f..35d65208bc5 100644 --- a/test/langtools/tools/javac/classfiles/attributes/innerclasses/NoInnerClassesTest.java +++ b/test/langtools/tools/javac/classfiles/attributes/innerclasses/NoInnerClassesTest.java @@ -47,6 +47,6 @@ public static void main(String[] args) throws IOException { public void test() throws IOException { ClassModel classModel = readClassFile("NoInnerClassesTest"); - assertNull(classModel.findAttribute(Attributes.INNER_CLASSES).orElse(null), "Found inner class attribute"); + assertNull(classModel.findAttribute(Attributes.innerClasses()).orElse(null), "Found inner class attribute"); } } diff --git a/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java b/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java index 8711118b8fd..8b5e4e7b695 100644 --- a/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java +++ b/test/langtools/tools/javac/classwriter/IndyCorrectInvocationName.java @@ -165,12 +165,12 @@ public static CallSite bootstrap(Lookup lookup, String name, MethodType type) th Path testClass = classes.resolve("Test.class"); ClassModel cf = ClassFile.of().parse(testClass); - BootstrapMethodsAttribute bootAttr = cf.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bootAttr = cf.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); if (bootAttr.bootstrapMethodsSize() != 1) { throw new AssertionError("Incorrect number of bootstrap methods: " + bootAttr.bootstrapMethodsSize()); } - CodeAttribute codeAttr = cf.methods().get(1).findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAttr = cf.methods().get(1).findAttribute(Attributes.code()).orElseThrow(); Set seenBootstraps = new HashSet<>(); Set seenNameAndTypes = new HashSet<>(); Set seenNames = new HashSet<>(); diff --git a/test/langtools/tools/javac/code/CharImmediateValue.java b/test/langtools/tools/javac/code/CharImmediateValue.java index 24f60c5d539..44e2744b74e 100644 --- a/test/langtools/tools/javac/code/CharImmediateValue.java +++ b/test/langtools/tools/javac/code/CharImmediateValue.java @@ -133,7 +133,7 @@ public static String run() { Path testClass = classes.resolve("Test.class"); ClassModel cf = ClassFile.of().parse(testClass); - CodeAttribute codeAttr = cf.methods().get(1).findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAttr = cf.methods().get(1).findAttribute(Attributes.code()).orElseThrow(); boolean seenCast = false; for (CodeElement i : codeAttr.elementList()) { if (i instanceof Instruction ins && ins.opcode() == Opcode.I2C) { diff --git a/test/langtools/tools/javac/defaultMethods/TestDefaultBody.java b/test/langtools/tools/javac/defaultMethods/TestDefaultBody.java index 5cad9ed6293..ec4e8b7b558 100644 --- a/test/langtools/tools/javac/defaultMethods/TestDefaultBody.java +++ b/test/langtools/tools/javac/defaultMethods/TestDefaultBody.java @@ -67,7 +67,7 @@ void verifyDefaultBody(File f) { MethodModel testMethod = null; CodeAttribute codeAttr = null; for (MethodModel m : cf.methods()) { - codeAttr = m.findAttribute(Attributes.CODE).orElse(null); + codeAttr = m.findAttribute(Attributes.code()).orElse(null); String mname = m.methodName().stringValue(); if (mname.equals(TEST_METHOD_NAME)) { testMethod = m; diff --git a/test/langtools/tools/javac/defaultMethods/super/TestDirectSuperInterfaceInvoke.java b/test/langtools/tools/javac/defaultMethods/super/TestDirectSuperInterfaceInvoke.java index 5e171b3cdf0..8be378eaf7b 100644 --- a/test/langtools/tools/javac/defaultMethods/super/TestDirectSuperInterfaceInvoke.java +++ b/test/langtools/tools/javac/defaultMethods/super/TestDirectSuperInterfaceInvoke.java @@ -86,7 +86,7 @@ void verifyDefaultBody(String classFile) { try { final ClassModel cf = ClassFile.of().parse(file.toPath()); for (MethodModel m : cf.methods()) { - CodeAttribute codeAttr = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAttr = m.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement ce : codeAttr.elementList()) { if (ce instanceof InvokeInstruction instr && instr.opcode() == Opcode.INVOKESPECIAL) { MemberRefEntry ref = instr.method(); diff --git a/test/langtools/tools/javac/expression/_super/NonDirectSuper/NonDirectSuper.java b/test/langtools/tools/javac/expression/_super/NonDirectSuper/NonDirectSuper.java index 05942c56722..e4879302058 100644 --- a/test/langtools/tools/javac/expression/_super/NonDirectSuper/NonDirectSuper.java +++ b/test/langtools/tools/javac/expression/_super/NonDirectSuper/NonDirectSuper.java @@ -61,7 +61,7 @@ void verifyInvokeSpecialRefToObject(File clazz) { try { final ClassModel cf = ClassFile.of().parse(clazz.toPath()); for (MethodModel m : cf.methods()) { - CodeAttribute codeAttr = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute codeAttr = m.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement ce : codeAttr.elementList()) { if (ce instanceof InvokeInstruction instr && (instr.opcode() == Opcode.INVOKESPECIAL || instr.opcode() == Opcode.INVOKEVIRTUAL)) { diff --git a/test/langtools/tools/javac/file/SymLinkTest.java b/test/langtools/tools/javac/file/SymLinkTest.java index f9dea1d8bc3..45405aac2ee 100644 --- a/test/langtools/tools/javac/file/SymLinkTest.java +++ b/test/langtools/tools/javac/file/SymLinkTest.java @@ -95,7 +95,7 @@ void test(Path base, String name) throws Exception{ .writeAll(); ClassModel cf = ClassFile.of().parse(classes.resolve("HelloWorld.class")); - SourceFileAttribute sf = cf.findAttribute(Attributes.SOURCE_FILE).orElseThrow(); + SourceFileAttribute sf = cf.findAttribute(Attributes.sourceFile()).orElseThrow(); String sourceFile = sf.sourceFile().stringValue(); if (!"HelloWorld.java".equals(sourceFile)) { diff --git a/test/langtools/tools/javac/flow/LVTHarness.java b/test/langtools/tools/javac/flow/LVTHarness.java index 6e8afef9903..cd4374d93e2 100644 --- a/test/langtools/tools/javac/flow/LVTHarness.java +++ b/test/langtools/tools/javac/flow/LVTHarness.java @@ -138,8 +138,8 @@ void checkClassFile(File file) throws IOException { } void checkMethod(MethodModel method, AliveRanges ranges) { - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); - LocalVariableTableAttribute lvt = code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).orElseThrow(); + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); + LocalVariableTableAttribute lvt = code.findAttribute(Attributes.localVariableTable()).orElseThrow(); List infoFromRanges = convertToStringList(ranges); List infoFromLVT = convertToStringList(lvt); diff --git a/test/langtools/tools/javac/lambda/ByteCodeTest.java b/test/langtools/tools/javac/lambda/ByteCodeTest.java index 7a5943935be..df5c8df1ff9 100644 --- a/test/langtools/tools/javac/lambda/ByteCodeTest.java +++ b/test/langtools/tools/javac/lambda/ByteCodeTest.java @@ -423,7 +423,7 @@ public String visit(PoolEntry c, int index) { } private Map readBSM() { - BootstrapMethodsAttribute bsmAttr = cf.findAttribute(Attributes.BOOTSTRAP_METHODS).orElse(null); + BootstrapMethodsAttribute bsmAttr = cf.findAttribute(Attributes.bootstrapMethods()).orElse(null); if (bsmAttr != null) { Map out = new HashMap<>(bsmAttr.bootstrapMethodsSize()); diff --git a/test/langtools/tools/javac/lambda/LocalVariableTable.java b/test/langtools/tools/javac/lambda/LocalVariableTable.java index 3a636751199..e78fed1288a 100644 --- a/test/langtools/tools/javac/lambda/LocalVariableTable.java +++ b/test/langtools/tools/javac/lambda/LocalVariableTable.java @@ -90,13 +90,13 @@ void check(Class c) throws Exception { return; } - CodeAttribute code = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = m.findAttribute(Attributes.code()).orElse(null); if (code == null) { error("Code attribute not found"); return; } - LocalVariableTableAttribute lvt = code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).orElse(null); + LocalVariableTableAttribute lvt = code.findAttribute(Attributes.localVariableTable()).orElse(null); if (lvt == null) { error("LocalVariableTable attribute not found"); return; diff --git a/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java b/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java index c8b405b706a..1220bf4dfa4 100644 --- a/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java +++ b/test/langtools/tools/javac/lambda/TestBootstrapMethodsCount.java @@ -112,7 +112,7 @@ void verifyBytecode() { File compiledTest = new File("Test.class"); try { ClassModel cf = ClassFile.of().parse(compiledTest.toPath()); - BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); int length = bsm_attr.bootstrapMethodsSize(); if (length != 1) { throw new Error("Bad number of method specifiers " + diff --git a/test/langtools/tools/javac/lambda/TestInvokeDynamic.java b/test/langtools/tools/javac/lambda/TestInvokeDynamic.java index 56bb63fc2c9..05c304cdd31 100644 --- a/test/langtools/tools/javac/lambda/TestInvokeDynamic.java +++ b/test/langtools/tools/javac/lambda/TestInvokeDynamic.java @@ -265,7 +265,7 @@ void verifyBytecode(Result> res) { fail("Test method not found"); return; } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { fail("Code attribute for test() method not found"); return; @@ -289,7 +289,7 @@ void verifyBytecode(Result> res) { } BootstrapMethodsAttribute bsm_attr = cm - .findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + .findAttribute(Attributes.bootstrapMethods()).orElseThrow(); if (bsm_attr.bootstrapMethodsSize() != 1) { fail("Bad number of method specifiers " + "in BootstrapMethods attribute"); @@ -337,7 +337,7 @@ void verifyBytecode(Result> res) { return; } - LineNumberTableAttribute lnt = ea.findAttribute(Attributes.LINE_NUMBER_TABLE).orElse(null); + LineNumberTableAttribute lnt = ea.findAttribute(Attributes.lineNumberTable()).orElse(null); if (lnt == null) { fail("No LineNumberTable attribute"); diff --git a/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecode.java b/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecode.java index dd637489361..c19c848ee68 100644 --- a/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecode.java +++ b/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecode.java @@ -218,7 +218,7 @@ void verifyBytecode(Result> res) { fail("Test method not found"); return; } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { fail("Code attribute for test() method not found"); return; @@ -243,7 +243,7 @@ void verifyBytecode(Result> res) { return; } - BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bsm_attr = cf.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); if (bsm_attr.bootstrapMethodsSize() != 1) { fail("Bad number of method specifiers " + "in BootstrapMethods attribute"); diff --git a/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java b/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java index 2ac3e322970..326de3168b3 100644 --- a/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java +++ b/test/langtools/tools/javac/lambda/bytecode/TestLambdaBytecodeTargetRelease14.java @@ -220,7 +220,7 @@ void verifyBytecode(Result> res) { fail("Test method not found"); return; } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { fail("Code attribute for test() method not found"); return; @@ -245,7 +245,7 @@ void verifyBytecode(Result> res) { return; } - BootstrapMethodsAttribute bsm_attr = cm.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bsm_attr = cm.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); if (bsm_attr.bootstrapMethodsSize() != 1) { fail("Bad number of method specifiers " + "in BootstrapMethods attribute"); diff --git a/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java b/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java index fddf11b57e4..8d948c55e7d 100644 --- a/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java +++ b/test/langtools/tools/javac/lambda/deduplication/DeduplicationTest.java @@ -145,7 +145,7 @@ public static void main(String[] args) throws Exception { if (cm.thisClass().asInternalName().equals("com/sun/tools/javac/comp/Deduplication$R")) { continue; } - BootstrapMethodsAttribute bsm = cm.findAttribute(Attributes.BOOTSTRAP_METHODS).orElseThrow(); + BootstrapMethodsAttribute bsm = cm.findAttribute(Attributes.bootstrapMethods()).orElseThrow(); for (BootstrapMethodEntry b : bsm.bootstrapMethods()) { bootstrapMethodNames.add( ((MethodHandleEntry)b.arguments().get(1)) diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 6534f9f4dd0..5f558d421ff 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -743,8 +743,8 @@ public void testNoDuplicateIncubatorWarning(Path base) throws Exception { private static void markModuleAsIncubator(Path moduleInfoFile) throws Exception { ClassModel cf = ClassFile.of().parse(moduleInfoFile); ModuleResolutionAttribute newAttr = ModuleResolutionAttribute.of(WARN_INCUBATING); - byte[] newBytes = ClassFile.of().transform(cf, ClassTransform.dropping(ce -> ce instanceof Attributes) - .andThen(ClassTransform.endHandler(classBuilder -> classBuilder.with(newAttr)))); + byte[] newBytes = ClassFile.of().transform(cf, + ClassTransform.endHandler(classBuilder -> classBuilder.with(newAttr))); try (OutputStream out = Files.newOutputStream(moduleInfoFile)) { out.write(newBytes); } diff --git a/test/langtools/tools/javac/linenumbers/ConditionalLineNumberTest.java b/test/langtools/tools/javac/linenumbers/ConditionalLineNumberTest.java index 2727c9bdbd8..c44def84987 100644 --- a/test/langtools/tools/javac/linenumbers/ConditionalLineNumberTest.java +++ b/test/langtools/tools/javac/linenumbers/ConditionalLineNumberTest.java @@ -54,7 +54,7 @@ static List findEntries() throws IOException { ClassModel self = ClassFile.of().parse(ConditionalLineNumberTest.class.getResourceAsStream("ConditionalLineNumberTest.class").readAllBytes()); for (MethodModel m : self.methods()) { if (m.methodName().equalsString("method")) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElse(null); assert code_attribute != null; for (Attribute at : code_attribute.attributes()) { if (at instanceof LineNumberTableAttribute) { diff --git a/test/langtools/tools/javac/linenumbers/FinallyLineNumberTest.java b/test/langtools/tools/javac/linenumbers/FinallyLineNumberTest.java index 0a6f23593c1..d150c6bb4b7 100644 --- a/test/langtools/tools/javac/linenumbers/FinallyLineNumberTest.java +++ b/test/langtools/tools/javac/linenumbers/FinallyLineNumberTest.java @@ -83,7 +83,7 @@ static List findEntries() throws IOException { ClassModel self = ClassFile.of().parse(FinallyLineNumberTest.class.getResourceAsStream("FinallyLineNumberTest.class").readAllBytes()); for (MethodModel m : self.methods()) { if (m.methodName().equalsString("method")) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElseThrow(); for (Attribute at : code_attribute.attributes()) { if (at instanceof LineNumberTableAttribute lineAt) { return lineAt.lineNumbers(); diff --git a/test/langtools/tools/javac/linenumbers/NestedLineNumberTest.java b/test/langtools/tools/javac/linenumbers/NestedLineNumberTest.java index 481534ec2a0..108a31c23db 100644 --- a/test/langtools/tools/javac/linenumbers/NestedLineNumberTest.java +++ b/test/langtools/tools/javac/linenumbers/NestedLineNumberTest.java @@ -30,7 +30,7 @@ static List findEntries() throws IOException { ClassModel self = ClassFile.of().parse(NestedLineNumberTest.Test.class.getResourceAsStream("NestedLineNumberTest$Test.class").readAllBytes()); for (MethodModel m : self.methods()) { if ("".equals(m.methodName().stringValue())) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElseThrow(); for (Attribute at : code_attribute.attributes()) { if (at instanceof LineNumberTableAttribute lineAt) { return lineAt.lineNumbers(); diff --git a/test/langtools/tools/javac/linenumbers/NullCheckLineNumberTest.java b/test/langtools/tools/javac/linenumbers/NullCheckLineNumberTest.java index 91c562b2360..d74a0e5667b 100644 --- a/test/langtools/tools/javac/linenumbers/NullCheckLineNumberTest.java +++ b/test/langtools/tools/javac/linenumbers/NullCheckLineNumberTest.java @@ -63,7 +63,7 @@ static List findEntries() throws IOException { ClassModel self = ClassFile.of().parse(Objects.requireNonNull(Test.class.getResourceAsStream("NullCheckLineNumberTest$Test.class")).readAllBytes()); for (MethodModel m : self.methods()) { if ("".equals(m.methodName().stringValue())) { - CodeAttribute code_attribute = m.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = m.findAttribute(Attributes.code()).orElseThrow(); for (Attribute at : code_attribute.attributes()) { if (at instanceof LineNumberTableAttribute lineAt) { return lineAt.lineNumbers().stream() diff --git a/test/langtools/tools/javac/meth/TestCP.java b/test/langtools/tools/javac/meth/TestCP.java index 31a5bd1762f..bc574134b89 100644 --- a/test/langtools/tools/javac/meth/TestCP.java +++ b/test/langtools/tools/javac/meth/TestCP.java @@ -135,7 +135,7 @@ void verifySigPolyInvokeVirtual(File f, String psType) { if (testMethod == null) { throw new Error("Test method not found"); } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { throw new Error("Code attribute for test() method not found"); } diff --git a/test/langtools/tools/javac/modules/AnnotationsOnModules.java b/test/langtools/tools/javac/modules/AnnotationsOnModules.java index 59b48fd4954..bfae27d4d21 100644 --- a/test/langtools/tools/javac/modules/AnnotationsOnModules.java +++ b/test/langtools/tools/javac/modules/AnnotationsOnModules.java @@ -86,7 +86,7 @@ public void testSimpleAnnotation(Path base) throws Exception { .writeAll(); ClassModel cf = ClassFile.of().parse(modulePath.resolve("m1x").resolve("module-info.class")); - RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (annotations == null || annotations.annotations().size() != 1) { throw new AssertionError("Annotations not correct!"); @@ -140,13 +140,13 @@ public void testSimpleJavadocDeprecationTag(Path base) throws Exception { } ClassModel cf = ClassFile.of().parse(modulePath.resolve("A").resolve("module-info.class")); - RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (annotations != null && annotations.annotations().size() > 0) { throw new AssertionError("Found annotation attributes. Expected no annotations for javadoc @deprecated tag."); } - if (cf.findAttribute(Attributes.DEPRECATED).isPresent()) { + if (cf.findAttribute(Attributes.deprecated()).isPresent()) { throw new AssertionError("Found Deprecated attribute. Expected no Deprecated attribute for javadoc @deprecated tag."); } } @@ -191,7 +191,7 @@ public void testEnhancedDeprecatedAnnotation(Path base) throws Exception { } ClassModel cf = ClassFile.of().parse(modulePath.resolve("A").resolve("module-info.class")); - RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElse(null); + RuntimeVisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.runtimeVisibleAnnotations()).orElse(null); if (annotations == null ) { throw new AssertionError("Annotations not found!"); @@ -314,7 +314,7 @@ public void testAnnotationWithImport(Path base) throws Exception { .writeAll(); ClassModel cf = ClassFile.of().parse(modulePath.resolve("m1x").resolve("module-info.class")); - RuntimeInvisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); + RuntimeInvisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.runtimeInvisibleAnnotations()).orElse(null); if (annotations == null || annotations.annotations().size() != 1) { throw new AssertionError("Annotations not correct!"); @@ -356,7 +356,7 @@ public void testAnnotationWithImportFromAnotherModule(Path base) throws Exceptio .writeAll(); ClassModel cf = ClassFile.of().parse(modulePath.resolve("B").resolve("module-info.class")); - RuntimeInvisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); + RuntimeInvisibleAnnotationsAttribute annotations = cf.findAttribute(Attributes.runtimeInvisibleAnnotations()).orElse(null); if (annotations == null ) { throw new AssertionError("Annotations not found!"); @@ -431,7 +431,7 @@ public void testAnnotationWithoutTarget(Path base) throws Exception { .writeAll(); ClassModel cf = ClassFile.of().parse(classes.resolve("m1x").resolve("module-info.class")); - RuntimeInvisibleAnnotationsAttribute invisibleAnnotations = cf.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); + RuntimeInvisibleAnnotationsAttribute invisibleAnnotations = cf.findAttribute(Attributes.runtimeInvisibleAnnotations()).orElse(null); if (invisibleAnnotations == null) { throw new AssertionError("Annotations not found!"); diff --git a/test/langtools/tools/javac/modules/JavaBaseTest.java b/test/langtools/tools/javac/modules/JavaBaseTest.java index 64f914e5d2f..188bc4801e5 100644 --- a/test/langtools/tools/javac/modules/JavaBaseTest.java +++ b/test/langtools/tools/javac/modules/JavaBaseTest.java @@ -206,7 +206,7 @@ void createClass(Path base, List mods, String target) throws Exception { ClassModel cm1 = ClassFile.of().parse(modules1.resolve("module-info.class")); - ModuleAttribute modAttr1 = cm1.findAttribute(Attributes.MODULE).orElseThrow(); + ModuleAttribute modAttr1 = cm1.findAttribute(Attributes.module()).orElseThrow(); List requires = Arrays.asList(new ModuleRequireInfo[modAttr1.requires().size()]); for (int i = 0; i < modAttr1.requires().size(); ++i) { ModuleRequireInfo e1 = modAttr1.requires().get(i); diff --git a/test/langtools/tools/javac/modules/ModuleVersion.java b/test/langtools/tools/javac/modules/ModuleVersion.java index d6b514eee31..cbf9b82c54c 100644 --- a/test/langtools/tools/javac/modules/ModuleVersion.java +++ b/test/langtools/tools/javac/modules/ModuleVersion.java @@ -114,7 +114,7 @@ public void testMultipleModuleVersions(Path base) throws Exception { private void checkModuleVersion(Path classfile, String version) throws IOException { ClassModel cm = ClassFile.of().parse(classfile); - ModuleAttribute moduleAttribute = cm.findAttribute(Attributes.MODULE).orElse(null); + ModuleAttribute moduleAttribute = cm.findAttribute(Attributes.module()).orElse(null); if (moduleAttribute == null) { throw new AssertionError("Version attribute missing!"); diff --git a/test/langtools/tools/javac/modules/OpenModulesTest.java b/test/langtools/tools/javac/modules/OpenModulesTest.java index 4523b726548..e21601031e7 100644 --- a/test/langtools/tools/javac/modules/OpenModulesTest.java +++ b/test/langtools/tools/javac/modules/OpenModulesTest.java @@ -233,7 +233,7 @@ public void testNonZeroOpensInOpen(Path base) throws Exception { Path miClass = m1Classes.resolve("module-info.class"); ClassModel cm = ClassFile.of().parse(miClass); - ModuleAttribute module = cm.findAttribute(Attributes.MODULE).orElseThrow(); + ModuleAttribute module = cm.findAttribute(Attributes.module()).orElseThrow(); ModuleAttribute newModule = ModuleAttribute.of(module.moduleName(), module.moduleFlagsMask() | ClassFile.ACC_OPEN, module.moduleVersion().orElse(null), diff --git a/test/langtools/tools/javac/multicatch/7005371/T7005371.java b/test/langtools/tools/javac/multicatch/7005371/T7005371.java index bf83cd26089..c99371642a6 100644 --- a/test/langtools/tools/javac/multicatch/7005371/T7005371.java +++ b/test/langtools/tools/javac/multicatch/7005371/T7005371.java @@ -70,11 +70,11 @@ void verifyLocalVariableTypeTableAttr(File f) { if (testMethod == null) { throw new Error("Missing method: " + TEST_METHOD_NAME); } - CodeAttribute code = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = testMethod.findAttribute(Attributes.code()).orElse(null); if (code == null) { throw new Error("Missing Code attribute for method: " + TEST_METHOD_NAME); } - LocalVariableTypeTableAttribute lvt_table = code.findAttribute(Attributes.LOCAL_VARIABLE_TYPE_TABLE).orElse(null); + LocalVariableTypeTableAttribute lvt_table = code.findAttribute(Attributes.localVariableTypeTable()).orElse(null); if (lvt_table == null) { throw new Error("Missing LocalVariableTypeTable attribute for method: " + TEST_METHOD_NAME); } diff --git a/test/langtools/tools/javac/multicatch/Pos05.java b/test/langtools/tools/javac/multicatch/Pos05.java index 1dade792178..16ee54f2ccd 100644 --- a/test/langtools/tools/javac/multicatch/Pos05.java +++ b/test/langtools/tools/javac/multicatch/Pos05.java @@ -90,7 +90,7 @@ void verifyMulticatchExceptionRanges(File f) { if (testMethod == null) { throw new Error("Test method not found"); } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { throw new Error("Code attribute for test() method not found"); } diff --git a/test/langtools/tools/javac/patterns/Annotations.java b/test/langtools/tools/javac/patterns/Annotations.java index f14ab3fb970..a471cc57b63 100644 --- a/test/langtools/tools/javac/patterns/Annotations.java +++ b/test/langtools/tools/javac/patterns/Annotations.java @@ -67,8 +67,8 @@ void run() throws Exception { ClassModel cf = ClassFile.of().parse(annotationsClass.readAllBytes()); for (MethodModel m : cf.methods()) { if (m.methodName().equalsString("test")) { - CodeAttribute codeAttr = m.findAttribute(Attributes.CODE).orElseThrow(); - RuntimeInvisibleTypeAnnotationsAttribute annotations = codeAttr.findAttribute(Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS).orElseThrow(); + CodeAttribute codeAttr = m.findAttribute(Attributes.code()).orElseThrow(); + RuntimeInvisibleTypeAnnotationsAttribute annotations = codeAttr.findAttribute(Attributes.runtimeInvisibleTypeAnnotations()).orElseThrow(); String expected = "LAnnotations$DTA; pos: [LOCAL_VARIABLE, {start_pc=31, end_pc=38, index=1}], " + "LAnnotations$TA; pos: [LOCAL_VARIABLE, {start_pc=50, end_pc=57, index=1}], "; StringBuilder actual = new StringBuilder(); diff --git a/test/langtools/tools/javac/patterns/LocalVariableTable.java b/test/langtools/tools/javac/patterns/LocalVariableTable.java index 9fa29b09065..37051daf142 100644 --- a/test/langtools/tools/javac/patterns/LocalVariableTable.java +++ b/test/langtools/tools/javac/patterns/LocalVariableTable.java @@ -87,13 +87,13 @@ void check(Class c) throws Exception { return; } - CodeAttribute code = m.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute code = m.findAttribute(Attributes.code()).orElse(null); if (code == null) { error("Code attribute not found"); return; } - LocalVariableTableAttribute lvt = code.findAttribute(Attributes.LOCAL_VARIABLE_TABLE).orElse(null); + LocalVariableTableAttribute lvt = code.findAttribute(Attributes.localVariableTable()).orElse(null); if (lvt == null) { error("LocalVariableTable attribute not found"); return; diff --git a/test/langtools/tools/javac/patterns/NestedPatternVariablesBytecode.java b/test/langtools/tools/javac/patterns/NestedPatternVariablesBytecode.java index 3759676e2c3..36068729146 100644 --- a/test/langtools/tools/javac/patterns/NestedPatternVariablesBytecode.java +++ b/test/langtools/tools/javac/patterns/NestedPatternVariablesBytecode.java @@ -85,7 +85,7 @@ String test(Object o) { .filter(this::isTestMethod) .findAny() .orElseThrow(); - CodeAttribute code_attribute = testMethod.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = testMethod.findAttribute(Attributes.code()).orElseThrow(); List actualCode = getCodeInstructions(code_attribute); List expectedCode = Arrays.asList( diff --git a/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java b/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java index b7e7df089a5..55444e1d748 100644 --- a/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java +++ b/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java @@ -71,7 +71,7 @@ void checkClassFile(File file) throws IOException { ICONST_0 IRETURN """; - CodeAttribute code = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code = method.findAttribute(Attributes.code()).orElseThrow(); String actualInstructions = printCode(code); if (!expectedInstructions.equals(actualInstructions)) { throw new AssertionError("Unexpected instructions found:\n" + diff --git a/test/langtools/tools/javac/platform/ModuleVersionTest.java b/test/langtools/tools/javac/platform/ModuleVersionTest.java index 1b01fc397e8..0e8f8b8c05f 100644 --- a/test/langtools/tools/javac/platform/ModuleVersionTest.java +++ b/test/langtools/tools/javac/platform/ModuleVersionTest.java @@ -103,7 +103,7 @@ public class Test { ClassModel clazz = ClassFile.of().parse(moduleInfo); assertTrue(clazz.isModuleInfo()); - ModuleAttribute module = clazz.findAttribute(Attributes.MODULE).get(); + ModuleAttribute module = clazz.findAttribute(Attributes.module()).get(); ModuleRequireInfo req = module.requires().get(0); assertEquals("java.base", req.requires().name().stringValue()); assertEquals(expectedVersion, req.requiresVersion().get().stringValue()); diff --git a/test/langtools/tools/javac/processing/model/element/TestOrigin.java b/test/langtools/tools/javac/processing/model/element/TestOrigin.java index ba4d7ec7ef9..1fae5374bea 100644 --- a/test/langtools/tools/javac/processing/model/element/TestOrigin.java +++ b/test/langtools/tools/javac/processing/model/element/TestOrigin.java @@ -276,7 +276,7 @@ public void testModuleDirectives(Path base) throws Exception { Path moduleInfo = classes.resolve("module-info.class"); ClassModel cf = ClassFile.of().parse(moduleInfo); - ModuleAttribute module = cf.findAttribute(Attributes.MODULE).orElseThrow(); + ModuleAttribute module = cf.findAttribute(Attributes.module()).orElseThrow(); List newRequires = new ArrayList<>(3); newRequires.add(ModuleRequireInfo.of(module.requires().get(0).requires(), ClassFile.ACC_MANDATED, module.requires().get(0).requiresVersion().orElse(null))); diff --git a/test/langtools/tools/javac/records/RecordCompilationTests.java b/test/langtools/tools/javac/records/RecordCompilationTests.java index 0436169556f..9f5e73cc5d0 100644 --- a/test/langtools/tools/javac/records/RecordCompilationTests.java +++ b/test/langtools/tools/javac/records/RecordCompilationTests.java @@ -1320,7 +1320,7 @@ void testCheckInitializationOrderInCompactConstructor() throws Exception { ClassModel classFile = ClassFile.of().parse(fileEntry.toPath()); for (MethodModel method : classFile.methods()) { if (method.methodName().equalsString("")) { - CodeAttribute code_attribute = method.findAttribute(Attributes.CODE).orElseThrow(); + CodeAttribute code_attribute = method.findAttribute(Attributes.code()).orElseThrow(); for (CodeElement ce : code_attribute.elementList()) { if (ce instanceof Instruction instruction && instruction.opcode() == Opcode.PUTFIELD) { if (putField1 != null && putField2 != null) { diff --git a/test/langtools/tools/javac/records/recordComponent/RecordComponentTypeTest.java b/test/langtools/tools/javac/records/recordComponent/RecordComponentTypeTest.java index f11c464231f..015dc805eea 100644 --- a/test/langtools/tools/javac/records/recordComponent/RecordComponentTypeTest.java +++ b/test/langtools/tools/javac/records/recordComponent/RecordComponentTypeTest.java @@ -155,7 +155,7 @@ public record RecordComponentUsingGeneratedTypeWithAnnotation(@TestAnnotation Ge } private void checkRuntimeVisibleAnnotation(AttributedElement attributedElement) throws Exception { - RuntimeVisibleAnnotationsAttribute annotations = attributedElement.findAttribute(Attributes.RUNTIME_VISIBLE_ANNOTATIONS).orElseThrow(); + RuntimeVisibleAnnotationsAttribute annotations = attributedElement.findAttribute(Attributes.runtimeVisibleAnnotations()).orElseThrow(); boolean hasAnnotation = false; for (Annotation annotation : annotations.annotations()) { if (annotation.classSymbol().descriptorString().equals("LTestAnnotation;")) { diff --git a/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java b/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java index 16860d65cc2..6cec46ef2d1 100644 --- a/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java +++ b/test/langtools/tools/javac/sealed/SealedDiffConfigurationsTest.java @@ -133,7 +133,7 @@ public void testSameCompilationUnitPos2(Path base) throws Exception { private void checkSealedClassFile(Path out, String cfName, List expectedSubTypeNames) throws ConstantPoolException, Exception { ClassModel sealedCF = ClassFile.of().parse(out.resolve(cfName)); Assert.check((sealedCF.flags().flagsMask() & ClassFile.ACC_FINAL) == 0, String.format("class at file %s must not be final", cfName)); - PermittedSubclassesAttribute permittedSubclasses = sealedCF.findAttribute(Attributes.PERMITTED_SUBCLASSES).orElseThrow(); + PermittedSubclassesAttribute permittedSubclasses = sealedCF.findAttribute(Attributes.permittedSubclasses()).orElseThrow(); Assert.check(permittedSubclasses.permittedSubclasses().size() == expectedSubTypeNames.size()); List subtypeNames = new ArrayList<>(); permittedSubclasses.permittedSubclasses().forEach(i -> { @@ -152,7 +152,7 @@ private void checkSubtypeClassFile(Path out, String cfName, String superClassNam if (shouldBeFinal) { Assert.check((subCF1.flags().flagsMask() & ClassFile.ACC_FINAL) != 0, String.format("class at file %s must be final", cfName)); } - Assert.checkNull(subCF1.findAttribute(Attributes.PERMITTED_SUBCLASSES).orElse(null)); + Assert.checkNull(subCF1.findAttribute(Attributes.permittedSubclasses()).orElse(null)); Assert.check(subCF1.superclass().orElseThrow().name().equalsString(superClassName)); } diff --git a/test/langtools/tools/javac/varargs/6199075/T6199075.java b/test/langtools/tools/javac/varargs/6199075/T6199075.java index d2eaab364f5..6e77280eea5 100644 --- a/test/langtools/tools/javac/varargs/6199075/T6199075.java +++ b/test/langtools/tools/javac/varargs/6199075/T6199075.java @@ -226,7 +226,7 @@ void verifyBytecode(VarargsMethod selected) { if (testMethod == null) { throw new Error("Test method not found"); } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { throw new Error("Code attribute for test() method not found"); } diff --git a/test/langtools/tools/javac/varargs/7042566/T7042566.java b/test/langtools/tools/javac/varargs/7042566/T7042566.java index 845cab3bdf8..41c8e9609ca 100644 --- a/test/langtools/tools/javac/varargs/7042566/T7042566.java +++ b/test/langtools/tools/javac/varargs/7042566/T7042566.java @@ -282,7 +282,7 @@ void verifyBytecode(Result> res, VarargsMetho fail("Test method not found"); return; } - CodeAttribute ea = testMethod.findAttribute(Attributes.CODE).orElse(null); + CodeAttribute ea = testMethod.findAttribute(Attributes.code()).orElse(null); if (ea == null) { fail("Code attribute for test() method not found"); return; diff --git a/test/langtools/tools/javap/T6716452.java b/test/langtools/tools/javap/T6716452.java index 4cc8f4ec41d..63ccead52e7 100644 --- a/test/langtools/tools/javap/T6716452.java +++ b/test/langtools/tools/javap/T6716452.java @@ -51,8 +51,8 @@ public void run() throws Exception { } void test(MethodModel mm) { - test(mm, Attributes.CODE, CodeAttribute.class); - test(mm, Attributes.EXCEPTIONS, ExceptionsAttribute.class); + test(mm, Attributes.code(), CodeAttribute.class); + test(mm, Attributes.exceptions(), ExceptionsAttribute.class); } // test the result of MethodModel.findAttribute, MethodModel.attributes().indexOf() according to expectations diff --git a/test/langtools/tools/javap/classfile/6888367/T6888367.java b/test/langtools/tools/javap/classfile/6888367/T6888367.java index 16bc06321ca..3e3e3adcd7a 100644 --- a/test/langtools/tools/javap/classfile/6888367/T6888367.java +++ b/test/langtools/tools/javap/classfile/6888367/T6888367.java @@ -85,7 +85,7 @@ void testMethods(ClassModel cm) throws Exception { void testInnerClasses(ClassModel cm) throws Exception { InnerClassesAttribute ic = - cm.findAttribute(Attributes.INNER_CLASSES).orElse(null); + cm.findAttribute(Attributes.innerClasses()).orElse(null); assert ic != null; for (InnerClassInfo info: ic.classes()) { ClassEntry outerClass = info.outerClass().orElse(null); @@ -106,7 +106,7 @@ void test(String name, ConstantDesc desc, AttributedElement m) { return; System.err.println(name); - SignatureAttribute sa = m.findAttribute(Attributes.SIGNATURE).orElse(null); + SignatureAttribute sa = m.findAttribute(Attributes.signature()).orElse(null); if (sa != null) System.err.println(" signature: " + sa.signature()); @@ -173,7 +173,7 @@ static class AnnotValues { } AnnotValues getAnnotValues(String annotName, AttributedElement m) { - RuntimeInvisibleAnnotationsAttribute annots = m.findAttribute(Attributes.RUNTIME_INVISIBLE_ANNOTATIONS).orElse(null); + RuntimeInvisibleAnnotationsAttribute annots = m.findAttribute(Attributes.runtimeInvisibleAnnotations()).orElse(null); if (annots != null) { for (Annotation a: annots.annotations()) { if (a.classSymbol().descriptorString().equals("L" + annotName + ";")) { diff --git a/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java b/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java index 1aa3ddbebd8..1f5b2f43958 100644 --- a/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java +++ b/test/langtools/tools/javap/typeAnnotations/JSR175Annotations.java @@ -58,8 +58,8 @@ public void run() throws Exception { } void test(AttributedElement m) { - test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.runtimeVisibleTypeAnnotations()); + test(m, Attributes.runtimeInvisibleTypeAnnotations()); } // test the result of AttributedElement.findAttribute according to expectations diff --git a/test/langtools/tools/javap/typeAnnotations/NewArray.java b/test/langtools/tools/javap/typeAnnotations/NewArray.java index 7a5ca4675ce..cf08baf2955 100644 --- a/test/langtools/tools/javap/typeAnnotations/NewArray.java +++ b/test/langtools/tools/javap/typeAnnotations/NewArray.java @@ -52,8 +52,8 @@ public void run() throws Exception { } void test(MethodModel mm) { - test(mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(mm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(mm, Attributes.runtimeVisibleTypeAnnotations()); + test(mm, Attributes.runtimeInvisibleTypeAnnotations()); } // test the result of Attributes.getIndex according to expectations @@ -62,7 +62,7 @@ > void test(MethodModel mm, AttributeMapper attr_name) Attribute attr_instance; CodeAttribute cAttr; - cAttr = mm.findAttribute(Attributes.CODE).orElse(null); + cAttr = mm.findAttribute(Attributes.code()).orElse(null); if (cAttr != null) { attr_instance = cAttr.findAttribute(attr_name).orElse(null); if (attr_instance != null) { diff --git a/test/langtools/tools/javap/typeAnnotations/Presence.java b/test/langtools/tools/javap/typeAnnotations/Presence.java index 7b144457070..2fb488e705e 100644 --- a/test/langtools/tools/javap/typeAnnotations/Presence.java +++ b/test/langtools/tools/javap/typeAnnotations/Presence.java @@ -59,8 +59,8 @@ public void run() throws Exception { } void test(AttributedElement m) { - test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.runtimeVisibleTypeAnnotations()); + test(m, Attributes.runtimeInvisibleTypeAnnotations()); } // test the result of AttributedElement.findAttribute according to expectations @@ -80,7 +80,7 @@ > void test(AttributedElement m, AttributeMapper attr_ } } if (m instanceof MethodModel) { - attr_instance = m.findAttribute(Attributes.CODE).orElse(null); + attr_instance = m.findAttribute(Attributes.code()).orElse(null); if(attr_instance!= null) { CodeAttribute cAttr = (CodeAttribute)attr_instance; attr_instance = cAttr.findAttribute(attr_name).orElse(null); diff --git a/test/langtools/tools/javap/typeAnnotations/PresenceInner.java b/test/langtools/tools/javap/typeAnnotations/PresenceInner.java index a47a5ea9f53..ccb79534616 100644 --- a/test/langtools/tools/javap/typeAnnotations/PresenceInner.java +++ b/test/langtools/tools/javap/typeAnnotations/PresenceInner.java @@ -71,8 +71,8 @@ public void run() throws Exception { } void test(AttributedElement m) { - test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.runtimeVisibleTypeAnnotations()); + test(m, Attributes.runtimeInvisibleTypeAnnotations()); } // test the result of AttributedElement.findAttribute according to expectations diff --git a/test/langtools/tools/javap/typeAnnotations/TypeCasts.java b/test/langtools/tools/javap/typeAnnotations/TypeCasts.java index 6d318107c92..c8ee0fde965 100644 --- a/test/langtools/tools/javap/typeAnnotations/TypeCasts.java +++ b/test/langtools/tools/javap/typeAnnotations/TypeCasts.java @@ -55,8 +55,8 @@ public void run() throws Exception { } void test(MethodModel mm) { - test(mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(mm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(mm, Attributes.runtimeVisibleTypeAnnotations()); + test(mm, Attributes.runtimeInvisibleTypeAnnotations()); } @@ -66,7 +66,7 @@ > void test(MethodModel mm, AttributeMapper attr_name) Attribute attr; CodeAttribute cAttr; - cAttr = mm.findAttribute(Attributes.CODE).orElse(null); + cAttr = mm.findAttribute(Attributes.code()).orElse(null); if (cAttr != null) { attr = cAttr.findAttribute(attr_name).orElse(null); if (attr != null) { diff --git a/test/langtools/tools/javap/typeAnnotations/Visibility.java b/test/langtools/tools/javap/typeAnnotations/Visibility.java index d2f16b49d9b..ebffbf9176d 100644 --- a/test/langtools/tools/javap/typeAnnotations/Visibility.java +++ b/test/langtools/tools/javap/typeAnnotations/Visibility.java @@ -55,8 +55,8 @@ public void run() throws Exception { } void test(MethodModel mm) { - test(mm, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(mm, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(mm, Attributes.runtimeVisibleTypeAnnotations()); + test(mm, Attributes.runtimeInvisibleTypeAnnotations()); } // test the result of mm.findAttribute according to expectations diff --git a/test/langtools/tools/javap/typeAnnotations/Wildcards.java b/test/langtools/tools/javap/typeAnnotations/Wildcards.java index 8ef0bb61e07..6bbabebdd37 100644 --- a/test/langtools/tools/javap/typeAnnotations/Wildcards.java +++ b/test/langtools/tools/javap/typeAnnotations/Wildcards.java @@ -56,8 +56,8 @@ public void run() throws Exception { System.out.println("PASSED"); } void test(AttributedElement m) { - test(m, Attributes.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); - test(m, Attributes.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); + test(m, Attributes.runtimeVisibleTypeAnnotations()); + test(m, Attributes.runtimeInvisibleTypeAnnotations()); } > void test(AttributedElement m, AttributeMapper attr_name) { Attribute attr_instance = m.findAttribute(attr_name).orElse(null); From 6d2aeb82bc6f8b6894bf3777162be0efb2826397 Mon Sep 17 00:00:00 2001 From: Dan Heidinga Date: Fri, 24 May 2024 16:03:12 +0000 Subject: [PATCH 33/99] 8332745: Method::is_vanilla_constructor is never used Reviewed-by: coleenp, ayang --- .../share/classfile/classFileParser.cpp | 31 +------------ .../share/classfile/classFileParser.hpp | 1 - src/hotspot/share/oops/instanceKlass.hpp | 2 - src/hotspot/share/oops/instanceKlassFlags.hpp | 3 +- src/hotspot/share/oops/method.cpp | 43 ------------------- 5 files changed, 2 insertions(+), 78 deletions(-) diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 734b425cb45..815550da0bc 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -2827,11 +2827,6 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, _has_finalizer = true; } } - if (name == vmSymbols::object_initializer_name() && - signature == vmSymbols::void_method_signature() && - m->is_vanilla_constructor()) { - _has_vanilla_constructor = true; - } NOT_PRODUCT(m->verify()); return m; @@ -4162,29 +4157,6 @@ void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) { } } - // Check if this klass has a vanilla default constructor - if (super == nullptr) { - // java.lang.Object has empty default constructor - ik->set_has_vanilla_constructor(); - } else { - if (super->has_vanilla_constructor() && - _has_vanilla_constructor) { - ik->set_has_vanilla_constructor(); - } -#ifdef ASSERT - bool v = false; - if (super->has_vanilla_constructor()) { - const Method* const constructor = - ik->find_method(vmSymbols::object_initializer_name(), - vmSymbols::void_method_signature()); - if (constructor != nullptr && constructor->is_vanilla_constructor()) { - v = true; - } - } - assert(v == ik->has_vanilla_constructor(), "inconsistent has_vanilla_constructor"); -#endif - } - // If it cannot be fast-path allocated, set a bit in the layout helper. // See documentation of InstanceKlass::can_be_fastpath_allocated(). assert(ik->size_helper() > 0, "layout_helper is initialized"); @@ -5371,7 +5343,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, ik->set_has_contended_annotations(true); } - // Fill in has_finalizer, has_vanilla_constructor, and layout_helper + // Fill in has_finalizer and layout_helper set_precomputed_flags(ik); // check if this class can access its super class @@ -5557,7 +5529,6 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream, _has_contended_fields(false), _has_finalizer(false), _has_empty_finalizer(false), - _has_vanilla_constructor(false), _max_bootstrap_specifier_index(-1) { _class_name = name != nullptr ? name : vmSymbols::unknown_class_name(); diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index 03984baf1ae..f43303722a8 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -197,7 +197,6 @@ class ClassFileParser { // precomputed flags bool _has_finalizer; bool _has_empty_finalizer; - bool _has_vanilla_constructor; int _max_bootstrap_specifier_index; // detects BSS values void parse_stream(const ClassFileStream* const stream, TRAPS); diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index a77227198f6..27c97e38b62 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -766,8 +766,6 @@ class InstanceKlass: public Klass { bool declares_nonstatic_concrete_methods() const { return _misc_flags.declares_nonstatic_concrete_methods(); } void set_declares_nonstatic_concrete_methods(bool b) { _misc_flags.set_declares_nonstatic_concrete_methods(b); } - bool has_vanilla_constructor() const { return _misc_flags.has_vanilla_constructor(); } - void set_has_vanilla_constructor() { _misc_flags.set_has_vanilla_constructor(true); } bool has_miranda_methods () const { return _misc_flags.has_miranda_methods(); } void set_has_miranda_methods() { _misc_flags.set_has_miranda_methods(true); } bool has_final_method() const { return _misc_flags.has_final_method(); } diff --git a/src/hotspot/share/oops/instanceKlassFlags.hpp b/src/hotspot/share/oops/instanceKlassFlags.hpp index a596e14fa42..033b6958e43 100644 --- a/src/hotspot/share/oops/instanceKlassFlags.hpp +++ b/src/hotspot/share/oops/instanceKlassFlags.hpp @@ -53,8 +53,7 @@ class InstanceKlassFlags { flag(has_contended_annotations , 1 << 10) /* has @Contended annotation */ \ flag(has_localvariable_table , 1 << 11) /* has localvariable information */ \ flag(has_miranda_methods , 1 << 12) /* True if this class has miranda methods in it's vtable */ \ - flag(has_vanilla_constructor , 1 << 13) /* True if klass has a vanilla default constructor */ \ - flag(has_final_method , 1 << 14) /* True if klass has final method */ \ + flag(has_final_method , 1 << 13) /* True if klass has final method */ \ /* end of list */ #define IK_FLAGS_ENUM_NAME(name, value) _misc_##name = value, diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 4be0cf78bdc..a5b2267cf33 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -661,49 +661,6 @@ int Method::extra_stack_words() { return extra_stack_entries() * Interpreter::stackElementSize; } -bool Method::is_vanilla_constructor() const { - // Returns true if this method is a vanilla constructor, i.e. an "" "()V" method - // which only calls the superclass vanilla constructor and possibly does stores of - // zero constants to local fields: - // - // aload_0 - // invokespecial - // indexbyte1 - // indexbyte2 - // - // followed by an (optional) sequence of: - // - // aload_0 - // aconst_null / iconst_0 / fconst_0 / dconst_0 - // putfield - // indexbyte1 - // indexbyte2 - // - // followed by: - // - // return - - assert(name() == vmSymbols::object_initializer_name(), "Should only be called for default constructors"); - assert(signature() == vmSymbols::void_method_signature(), "Should only be called for default constructors"); - int size = code_size(); - // Check if size match - if (size == 0 || size % 5 != 0) return false; - address cb = code_base(); - int last = size - 1; - if (cb[0] != Bytecodes::_aload_0 || cb[1] != Bytecodes::_invokespecial || cb[last] != Bytecodes::_return) { - // Does not call superclass default constructor - return false; - } - // Check optional sequence - for (int i = 4; i < last; i += 5) { - if (cb[i] != Bytecodes::_aload_0) return false; - if (!Bytecodes::is_zero_const(Bytecodes::cast(cb[i+1]))) return false; - if (cb[i+2] != Bytecodes::_putfield) return false; - } - return true; -} - - bool Method::compute_has_loops_flag() { BytecodeStream bcs(methodHandle(Thread::current(), this)); Bytecodes::Code bc; From c2cca2ab443ff87f689810b747985adfdbfbe54a Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Fri, 24 May 2024 16:07:36 +0000 Subject: [PATCH 34/99] 8330647: Two CDS tests fail with -UseCompressedOops and UseSerialGC/UseParallelGC Reviewed-by: dholmes, iklam --- test/jtreg-ext/requires/VMProps.java | 31 +++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index b55063f04f2..e37646ac6d1 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -67,6 +67,9 @@ public class VMProps implements Callable> { // value known to jtreg as an indicator of error state private static final String ERROR_STATE = "__ERROR__"; + private static final String GC_PREFIX = "-XX:+Use"; + private static final String GC_SUFFIX = "GC"; + private static final WhiteBox WB = WhiteBox.getWhiteBox(); private static class SafeMap { @@ -348,8 +351,6 @@ protected void vmGCforCDS(SafeMap map) { return; } - String GC_PREFIX = "-XX:+Use"; - String GC_SUFFIX = "GC"; String jtropts = System.getProperty("test.cds.runtime.options"); if (jtropts != null) { for (String opt : jtropts.split(",")) { @@ -462,7 +463,31 @@ protected String vmCDSForCustomLoaders() { * @return true if this VM can write Java heap objects into the CDS archive */ protected String vmCDSCanWriteArchivedJavaHeap() { - return "" + ("true".equals(vmCDS()) && WB.canWriteJavaHeapArchive()); + return "" + ("true".equals(vmCDS()) && WB.canWriteJavaHeapArchive() + && isCDSRuntimeOptionsCompatible()); + } + + /** + * @return true if the VM options specified via the "test.cds.runtime.options" + * property is compatible with writing Java heap objects into the CDS archive + */ + protected boolean isCDSRuntimeOptionsCompatible() { + String jtropts = System.getProperty("test.cds.runtime.options"); + if (jtropts == null) { + return true; + } + String CCP_DISABLED = "-XX:-UseCompressedClassPointers"; + String G1GC_ENABLED = "-XX:+UseG1GC"; + 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)) { + return false; + } + } + return true; } /** From cd3e4c03661f770ebeefcd3637d56589243ac0a9 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Fri, 24 May 2024 16:30:30 +0000 Subject: [PATCH 35/99] 8326734: text-decoration applied to lost when mixed with or 8325620: HTMLReader uses ConvertAction instead of specified CharacterAction for , , Reviewed-by: honkar, prr --- .../classes/javax/swing/text/html/CSS.java | 14 +- .../javax/swing/text/html/HTMLDocument.java | 71 ++++---- .../swing/text/html/MuxingAttributeSet.java | 36 ++-- .../javax/swing/text/html/StyleSheet.java | 75 ++++++++- .../html/HTMLDocument/HTMLStrikeOnly.java | 135 +++++++++++++++ .../html/HTMLDocument/HTMLTextDecoration.java | 157 ++++++++++++++++++ .../html/HTMLDocument/HTMLUnderlineOnly.java | 129 ++++++++++++++ .../HTMLDocument/HTMLUnderlineStrike.java | 2 +- 8 files changed, 563 insertions(+), 56 deletions(-) create mode 100644 test/jdk/javax/swing/text/html/HTMLDocument/HTMLStrikeOnly.java create mode 100644 test/jdk/javax/swing/text/html/HTMLDocument/HTMLTextDecoration.java create mode 100644 test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineOnly.java diff --git a/src/java.desktop/share/classes/javax/swing/text/html/CSS.java b/src/java.desktop/share/classes/javax/swing/text/html/CSS.java index 2b96b28dfbb..595799926a3 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/CSS.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/CSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -843,6 +843,18 @@ Object getInternalCSSValue(CSS.Attribute key, String value) { return r != null ? r : conv.parseCssValue(key.getDefaultValue()); } + static Object mergeTextDecoration(String value) { + boolean underline = value.contains("underline"); + boolean strikeThrough = value.contains("line-through"); + if (!underline && !strikeThrough) { + return null; + } + String newValue = underline && strikeThrough + ? "underline,line-through" + : (underline ? "underline" : "line-through"); + return new StringValue().parseCssValue(newValue); + } + /** * Maps from a StyleConstants to a CSS Attribute. */ diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java index 2b70e625325..c382b4e056a 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java @@ -2499,7 +2499,7 @@ public HTMLReader(int offset, int popDepth, int pushDepth, tagMap.put(HTML.Tag.SCRIPT, ha); tagMap.put(HTML.Tag.SELECT, fa); tagMap.put(HTML.Tag.SMALL, ca); - tagMap.put(HTML.Tag.SPAN, ca); + tagMap.put(HTML.Tag.SPAN, new ConvertSpanAction()); tagMap.put(HTML.Tag.STRIKE, conv); tagMap.put(HTML.Tag.S, conv); tagMap.put(HTML.Tag.STRONG, ca); @@ -3423,11 +3423,43 @@ public void start(HTML.Tag t, MutableAttributeSet attr) { if (styleAttributes != null) { charAttr.addAttributes(styleAttributes); } + + convertAttributes(t, attr); } public void end(HTML.Tag t) { popCharacterStyle(); } + + /** + * Converts HTML tags to CSS attributes. + * @param t the current HTML tag + * @param attr the attributes of the HTML tag + */ + void convertAttributes(HTML.Tag t, MutableAttributeSet attr) { + } + } + + final class ConvertSpanAction extends CharacterAction { + @Override + void convertAttributes(HTML.Tag t, MutableAttributeSet attr) { + Object newDecoration = attr.getAttribute(CSS.Attribute.TEXT_DECORATION); + Object previousDecoration = + charAttrStack.peek() + .getAttribute(CSS.Attribute.TEXT_DECORATION); + + if (newDecoration != null + && !"none".equals(newDecoration.toString()) + && previousDecoration != null + && !"none".equals(previousDecoration.toString())) { + StyleSheet sheet = getStyleSheet(); + sheet.addCSSAttribute(charAttr, + CSS.Attribute.TEXT_DECORATION, + CSS.mergeTextDecoration(newDecoration + "," + + previousDecoration) + .toString()); + } + } } /** @@ -3435,35 +3467,9 @@ public void end(HTML.Tag t) { * mappings that have a corresponding StyleConstants * and CSS mapping. The conversion is to CSS attributes. */ - class ConvertAction extends TagAction { - - public void start(HTML.Tag t, MutableAttributeSet attr) { - pushCharacterStyle(); - if (!foundInsertTag) { - // Note that the third argument should really be based off - // inParagraph and impliedP. If we're wrong (that is - // insertTagDepthDelta shouldn't be changed), we'll end up - // removing an extra EndSpec, which won't matter anyway. - boolean insert = canInsertTag(t, attr, false); - if (foundInsertTag) { - if (!inParagraph) { - inParagraph = impliedP = true; - } - } - if (!insert) { - return; - } - } - if (attr.isDefined(IMPLIED)) { - attr.removeAttribute(IMPLIED); - } - if (styleAttributes != null) { - charAttr.addAttributes(styleAttributes); - } - // We also need to add attr, otherwise we lose custom - // attributes, including class/id for style lookups, and - // further confuse style lookup (doesn't have tag). - charAttr.addAttribute(t, attr.copyAttributes()); + final class ConvertAction extends CharacterAction { + @Override + void convertAttributes(HTML.Tag t, MutableAttributeSet attr) { StyleSheet sheet = getStyleSheet(); if (t == HTML.Tag.B) { sheet.addCSSAttribute(charAttr, CSS.Attribute.FONT_WEIGHT, "bold"); @@ -3504,11 +3510,6 @@ public void start(HTML.Tag t, MutableAttributeSet attr) { } } } - - public void end(HTML.Tag t) { - popCharacterStyle(); - } - } class AnchorAction extends CharacterAction { diff --git a/src/java.desktop/share/classes/javax/swing/text/html/MuxingAttributeSet.java b/src/java.desktop/share/classes/javax/swing/text/html/MuxingAttributeSet.java index 9d423dcded9..4d6ae0e0ae1 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/MuxingAttributeSet.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/MuxingAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, 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 @@ -24,9 +24,16 @@ */ package javax.swing.text.html; -import javax.swing.text.*; import java.io.Serializable; -import java.util.*; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.stream.Collectors; + +import javax.swing.text.AttributeSet; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.SimpleAttributeSet; /** * An implementation of AttributeSet that can multiplex @@ -196,15 +203,24 @@ public AttributeSet copyAttributes() { * @see AttributeSet#getAttribute */ public Object getAttribute(Object key) { - AttributeSet[] as = getAttributes(); - int n = as.length; - for (int i = 0; i < n; i++) { - Object o = as[i].getAttribute(key); - if (o != null) { - return o; + final AttributeSet[] as = getAttributes(); + final int n = as.length; + if (key != CSS.Attribute.TEXT_DECORATION) { + for (int i = 0; i < n; i++) { + Object o = as[i].getAttribute(key); + if (o != null) { + return o; + } } + return null; } - return null; + + String values = Arrays.stream(as) + .map(a -> a.getAttribute(key)) + .filter(Objects::nonNull) + .map(Object::toString) + .collect(Collectors.joining(",")); + return CSS.mergeTextDecoration(values); } /** diff --git a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java index fd3c75829e8..0790060f5e8 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, 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 @@ -24,17 +24,53 @@ */ package javax.swing.text.html; -import sun.swing.SwingUtilities2; -import java.util.*; -import java.awt.*; -import java.io.*; -import java.net.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.Serializable; +import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.EmptyStackException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.UIManager; -import javax.swing.border.*; +import javax.swing.border.BevelBorder; +import javax.swing.border.Border; import javax.swing.event.ChangeListener; -import javax.swing.text.*; +import javax.swing.text.AttributeSet; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.Style; +import javax.swing.text.StyleConstants; +import javax.swing.text.StyleContext; +import javax.swing.text.StyledDocument; +import javax.swing.text.View; + +import sun.swing.SwingUtilities2; /** * Support for defining the visual characteristics of @@ -2817,10 +2853,31 @@ public Object getAttribute(Object key) { return doGetAttribute(key); } + /** + * Merges the current value of the 'text-decoration' property + * with the value from parent. + */ + private Object getTextDecoration(Object value) { + AttributeSet parent = getResolveParent(); + if (parent == null) { + return value; + } + + Object parentValue = parent.getAttribute(CSS.Attribute.TEXT_DECORATION); + return parentValue == null + ? value + : CSS.mergeTextDecoration(value + "," + parentValue); + } + Object doGetAttribute(Object key) { Object retValue = super.getAttribute(key); if (retValue != null) { - return retValue; + if (key != CSS.Attribute.TEXT_DECORATION) { + return retValue; + } else { + // Merge current value with parent + return getTextDecoration(retValue); + } } if (key == CSS.Attribute.FONT_SIZE) { diff --git a/test/jdk/javax/swing/text/html/HTMLDocument/HTMLStrikeOnly.java b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLStrikeOnly.java new file mode 100644 index 00000000000..5ec32f74d40 --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLStrikeOnly.java @@ -0,0 +1,135 @@ +/* + * 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.Dimension; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JEditorPane; +import javax.swing.text.View; +import javax.swing.text.html.CSS; + +/* + * @test + * @bug 8326734 + * @summary Tests different combinations of setting 'line-through' + * @run main HTMLStrikeOnly + */ +public class HTMLStrikeOnly { + private static final String HTML = """ + + + + + line-through + + + +

    line-through?

    +

    line-through?

    +

    line-through?

    +

    line-through?

    + +

    line-through?

    +

    line-through?

    +

    line-through?

    +

    line-through?

    + +

    line-through?

    +

    line-through?

    +

    line-through?

    + +

    line-through

    +

    line-through

    +

    line-through

    +

    line-through

    + + + """; + public static void main(String[] args) { + final JEditorPane html = new JEditorPane("text/html", HTML); + html.setEditable(false); + + final Dimension size = html.getPreferredSize(); + html.setSize(size); + + BufferedImage image = new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + // Paint the editor pane to ensure all views are created + html.paint(g); + g.dispose(); + + int errorCount = 0; + String firstError = null; + + System.out.println("----- Views -----"); + final View bodyView = html.getUI() + .getRootView(html) + .getView(1) + .getView(1); + for (int i = 0; i < bodyView.getViewCount(); i++) { + View pView = bodyView.getView(i); + View contentView = getContentView(pView); + + String decoration = + contentView.getAttributes() + .getAttribute(CSS.Attribute.TEXT_DECORATION) + .toString(); + + System.out.println(i + ": " + decoration); + if (!decoration.contains("line-through") + || decoration.contains("underline")) { + errorCount++; + if (firstError == null) { + firstError = "Line " + i + ": " + decoration; + } + } + } + + if (errorCount > 0) { + saveImage(image); + throw new RuntimeException(errorCount + " error(s) found, " + + "the first one: " + firstError); + } + } + + private static View getContentView(View parent) { + View view = parent.getView(0); + return view.getViewCount() > 0 + ? getContentView(view) + : view; + } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("html.png")); + } catch (IOException ignored) { } + } +} diff --git a/test/jdk/javax/swing/text/html/HTMLDocument/HTMLTextDecoration.java b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLTextDecoration.java new file mode 100644 index 00000000000..a8868d05a5a --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLTextDecoration.java @@ -0,0 +1,157 @@ +/* + * 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.Dimension; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JEditorPane; +import javax.swing.text.View; +import javax.swing.text.html.CSS; + +/* + * @test + * @bug 8323801 8326734 + * @summary Tests different combination of 'underline' and 'line-through'; + * the text should render with both 'underline' and 'line-through'. + * @run main HTMLTextDecoration + */ +public final class HTMLTextDecoration { + private static final String HTML = """ + + + + + underline + line-through text + + + +

    underline + line-through?

    +

    underline + line-through?

    +

    underline + line-through?

    + +

    underline + line-through?

    +

    underline + line-through?

    +

    underline + line-through?

    + +

    underline + line-through?

    +

    underline + line-through?

    + +

    underline + line-through?

    +

    underline + line-through?

    +

    underline + line-through?

    + +

    underline + line-through?

    +

    underline + line-through?

    + +

    underline + line-through?

    +

    underline + line-through?

    +

    underline + line-through?

    + +

    underline + line-through?

    +

    underline + line-through?

    + +
    underline + line-through?
    +
    underline + line-through?
    +
    underline + line-through?
    + +
    underline + line-through?
    +
    underline + line-through?
    + +

    underline + line-through?

    +

    underline + line-through?

    + +
    underline + line-through?
    +
    underline + line-through?
    + + + """; + + public static void main(String[] args) { + final JEditorPane html = new JEditorPane("text/html", HTML); + html.setEditable(false); + + final Dimension size = html.getPreferredSize(); + html.setSize(size); + + BufferedImage image = new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + // Paint the editor pane to ensure all views are created + html.paint(g); + g.dispose(); + + int errorCount = 0; + String firstError = null; + + System.out.println("----- Views -----"); + final View bodyView = html.getUI() + .getRootView(html) + .getView(1) + .getView(1); + for (int i = 0; i < bodyView.getViewCount(); i++) { + View pView = bodyView.getView(i); + View contentView = getContentView(pView); + + String decoration = + contentView.getAttributes() + .getAttribute(CSS.Attribute.TEXT_DECORATION) + .toString(); + + System.out.println(i + ": " + decoration); + if (!decoration.contains("underline") + || !decoration.contains("line-through")) { + errorCount++; + if (firstError == null) { + firstError = "Line " + i + ": " + decoration; + } + } + } + + if (errorCount > 0) { + saveImage(image); + throw new RuntimeException(errorCount + " error(s) found, " + + "the first one: " + firstError); + } + } + + private static View getContentView(View parent) { + View view = parent.getView(0); + return view.getViewCount() > 0 + ? getContentView(view) + : view; + } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("html.png")); + } catch (IOException ignored) { } + } +} diff --git a/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineOnly.java b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineOnly.java new file mode 100644 index 00000000000..e142203b458 --- /dev/null +++ b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineOnly.java @@ -0,0 +1,129 @@ +/* + * 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.Dimension; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.swing.JEditorPane; +import javax.swing.text.View; +import javax.swing.text.html.CSS; + +/* + * @test + * @bug 8326734 + * @summary Tests different combinations of setting 'underline' + * @run main HTMLUnderlineOnly + */ +public class HTMLUnderlineOnly { + private static final String HTML = """ + + + + + underline + + + +

    underline?

    +

    underline?

    + +

    underline?

    +

    underline?

    + +

    underline?

    +

    underline?

    + +

    underline

    +

    underline

    +

    underline

    + + + """; + public static void main(String[] args) { + final JEditorPane html = new JEditorPane("text/html", HTML); + html.setEditable(false); + + final Dimension size = html.getPreferredSize(); + html.setSize(size); + + BufferedImage image = new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + // Paint the editor pane to ensure all views are created + html.paint(g); + g.dispose(); + + int errorCount = 0; + String firstError = null; + + System.out.println("----- Views -----"); + final View bodyView = html.getUI() + .getRootView(html) + .getView(1) + .getView(1); + for (int i = 0; i < bodyView.getViewCount(); i++) { + View pView = bodyView.getView(i); + View contentView = getContentView(pView); + + String decoration = + contentView.getAttributes() + .getAttribute(CSS.Attribute.TEXT_DECORATION) + .toString(); + + System.out.println(i + ": " + decoration); + if (!decoration.contains("underline") + || decoration.contains("line-through")) { + errorCount++; + if (firstError == null) { + firstError = "Line " + i + ": " + decoration; + } + } + } + + if (errorCount > 0) { + saveImage(image); + throw new RuntimeException(errorCount + " error(s) found, " + + "the first one: " + firstError); + } + } + + private static View getContentView(View parent) { + View view = parent.getView(0); + return view.getViewCount() > 0 + ? getContentView(view) + : view; + } + + private static void saveImage(BufferedImage image) { + try { + ImageIO.write(image, "png", + new File("html.png")); + } catch (IOException ignored) { } + } +} diff --git a/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineStrike.java b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineStrike.java index 5061321ea43..79aa5c81281 100644 --- a/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineStrike.java +++ b/test/jdk/javax/swing/text/html/HTMLDocument/HTMLUnderlineStrike.java @@ -31,7 +31,7 @@ /* * @test - * @bug 8323801 + * @bug 8323801 8326734 * @summary Tests that '' produce underlined and struck-through text */ public final class HTMLUnderlineStrike { From f66a58661459bf64212ec332540c12d5d691270f Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Fri, 24 May 2024 17:31:30 +0000 Subject: [PATCH 36/99] 8332641: Update nsk.share.jpda.Jdb to don't use finalization Reviewed-by: cjplummer, kevinw --- .../jtreg/vmTestbase/nsk/share/jdb/Jdb.java | 15 +++++--------- .../vmTestbase/nsk/share/jdb/JdbTest.java | 20 ++++++++++++------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Jdb.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Jdb.java index 107f8f2e0d8..7b3281a7e17 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Jdb.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/Jdb.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, 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 @@ -24,7 +24,6 @@ package nsk.share.jdb; import nsk.share.*; -import nsk.share.jpda.*; import java.util.*; import java.io.*; @@ -36,7 +35,7 @@ * This class provides abilities to launch it, to send command, * to read reply on the command, to set breakpoint on entry in debugggee's method. */ -public class Jdb extends LocalProcess implements Finalizable { +public class Jdb extends LocalProcess { /** File to log stdout stream */ static final String JDB_STDOUT_FILE = "jdb.stdout"; /** File to log stderr stream */ @@ -95,11 +94,8 @@ public static Launcher getLauncher() { return launcher; } - public void finalizeAtExit() throws Throwable { - finalize(); - } - public void finalize() throws Throwable { + public void close() { if (fout != null) { // fout.flush(); fout.close(); @@ -116,7 +112,6 @@ public void finalize() throws Throwable { if (jdbStderrReader != null) { jdbStderrReader.close(); } - super.finalize(); } /** Create Jdb object. */ @@ -961,10 +956,10 @@ public static Jdb startAttachingJdb (Launcher launcher, String[] jdbCmdArgs, Str System.out.println("Unsuccessful launch of attaching jdb. Next try..."); try { - jdb.finalize(); + jdb.close(); } catch (Throwable t) { t.printStackTrace(getLauncher().getLog().getOutStream()); - throw new Failure("Caught unexpected error while finalizing jdb: " + t); + throw new Failure("Caught unexpected error while closing jdb streams: " + t); } break; diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java index c0edc58993b..ce2eb8de68f 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, 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 @@ -24,10 +24,8 @@ package nsk.share.jdb; import nsk.share.*; -import nsk.share.jpda.*; import java.io.*; -import java.util.*; public abstract class JdbTest { public static final int PASSED = 0; // Exit code for passed test @@ -174,6 +172,14 @@ protected int runTest(String argv[], PrintStream out) { } else { failure("jdb abnormally exited with code: " + code); } + + try { + jdb.close(); + } catch (Throwable ex) { + failure("Caught exception/error while closing jdb streams:\n\t" + ex); + ex.printStackTrace(log.getOutStream()); + } + jdb = null; if (debuggee != null @@ -204,19 +210,19 @@ protected int runTest(String argv[], PrintStream out) { if (jdb != null) { try { - jdb.finalize(); + jdb.close(); } catch (Throwable ex) { - failure("Caught exception/error while finalization of jdb:\n\t" + ex); + failure("Caught exception/error while closing jdb streams:\n\t" + ex); ex.printStackTrace(log.getOutStream()); } } else { - log.complain("jdb reference is null, cannot run jdb.finalize() method"); + log.complain("jdb reference is null, cannot run jdb.close() method"); } if (debuggee != null) { debuggee.killDebuggee(); } else { - log.complain("debuggee reference is null, cannot run debuggee.finalize() method"); + log.complain("debuggee reference is null, cannot run debuggee.killDebuggee() method"); } } From b3b33667ad3bdb7be868fb165a1ea53054947cd0 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Fri, 24 May 2024 17:34:00 +0000 Subject: [PATCH 37/99] 8332631: Update nsk.share.jpda.BindServer to don't use finalization Reviewed-by: cjplummer, sspitsyn --- .../vmTestbase/nsk/share/jpda/BindServer.java | 124 +++++++----------- 1 file changed, 44 insertions(+), 80 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/BindServer.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/BindServer.java index bd57206302b..2ed334e0386 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/BindServer.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/BindServer.java @@ -28,7 +28,6 @@ import java.util.*; import nsk.share.*; -import nsk.share.jpda.*; /** * BindServer is an utility to perform JPDA tests @@ -58,7 +57,7 @@ * @see DebugeeBinder * @see DebugeeArgumentHandler */ -public class BindServer implements Finalizable { +public final class BindServer { /** Version of BindServer implementation. */ public static final long VERSION = 2; @@ -88,7 +87,6 @@ public class BindServer implements Finalizable { private static String pathConvertions[][] = null; - private ListeningThread listeningThread = null; private int totalRequests = 0; private int acceptedRequests = 0; @@ -149,8 +147,6 @@ private int runIt(String argv[], PrintStream out) { log = new Log(out, argHandler); logger = new Log.Logger(log, ""); - registerCleanup(); - logger.trace(TRACE_LEVEL_THREADS, "BindServer: starting main thread"); logger.display("Listening to port: " + argHandler.getBindPortNumber()); @@ -178,45 +174,39 @@ private int runIt(String argv[], PrintStream out) { BufferedReader stdIn = new BufferedReader( new InputStreamReader(System.in)); + try (ListeningThread listeningThread = new ListeningThread(this)) { + listeningThread.bind(); + listeningThread.start(); - listeningThread = new ListeningThread(this); - listeningThread.bind(); - listeningThread.start(); - - System.out.println("\n" - + "BindServer started" + "\n" - + "Type \"exit\" to shut down BindServer" - + "\n"); + System.out.println("\n" + + "BindServer started" + "\n" + + "Type \"exit\" to shut down BindServer" + + "\n"); - for (;;) { - try { - String userInput = stdIn.readLine(); - if (userInput == null || userInput.equals("exit") - || userInput.equals("quit")) { - logger.display("Shutting down BindServer"); - stdIn.close(); - stdIn = null; - break; - } else if (userInput.trim().equals("")) { - continue; - } else { - System.out.println("ERROR: Unknown command: " + userInput); + for (; ; ) { + try { + String userInput = stdIn.readLine(); + if (userInput == null || userInput.equals("exit") + || userInput.equals("quit")) { + logger.display("Shutting down BindServer"); + stdIn.close(); + stdIn = null; + break; + } else if (userInput.trim().equals("")) { + continue; + } else { + System.out.println("ERROR: Unknown command: " + userInput); + } + } catch (IOException e) { + e.printStackTrace(log.getOutStream()); + throw new Failure("Caught exception while reading console command:\n\t" + + e); } - } catch(IOException e) { - e.printStackTrace(log.getOutStream()); - throw new Failure("Caught exception while reading console command:\n\t" - + e); } - } - printSummary(System.out); + printSummary(System.out); - logger.trace(TRACE_LEVEL_THREADS, "BindServer: exiting main thread"); - try { - cleanup(); - } catch (Throwable e) { - e.printStackTrace(log.getOutStream()); - logger.complain("Caught exception while finalization of BindServer:\n\t" + e); + logger.trace(TRACE_LEVEL_THREADS, "BindServer: exiting main thread"); } return PASSED; @@ -387,38 +377,6 @@ private static void waitInterruptThread(Thread thr) { waitInterruptThread(thr, THREAD_TIMEOUT); } - /** - * Close BindServer by finishing all threads and closing - * all conections. - */ - public synchronized void close() { - if (listeningThread != null) { - listeningThread.close(); - listeningThread = null; - } - } - - /** - * Make finalization of BindServer object by invoking - * method close(). - * - * @see #close() - */ - @Override - public void cleanup() { - close(); - } - - /** - * Make finalization of BindServer object at program exit - * by invoking method cleanup(). - * - */ - public void finalizeAtExit() throws Throwable { - cleanup(); - logger.trace(TRACE_LEVEL_THREADS, "BindServer: finalization at exit completed"); - } - ///////// Thread listening a TCP/IP socket ////////// /** @@ -427,7 +385,7 @@ public void finalizeAtExit() throws Throwable { * * @see ServingThread */ - private static class ListeningThread extends Thread { + private static class ListeningThread extends Thread implements AutoCloseable { private volatile boolean shouldStop = false; private volatile boolean closed = false; @@ -673,23 +631,29 @@ private void closeConnection() { /** * Close thread by closing all connections and waiting - * foor thread finished. + * for thread to finish. * * @see #closeConnection() */ + @Override public synchronized void close() { if (closed) { return; } - closeHostConnection(); - if (servingThread != null) { - servingThread.close(); - servingThread = null; + try { + closeHostConnection(); + if (servingThread != null) { + servingThread.close(); + servingThread = null; + } + waitForThread(THREAD_TIMEOUT); + closeConnection(); + closed = true; + logger.trace(TRACE_LEVEL_THREADS, "ListeningThread closed"); + } catch (Throwable e) { + e.printStackTrace(log.getOutStream()); + logger.complain("Caught exception while closing ListeningThread:\n\t" + e); } - waitForThread(THREAD_TIMEOUT); - closeConnection(); - closed = true; - logger.trace(TRACE_LEVEL_THREADS, "ListeningThread closed"); } } // ListeningThread From 236432dbdb9bab4aece54c2fea08f055e5dbf97e Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Fri, 24 May 2024 17:51:49 +0000 Subject: [PATCH 38/99] 8332084: Ensure JdkConsoleImpl.restoreEcho visibility in a shutdown hook Reviewed-by: prappo, joehw, smarks --- .../jdk/internal/io/JdkConsoleImpl.java | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java index 7930e00fbc0..a1086b245d1 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java @@ -127,7 +127,9 @@ public char[] readPassword(Locale locale, String format, Object ... args) { synchronized(readLock) { installShutdownHook(); try { - restoreEcho = echo(false); + synchronized(restoreEchoLock) { + restoreEcho = echo(false); + } } catch (IOException x) { throw new IOError(x); } @@ -140,8 +142,11 @@ public char[] readPassword(Locale locale, String format, Object ... args) { ioe = new IOError(x); } finally { try { - if (restoreEcho) - restoreEcho = echo(true); + synchronized(restoreEchoLock) { + if (restoreEcho) { + restoreEcho = echo(true); + } + } } catch (IOException x) { if (ioe == null) ioe = new IOError(x); @@ -154,7 +159,7 @@ public char[] readPassword(Locale locale, String format, Object ... args) { if (reader instanceof LineReader lr) { lr.zeroOut(); } - } catch (IOException x) { + } catch (IOException _) { // ignore } throw ioe; @@ -178,13 +183,15 @@ private void installShutdownHook() { new Runnable() { public void run() { try { - if (restoreEcho) { - echo(true); + synchronized(restoreEchoLock) { + if (restoreEcho) { + echo(true); + } } - } catch (IOException x) { } + } catch (IOException _) { } } }); - } catch (IllegalStateException e) { + } catch (IllegalStateException _) { // shutdown is already in progress and readPassword is first used // by a shutdown hook } @@ -209,6 +216,8 @@ public Charset charset() { private final Charset charset; private final Object readLock; private final Object writeLock; + // Must not block while holding this. It is used in the shutdown hook. + private final Object restoreEchoLock; private final Reader reader; private final Writer out; private final PrintWriter pw; @@ -379,6 +388,7 @@ public JdkConsoleImpl(Charset charset) { this.charset = charset; readLock = new Object(); writeLock = new Object(); + restoreEchoLock = new Object(); out = StreamEncoder.forOutputStreamWriter( new FileOutputStream(FileDescriptor.out), writeLock, From ebc520e83f503eeb4e5af6d5aef62df9227af4f7 Mon Sep 17 00:00:00 2001 From: William Kemper Date: Fri, 24 May 2024 18:10:31 +0000 Subject: [PATCH 39/99] 8332841: GenShen: Pull shared members from control thread into common base class Reviewed-by: ysr --- .../gc/shenandoah/shenandoahControlThread.cpp | 99 ++-------------- .../gc/shenandoah/shenandoahControlThread.hpp | 59 ++------- .../gc/shenandoah/shenandoahController.cpp | 112 ++++++++++++++++++ .../gc/shenandoah/shenandoahController.hpp | 105 ++++++++++++++++ .../share/gc/shenandoah/shenandoahHeap.cpp | 2 +- 5 files changed, 236 insertions(+), 141 deletions(-) create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahController.cpp create mode 100644 src/hotspot/share/gc/shenandoah/shenandoahController.hpp diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index bdf1e5b9128..4f711350844 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -35,25 +35,21 @@ #include "gc/shenandoah/shenandoahPacer.inline.hpp" #include "gc/shenandoah/shenandoahUtils.hpp" #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "gc/shenandoah/mode/shenandoahMode.hpp" +#include "logging/log.hpp" #include "memory/metaspaceUtils.hpp" #include "memory/metaspaceStats.hpp" -#include "memory/resourceArea.hpp" -#include "runtime/atomic.hpp" ShenandoahControlThread::ShenandoahControlThread() : - ConcurrentGCThread(), - _alloc_failure_waiters_lock(Mutex::safepoint-2, "ShenandoahAllocFailureGC_lock", true), - _gc_waiters_lock(Mutex::safepoint-2, "ShenandoahRequestedGC_lock", true), + ShenandoahController(), _requested_gc_cause(GCCause::_no_cause_specified), - _degen_point(ShenandoahGC::_degenerated_outside_cycle), - _allocs_seen(0) { + _degen_point(ShenandoahGC::_degenerated_outside_cycle) { set_name("Shenandoah Control Thread"); - reset_gc_id(); create_and_start(); } void ShenandoahControlThread::run_service() { - ShenandoahHeap* heap = ShenandoahHeap::heap(); + ShenandoahHeap* const heap = ShenandoahHeap::heap(); const GCMode default_mode = concurrent_normal; const GCCause::Cause default_cause = GCCause::_shenandoah_concurrent_gc; @@ -77,7 +73,7 @@ void ShenandoahControlThread::run_service() { const GCCause::Cause requested_gc_cause = _requested_gc_cause; // This control loop iteration has seen this much allocation. - const size_t allocs_seen = Atomic::xchg(&_allocs_seen, (size_t)0, memory_order_relaxed); + const size_t allocs_seen = reset_allocs_seen(); // Check if we have seen a new target for soft max heap size. const bool soft_max_changed = heap->check_soft_max_changed(); @@ -106,7 +102,6 @@ void ShenandoahControlThread::run_service() { policy->record_alloc_failure_to_full(); mode = stw_full; } - } else if (is_gc_requested) { cause = requested_gc_cause; log_info(gc)("Trigger: GC request (%s)", GCCause::to_string(cause)); @@ -239,7 +234,7 @@ void ShenandoahControlThread::run_service() { heap->pacer()->setup_for_idle(); } } else { - // Allow allocators to know we have seen this much regions + // Report to pacer that we have seen this many words allocated if (ShenandoahPacing && (allocs_seen > 0)) { heap->pacer()->report_alloc(allocs_seen); } @@ -407,88 +402,8 @@ void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { } } -void ShenandoahControlThread::handle_alloc_failure(ShenandoahAllocRequest& req, bool block) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); - - assert(current()->is_Java_thread(), "expect Java thread here"); - - if (try_set_alloc_failure_gc()) { - // Only report the first allocation failure - log_info(gc)("Failed to allocate %s, " SIZE_FORMAT "%s", - req.type_string(), - byte_size_in_proper_unit(req.size() * HeapWordSize), proper_unit_for_byte_size(req.size() * HeapWordSize)); - - // Now that alloc failure GC is scheduled, we can abort everything else - heap->cancel_gc(GCCause::_allocation_failure); - } - - - if (block) { - MonitorLocker ml(&_alloc_failure_waiters_lock); - while (is_alloc_failure_gc()) { - ml.wait(); - } - } -} - -void ShenandoahControlThread::handle_alloc_failure_evac(size_t words) { - ShenandoahHeap* heap = ShenandoahHeap::heap(); - - if (try_set_alloc_failure_gc()) { - // Only report the first allocation failure - log_info(gc)("Failed to allocate " SIZE_FORMAT "%s for evacuation", - byte_size_in_proper_unit(words * HeapWordSize), proper_unit_for_byte_size(words * HeapWordSize)); - } - - // Forcefully report allocation failure - heap->cancel_gc(GCCause::_shenandoah_allocation_failure_evac); -} - -void ShenandoahControlThread::notify_alloc_failure_waiters() { - _alloc_failure_gc.unset(); - MonitorLocker ml(&_alloc_failure_waiters_lock); - ml.notify_all(); -} - -bool ShenandoahControlThread::try_set_alloc_failure_gc() { - return _alloc_failure_gc.try_set(); -} - -bool ShenandoahControlThread::is_alloc_failure_gc() { - return _alloc_failure_gc.is_set(); -} - void ShenandoahControlThread::notify_gc_waiters() { _gc_requested.unset(); MonitorLocker ml(&_gc_waiters_lock); ml.notify_all(); } - -void ShenandoahControlThread::pacing_notify_alloc(size_t words) { - assert(ShenandoahPacing, "should only call when pacing is enabled"); - Atomic::add(&_allocs_seen, words, memory_order_relaxed); -} - -void ShenandoahControlThread::reset_gc_id() { - Atomic::store(&_gc_id, (size_t)0); -} - -void ShenandoahControlThread::update_gc_id() { - Atomic::inc(&_gc_id); -} - -size_t ShenandoahControlThread::get_gc_id() { - return Atomic::load(&_gc_id); -} - -void ShenandoahControlThread::start() { - create_and_start(); -} - -void ShenandoahControlThread::prepare_for_graceful_shutdown() { - _graceful_shutdown.set(); -} - -bool ShenandoahControlThread::in_graceful_shutdown() { - return _graceful_shutdown.is_set(); -} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp index 9da25b1a73c..be99ef1d865 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.hpp @@ -28,10 +28,11 @@ #include "gc/shared/gcCause.hpp" #include "gc/shared/concurrentGCThread.hpp" #include "gc/shenandoah/shenandoahGC.hpp" +#include "gc/shenandoah/shenandoahController.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" #include "gc/shenandoah/shenandoahSharedVariables.hpp" -class ShenandoahControlThread: public ConcurrentGCThread { +class ShenandoahControlThread: public ShenandoahController { friend class VMStructs; private: @@ -42,68 +43,30 @@ class ShenandoahControlThread: public ConcurrentGCThread { stw_full } GCMode; - // While we could have a single lock for these, it may risk unblocking - // GC waiters when alloc failure GC cycle finishes. We want instead - // to make complete explicit cycle for for demanding customers. - Monitor _alloc_failure_waiters_lock; - Monitor _gc_waiters_lock; - -public: - void run_service(); - void stop_service(); - -private: ShenandoahSharedFlag _gc_requested; - ShenandoahSharedFlag _alloc_failure_gc; - ShenandoahSharedFlag _graceful_shutdown; GCCause::Cause _requested_gc_cause; ShenandoahGC::ShenandoahDegenPoint _degen_point; - shenandoah_padding(0); - volatile size_t _allocs_seen; - shenandoah_padding(1); - volatile size_t _gc_id; - shenandoah_padding(2); +public: + ShenandoahControlThread(); + + void run_service() override; + void stop_service() override; + + void request_gc(GCCause::Cause cause) override; + +private: bool check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point); void service_concurrent_normal_cycle(GCCause::Cause cause); void service_stw_full_cycle(GCCause::Cause cause); void service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point); - bool try_set_alloc_failure_gc(); - void notify_alloc_failure_waiters(); - bool is_alloc_failure_gc(); - - void reset_gc_id(); - void update_gc_id(); - size_t get_gc_id(); - void notify_gc_waiters(); // Handle GC request. // Blocks until GC is over. void handle_requested_gc(GCCause::Cause cause); - -public: - // Constructor - ShenandoahControlThread(); - - // Handle allocation failure from a mutator allocation. - // Optionally blocks while collector is handling the failure. If the GC - // threshold has been exceeded, the mutator allocation will not block so - // that the out of memory error can be raised promptly. - void handle_alloc_failure(ShenandoahAllocRequest& req, bool block = true); - - // Handle allocation failure from evacuation path. - void handle_alloc_failure_evac(size_t words); - - void request_gc(GCCause::Cause cause); - - void pacing_notify_alloc(size_t words); - - void start(); - void prepare_for_graceful_shutdown(); - bool in_graceful_shutdown(); }; #endif // SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLTHREAD_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.cpp b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp new file mode 100644 index 00000000000..6d6d21c4066 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.cpp @@ -0,0 +1,112 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ +#include "precompiled.hpp" + +#include "gc/shared/gc_globals.hpp" +#include "gc/shenandoah/shenandoahController.hpp" +#include "gc/shenandoah/shenandoahHeap.hpp" +#include "gc/shenandoah/shenandoahHeapRegion.inline.hpp" + +void ShenandoahController::pacing_notify_alloc(size_t words) { + assert(ShenandoahPacing, "should only call when pacing is enabled"); + Atomic::add(&_allocs_seen, words, memory_order_relaxed); +} + +size_t ShenandoahController::reset_allocs_seen() { + return Atomic::xchg(&_allocs_seen, (size_t)0, memory_order_relaxed); +} + +void ShenandoahController::prepare_for_graceful_shutdown() { + _graceful_shutdown.set(); +} + +bool ShenandoahController::in_graceful_shutdown() { + return _graceful_shutdown.is_set(); +} + +void ShenandoahController::update_gc_id() { + Atomic::inc(&_gc_id); +} + +size_t ShenandoahController::get_gc_id() { + return Atomic::load(&_gc_id); +} + +void ShenandoahController::handle_alloc_failure(ShenandoahAllocRequest& req, bool block) { + ShenandoahHeap* heap = ShenandoahHeap::heap(); + + assert(current()->is_Java_thread(), "expect Java thread here"); + bool is_humongous = req.size() > ShenandoahHeapRegion::humongous_threshold_words(); + + if (try_set_alloc_failure_gc(is_humongous)) { + // Only report the first allocation failure + log_info(gc)("Failed to allocate %s, " SIZE_FORMAT "%s", + req.type_string(), + byte_size_in_proper_unit(req.size() * HeapWordSize), proper_unit_for_byte_size(req.size() * HeapWordSize)); + + // Now that alloc failure GC is scheduled, we can abort everything else + heap->cancel_gc(GCCause::_allocation_failure); + } + + + if (block) { + MonitorLocker ml(&_alloc_failure_waiters_lock); + while (is_alloc_failure_gc()) { + ml.wait(); + } + } +} + +void ShenandoahController::handle_alloc_failure_evac(size_t words) { + ShenandoahHeap* heap = ShenandoahHeap::heap(); + bool is_humongous = (words > ShenandoahHeapRegion::region_size_words()); + + if (try_set_alloc_failure_gc(is_humongous)) { + // Only report the first allocation failure + log_info(gc)("Failed to allocate " SIZE_FORMAT "%s for evacuation", + byte_size_in_proper_unit(words * HeapWordSize), proper_unit_for_byte_size(words * HeapWordSize)); + } + + // Forcefully report allocation failure + heap->cancel_gc(GCCause::_shenandoah_allocation_failure_evac); +} + +void ShenandoahController::notify_alloc_failure_waiters() { + _alloc_failure_gc.unset(); + _humongous_alloc_failure_gc.unset(); + MonitorLocker ml(&_alloc_failure_waiters_lock); + ml.notify_all(); +} + +bool ShenandoahController::try_set_alloc_failure_gc(bool is_humongous) { + if (is_humongous) { + _humongous_alloc_failure_gc.try_set(); + } + return _alloc_failure_gc.try_set(); +} + +bool ShenandoahController::is_alloc_failure_gc() { + return _alloc_failure_gc.is_set(); +} + diff --git a/src/hotspot/share/gc/shenandoah/shenandoahController.hpp b/src/hotspot/share/gc/shenandoah/shenandoahController.hpp new file mode 100644 index 00000000000..2808f30b444 --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahController.hpp @@ -0,0 +1,105 @@ +/* + * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP +#define LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP + +#include "gc/shared/gcCause.hpp" +#include "gc/shared/concurrentGCThread.hpp" +#include "gc/shenandoah/shenandoahAllocRequest.hpp" +#include "gc/shenandoah/shenandoahSharedVariables.hpp" + +/** + * This interface exposes methods necessary for the heap to interact + * with the threads responsible for driving the collection cycle. + */ +class ShenandoahController: public ConcurrentGCThread { +private: + ShenandoahSharedFlag _graceful_shutdown; + + shenandoah_padding(0); + volatile size_t _allocs_seen; + shenandoah_padding(1); + volatile size_t _gc_id; + shenandoah_padding(2); + +protected: + ShenandoahSharedFlag _alloc_failure_gc; + ShenandoahSharedFlag _humongous_alloc_failure_gc; + + // While we could have a single lock for these, it may risk unblocking + // GC waiters when alloc failure GC cycle finishes. We want instead + // to make complete explicit cycle for demanding customers. + Monitor _alloc_failure_waiters_lock; + Monitor _gc_waiters_lock; + +public: + ShenandoahController(): + ConcurrentGCThread(), + _allocs_seen(0), + _gc_id(0), + _alloc_failure_waiters_lock(Mutex::safepoint-2, "ShenandoahAllocFailureGC_lock", true), + _gc_waiters_lock(Mutex::safepoint-2, "ShenandoahRequestedGC_lock", true) + { } + + // Request a collection cycle. This handles "explicit" gc requests + // like System.gc and "implicit" gc requests, like metaspace oom. + virtual void request_gc(GCCause::Cause cause) = 0; + + // This cancels the collection cycle and has an option to block + // until another cycle runs and clears the alloc failure gc flag. + void handle_alloc_failure(ShenandoahAllocRequest& req, bool block); + + // Invoked for allocation failures during evacuation. This cancels + // the collection cycle without blocking. + void handle_alloc_failure_evac(size_t words); + + // Return true if setting the flag which indicates allocation failure succeeds. + bool try_set_alloc_failure_gc(bool is_humongous); + + // Notify threads waiting for GC to complete. + void notify_alloc_failure_waiters(); + + // True if allocation failure flag has been set. + bool is_alloc_failure_gc(); + + // This is called for every allocation. The control thread accumulates + // this value when idle. During the gc cycle, the control resets it + // and reports it to the pacer. + void pacing_notify_alloc(size_t words); + size_t reset_allocs_seen(); + + // These essentially allows to cancel a collection cycle for the + // purpose of shutting down the JVM, without trying to start a degenerated + // cycle. + void prepare_for_graceful_shutdown(); + bool in_graceful_shutdown(); + + + // Returns the internal gc count used by the control thread. Probably + // doesn't need to be exposed. + size_t get_gc_id(); + void update_gc_id(); +}; +#endif //LINUX_X86_64_SERVER_SLOWDEBUG_SHENANDOAHCONTROLLER_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index f270e16f53e..ee3f4e7d8eb 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -955,7 +955,7 @@ HeapWord* ShenandoahHeap::allocate_memory(ShenandoahAllocRequest& req) { size_t original_count = shenandoah_policy()->full_gc_count(); while (result == nullptr && (get_gc_no_progress_count() == 0 || original_count == shenandoah_policy()->full_gc_count())) { - control_thread()->handle_alloc_failure(req); + control_thread()->handle_alloc_failure(req, true); result = allocate_memory_under_lock(req, in_new_region); } From 253508b03a3de4dab00ed7fb57e9f345d8aed1a4 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Fri, 24 May 2024 19:31:20 +0000 Subject: [PATCH 40/99] 8332303: Better JMX interoperability with older JDKs, after removing Subject Delegation Reviewed-by: dfuchs, cjplummer --- .../management/remote/rmi/RMIConnection.java | 9 +++++---- .../remote/rmi/RMIConnectionImpl.java | 18 +++++++++++------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java index 5ce708ed43a..37b43b189eb 100644 --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java @@ -956,7 +956,8 @@ public void removeNotificationListener(ObjectName name, * @param filters an array of marshalled representations of the * NotificationFilters. Elements of this array can * be null. - * @param delegationSubjects must be {@code null}. + * @param delegationSubjects must be {@code null}, or an array + * which does not contain any non-null entries. * * @return an array of listenerIDs identifying the * local listeners. This array has the same number of elements as @@ -964,8 +965,7 @@ public void removeNotificationListener(ObjectName name, * * @throws IllegalArgumentException if names or * filters is null, or if names contains - * a null element, or if the three arrays do not all have the same - * size. + * a null element, or if these two arrays do not have the same size. * @throws ClassCastException if one of the elements of * filters unmarshalls as a non-null object that is * not a NotificationFilter. @@ -974,7 +974,8 @@ public void removeNotificationListener(ObjectName name, * @throws SecurityException if, for one of the MBeans, the * client does not have permission to add a listener. * @throws IOException if a general communication exception occurred. - * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. + * @throws UnsupportedOperationException if {@code delegationSubjects} + * is non-null and contains any non-null entries. */ public Integer[] addNotificationListeners(ObjectName[] names, MarshalledObject[] filters, diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java index 6b901ea2638..289bc8f3822 100644 --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java @@ -971,13 +971,17 @@ public Integer[] addNotificationListeners(ObjectName[] names, if (names == null || filters == null) { throw new IllegalArgumentException("Got null arguments."); } + // Accept an array of delegationSubjects from e.g. earlier JDKs, + // but throw if it contains any non-null values. if (delegationSubjects != null) { - throw new UnsupportedOperationException("Subject Delegation has been removed."); + for (Subject s: delegationSubjects) { + if (s != null) { + throw new UnsupportedOperationException("Subject Delegation has been removed."); + } + } } - Subject[] sbjs = new Subject[names.length]; - if (names.length != filters.length || filters.length != sbjs.length) { - final String msg = - "The value lengths of 3 parameters are not same."; + if (names.length != filters.length) { + final String msg = "The lengths of names and filters parameters are not same."; throw new IllegalArgumentException(msg); } @@ -1005,7 +1009,7 @@ public Integer[] addNotificationListeners(ObjectName[] names, filterValues[i] = unwrap(filters[i], targetCl, defaultClassLoader, - NotificationFilter.class, sbjs[i]); + NotificationFilter.class, null); if (debug) logger.debug("addNotificationListener"+ "(ObjectName,NotificationFilter)", @@ -1017,7 +1021,7 @@ public Integer[] addNotificationListeners(ObjectName[] names, doPrivilegedOperation(ADD_NOTIFICATION_LISTENERS, new Object[] { names[i], filterValues[i] }, - sbjs[i]); + null); } return ids; From 7bf1989f59695c3d08b4bd116fb4c022cf9661f4 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Fri, 24 May 2024 20:43:23 +0000 Subject: [PATCH 41/99] 8320575: generic type information lost on mandated parameters of record's compact constructors Co-authored-by: Chen Liang Reviewed-by: jlahoda --- .../classes/java/lang/reflect/Executable.java | 85 ++++-- test/jdk/java/lang/reflect/records/R10.jcod | 262 ++++++++++++++++++ .../reflect/records/RecordReflectionTest.java | 81 +++++- 3 files changed, 399 insertions(+), 29 deletions(-) create mode 100644 test/jdk/java/lang/reflect/records/R10.jcod diff --git a/src/java.base/share/classes/java/lang/reflect/Executable.java b/src/java.base/share/classes/java/lang/reflect/Executable.java index 420be5029b0..b808e052fb2 100644 --- a/src/java.base/share/classes/java/lang/reflect/Executable.java +++ b/src/java.base/share/classes/java/lang/reflect/Executable.java @@ -255,12 +255,17 @@ public Set accessFlags() { * represented by this object. Returns an array of length * 0 if the underlying executable takes no parameters. * Note that the constructors of some inner classes - * may have an implicitly declared parameter in addition to - * explicitly declared ones. + * may have an {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED + * implicitly declared} parameter in addition to explicitly + * declared ones. + * Also note that compact constructors of a record class may have + * {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED + * implicitly declared} parameters. * * @return the parameter types for the executable this object * represents */ + @SuppressWarnings("doclint:reference") // cross-module links public abstract Class[] getParameterTypes(); /** @@ -280,18 +285,32 @@ public Set accessFlags() { * underlying executable takes no parameters. Note that the * constructors of some inner classes may have an implicitly * declared parameter in addition to explicitly declared ones. - * Also note that as a
    modeling - * artifact, the number of returned parameters can differ + * Compact constructors of a record class may also have + * {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED + * implicitly declared} parameters, + * but they are a special case and thus considered as if they had + * been explicitly declared in the source. + * Finally note that as a {@link java.lang.reflect##LanguageJvmModel + * modeling artifact}, the number of returned parameters can differ * depending on whether or not generic information is present. If - * generic information is present, only parameters explicitly - * present in the source will be returned; if generic information - * is not present, implicit and synthetic parameters may be + * generic information is present, parameters explicitly + * present in the source or parameters of compact constructors + * of a record class will be returned. + * Note that parameters of compact constructors of a record class are a special case, + * as they are not explicitly present in the source, and its type will be returned + * regardless of the parameters being + * {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED + * implicitly declared} or not. + * If generic information is not present, implicit and synthetic parameters may be * returned as well. * *

    If a formal parameter type is a parameterized type, * the {@code Type} object returned for it must accurately reflect - * the actual type arguments used in the source code. + * the actual type arguments used in the source code. This assertion also + * applies to the parameters of compact constructors of a record class, + * independently of them being + * {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED + * implicitly declared} or not. * *

    If a formal parameter type is a type variable or a parameterized * type, it is created. Otherwise, it is resolved. @@ -309,6 +328,7 @@ public Set accessFlags() { * the underlying executable's parameter types refer to a parameterized * type that cannot be instantiated for any reason */ + @SuppressWarnings("doclint:reference") // cross-module links public Type[] getGenericParameterTypes() { if (hasGenericInformation()) return getGenericInfo().getParameterTypes(); @@ -335,22 +355,34 @@ Type[] getAllGenericParameterTypes() { // If we have real parameter data, then we use the // synthetic and mandate flags to our advantage. if (realParamData) { - final Type[] out = new Type[nonGenericParamTypes.length]; - final Parameter[] params = getParameters(); - int fromidx = 0; - for (int i = 0; i < out.length; i++) { - final Parameter param = params[i]; - if (param.isSynthetic() || param.isImplicit()) { - // If we hit a synthetic or mandated parameter, - // use the non generic parameter info. - out[i] = nonGenericParamTypes[i]; + if (getDeclaringClass().isRecord() && this instanceof Constructor) { + /* we could be seeing a compact constructor of a record class + * its parameters are mandated but we should be able to retrieve + * its generic information if present + */ + if (genericParamTypes.length == nonGenericParamTypes.length) { + return genericParamTypes; } else { - // Otherwise, use the generic parameter info. - out[i] = genericParamTypes[fromidx]; - fromidx++; + return nonGenericParamTypes.clone(); } + } else { + final Type[] out = new Type[nonGenericParamTypes.length]; + final Parameter[] params = getParameters(); + int fromidx = 0; + for (int i = 0; i < out.length; i++) { + final Parameter param = params[i]; + if (param.isSynthetic() || param.isImplicit()) { + // If we hit a synthetic or mandated parameter, + // use the non generic parameter info. + out[i] = nonGenericParamTypes[i]; + } else { + // Otherwise, use the generic parameter info. + out[i] = genericParamTypes[fromidx]; + fromidx++; + } + } + return out; } - return out; } else { // Otherwise, use the non-generic parameter data. // Without method parameter reflection data, we have @@ -748,13 +780,18 @@ Type parameterize(Class c) { * Returns an array of length 0 if the method/constructor declares no * parameters. * Note that the constructors of some inner classes - * may have an implicitly declared parameter in addition to - * explicitly declared ones. + * may have an + * {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED + * implicitly declared} parameter in addition to explicitly declared ones. + * Also note that compact constructors of a record class may have + * {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED + * implicitly declared} parameters. * * @return an array of objects representing the types of the * formal parameters of the method or constructor represented by this * {@code Executable} */ + @SuppressWarnings("doclint:reference") // cross-module links public AnnotatedType[] getAnnotatedParameterTypes() { return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(), SharedSecrets.getJavaLangAccess(). diff --git a/test/jdk/java/lang/reflect/records/R10.jcod b/test/jdk/java/lang/reflect/records/R10.jcod new file mode 100644 index 00000000000..037699f5d1b --- /dev/null +++ b/test/jdk/java/lang/reflect/records/R10.jcod @@ -0,0 +1,262 @@ +// this record is defined as: +// record R10(List ls) { // there is no compact constructor and thus there is no mandated param +// } +class R10 { + 0xCAFEBABE; + 0; // minor version + 64; // version + [] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 + class #4; // #2 + NameAndType #5 #6; // #3 + Utf8 "java/lang/Record"; // #4 + Utf8 ""; // #5 + Utf8 "()V"; // #6 + Field #8 #9; // #7 + class #10; // #8 + NameAndType #11 #12; // #9 + Utf8 "R10"; // #10 + Utf8 "ls"; // #11 + Utf8 "Ljava/util/List;"; // #12 + InvokeDynamic 0s #14; // #13 + NameAndType #15 #16; // #14 + Utf8 "toString"; // #15 + Utf8 "(LR10;)Ljava/lang/String;"; // #16 + InvokeDynamic 0s #18; // #17 + NameAndType #19 #20; // #18 + Utf8 "hashCode"; // #19 + Utf8 "(LR10;)I"; // #20 + InvokeDynamic 0s #22; // #21 + NameAndType #23 #24; // #22 + Utf8 "equals"; // #23 + Utf8 "(LR10;Ljava/lang/Object;)Z"; // #24 + Utf8 "Signature"; // #25 + Utf8 "Ljava/util/List;"; // #26 + Utf8 "(Ljava/util/List;)V"; // #27 + Utf8 "Code"; // #28 + Utf8 "LineNumberTable"; // #29 + Utf8 "MethodParameters"; // #30 + Utf8 "(Ljava/util/List;)V"; // #31 + Utf8 "()Ljava/lang/String;"; // #32 + Utf8 "()I"; // #33 + Utf8 "(Ljava/lang/Object;)Z"; // #34 + Utf8 "()Ljava/util/List;"; // #35 + Utf8 "()Ljava/util/List;"; // #36 + Utf8 "SourceFile"; // #37 + Utf8 "R10.java"; // #38 + Utf8 "Record"; // #39 + Utf8 "BootstrapMethods"; // #40 + MethodHandle 6b #42; // #41 + Method #43 #44; // #42 + class #45; // #43 + NameAndType #46 #47; // #44 + Utf8 "java/lang/runtime/ObjectMethods"; // #45 + Utf8 "bootstrap"; // #46 + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;"; // #47 + String #11; // #48 + MethodHandle 1b #7; // #49 + Utf8 "InnerClasses"; // #50 + class #52; // #51 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #52 + class #54; // #53 + Utf8 "java/lang/invoke/MethodHandles"; // #54 + Utf8 "Lookup"; // #55 + } // Constant Pool + + 0x0030; // access + #8;// this_cpx + #2;// super_cpx + + [] { // Interfaces + } // Interfaces + + [] { // Fields + { // field + 0x0012; // access + #11; // name_index + #12; // descriptor_index + [] { // Attributes + Attr(#25) { // Signature + #26; + } // end Signature + } // Attributes + } + } // Fields + + [] { // Methods + { // method + 0x0000; // access + #5; // name_index + #27; // descriptor_index + [] { // Attributes + Attr(#28) { // Code + 2; // max_stack + 2; // max_locals + Bytes[]{ + 0x2AB700012A2BB500; + 0x07B1; + } + [] { // Traps + } // end Traps + [] { // Attributes + Attr(#29) { // LineNumberTable + [] { // line_number_table + 0 4; + } + } // end LineNumberTable + } // Attributes + } // end Code + ; + Attr(#30) { // MethodParameters + []b { // MethodParameters + #11 0x0000; // the parameter is not mandated, flag should be 0x8000 for it to be mandated + } + } // end MethodParameters + ; + Attr(#25) { // Signature + #31; + } // end Signature + } // Attributes + } + ; + { // method + 0x0011; // access + #15; // name_index + #32; // descriptor_index + [] { // Attributes + Attr(#28) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2ABA000D0000B0; + } + [] { // Traps + } // end Traps + [] { // Attributes + Attr(#29) { // LineNumberTable + [] { // line_number_table + 0 3; + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } + ; + { // method + 0x0011; // access + #19; // name_index + #33; // descriptor_index + [] { // Attributes + Attr(#28) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2ABA00110000AC; + } + [] { // Traps + } // end Traps + [] { // Attributes + Attr(#29) { // LineNumberTable + [] { // line_number_table + 0 3; + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } + ; + { // method + 0x0011; // access + #23; // name_index + #34; // descriptor_index + [] { // Attributes + Attr(#28) { // Code + 2; // max_stack + 2; // max_locals + Bytes[]{ + 0x2A2BBA00150000AC; + } + [] { // Traps + } // end Traps + [] { // Attributes + Attr(#29) { // LineNumberTable + [] { // line_number_table + 0 3; + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } + ; + { // method + 0x0001; // access + #11; // name_index + #35; // descriptor_index + [] { // Attributes + Attr(#28) { // Code + 1; // max_stack + 1; // max_locals + Bytes[]{ + 0x2AB40007B0; + } + [] { // Traps + } // end Traps + [] { // Attributes + Attr(#29) { // LineNumberTable + [] { // line_number_table + 0 3; + } + } // end LineNumberTable + } // Attributes + } // end Code + ; + Attr(#25) { // Signature + #36; + } // end Signature + } // Attributes + } + } // Methods + + [] { // Attributes + Attr(#37) { // SourceFile + #38; + } // end SourceFile + ; + Attr(#39) { // Record + [] { // components + { // component + #11; // name_index + #12; // descriptor_index + [] { // Attributes + Attr(#25) { // Signature + #26; + } // end Signature + } // Attributes + } + } + } // end Record + ; + Attr(#40) { // BootstrapMethods + [] { // bootstrap_methods + { // bootstrap_method + #41; // bootstrap_method_ref + [] { // bootstrap_arguments + #8; + #48; + #49; + } // bootstrap_arguments + } // bootstrap_method + } + } // end BootstrapMethods + ; + Attr(#50) { // InnerClasses + [] { // classes + #51 #53 #55 25; + } + } // end InnerClasses + } // Attributes +} // end class R10 diff --git a/test/jdk/java/lang/reflect/records/RecordReflectionTest.java b/test/jdk/java/lang/reflect/records/RecordReflectionTest.java index 23b707663a9..18a3b02f687 100644 --- a/test/jdk/java/lang/reflect/records/RecordReflectionTest.java +++ b/test/jdk/java/lang/reflect/records/RecordReflectionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, 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 @@ -23,8 +23,9 @@ /* * @test - * @bug 8235369 8235550 8247444 + * @bug 8235369 8235550 8247444 8320575 * @summary reflection test for records + * @build R10 * @compile RecordReflectionTest.java * @run testng/othervm RecordReflectionTest * @run testng/othervm/java.security.policy=allPermissions.policy RecordReflectionTest @@ -57,6 +58,27 @@ record R7(String s1, String s2, String... args) {} record R8(A a, B b) implements java.io.Serializable { } + record R9(List ls) { + R9 {} // compact constructor, will contain a mandated parameter + } + + /* record R10 is defined in an accompaning jcod file, defined as: + record R10(List ls) { // in this case there wasn't be any compact constructor and thus no mandated param + } + */ + + record R11(int i, List ls) { + R11 {} // compact constructor, will contain mandated parameters + } + + record R12(List ls, int i) { + R12 {} // compact constructor, will contain mandated parameters + } + + record R13(List ls1, int i, List ls2) { + R13 {} // compact constructor, will contain mandated parameters + } + @DataProvider(name = "recordClasses") public Object[][] recordClassData() { return List.of(R1.class, @@ -66,8 +88,13 @@ public Object[][] recordClassData() { R5.class, R6.class, R7.class, - R8.class) - .stream().map(c -> new Object[] {c}).toArray(Object[][]::new); + R8.class, + R9.class, + R10.class, + R11.class, + R12.class, + R13.class + ).stream().map(c -> new Object[] {c}).toArray(Object[][]::new); } @Test(dataProvider = "recordClasses") @@ -124,6 +151,34 @@ public Object[][] reflectionData() { new Object[]{ new R1(), new R2(6, 7), new R3(List.of("s")) }, new String[]{ "r1", "r2", "r3" }, new String[]{ R1.class.toString(), R2.class.toString(), R3.class.toString()} }, + new Object[] { new R9(List.of("1")), + 1, + new Object[]{ List.of("1") }, + new String[]{ "ls" }, + new String[]{ "java.util.List"} }, + /* R10 has exactly the same definition as R9 but the parameter of the compact constructor doesn't have + * the mandated flag, nevertheless we should be able to load the same generic information + */ + new Object[] { new R10(List.of("1")), + 1, + new Object[]{ List.of("1") }, + new String[]{ "ls" }, + new String[]{ "java.util.List"} }, + new Object[] { new R11(1, List.of("1")), + 2, + new Object[]{ 1, List.of("1") }, + new String[]{ "i", "ls" }, + new String[]{ "int", "java.util.List"} }, + new Object[] { new R12(List.of("1"), 1), + 2, + new Object[]{ List.of("1"), 1 }, + new String[]{ "ls", "i" }, + new String[]{ "java.util.List", "int"} }, + new Object[] { new R13(List.of("1"), 1, List.of("2")), + 3, + new Object[]{ List.of("1"), 1, List.of("2") }, + new String[]{ "ls1", "i", "ls2" }, + new String[]{ "java.util.List", "int", "java.util.List"} }, }; } @@ -149,6 +204,23 @@ public void testRecordReflection(Object recordOb, rc.getAccessor().getGenericReturnType(), signatures[i])); i++; } + // now let's check constructors + var constructor = recordClass.getDeclaredConstructors()[0]; + i = 0; + for (var p: constructor.getParameters()) { + assertEquals(p.getParameterizedType().toString(), signatures[i], + String.format("signature of method \"%s\" different from expected signature \"%s\"", + p.getType().toString(), signatures[i])); + i++; + } + // similar as above but testing another API + i = 0; + for (var p : constructor.getGenericParameterTypes()) { + assertEquals(p.toString(), signatures[i], + String.format("signature of method \"%s\" different from expected signature \"%s\"", + p.toString(), signatures[i])); + i++; + } } @Retention(RetentionPolicy.RUNTIME) @@ -201,5 +273,4 @@ public void testReadOnlyFieldInRecord() throws Throwable { } catch (IllegalAccessException e) { } } - } From 05f13e75ee4407ba9213c69b33c6032aa87c9e95 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Sat, 25 May 2024 00:35:56 +0000 Subject: [PATCH 42/99] 8329667: [macos] Issue with JTree related fix for JDK-8317771 Reviewed-by: asemenov, abhiscxk, psadhukhan --- .../sun/lwawt/macosx/CAccessibility.java | 77 +++------------- .../awt/a11y/OutlineAccessibility.h | 11 ++- .../awt/a11y/OutlineAccessibility.m | 88 ++++++++++++++++++- 3 files changed, 104 insertions(+), 72 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java index d4526324c58..2da02e34b45 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,10 +36,11 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.annotation.Native; -import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.concurrent.Callable; import java.util.Arrays; @@ -64,7 +65,6 @@ import javax.swing.JList; import javax.swing.JTree; import javax.swing.KeyStroke; -import javax.swing.tree.TreePath; import sun.awt.AWTAccessor; import sun.lwawt.LWWindowPeer; @@ -759,21 +759,6 @@ private static Object[] getChildrenAndRolesImpl(Accessible a, Component c, int w return new Object[]{childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1)}; } - private static Accessible createAccessibleTreeNode(JTree t, TreePath p) { - Accessible a = null; - - try { - Class accessibleJTreeNodeClass = Class.forName("javax.swing.JTree$AccessibleJTree$AccessibleJTreeNode"); - Constructor constructor = accessibleJTreeNodeClass.getConstructor(t.getAccessibleContext().getClass(), JTree.class, TreePath.class, Accessible.class); - constructor.setAccessible(true); - a = ((Accessible) constructor.newInstance(t.getAccessibleContext(), t, p, null)); - } catch (Exception e) { - e.printStackTrace(); - } - - return a; - } - // This method is called from the native // Each child takes up three entries in the array: one for itself, one for its role, and one for the recursion level private static Object[] getChildrenAndRolesRecursive(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored, final int level) { @@ -781,62 +766,21 @@ private static Object[] getChildrenAndRolesRecursive(final Accessible a, final C return invokeAndWait(new Callable() { public Object[] call() throws Exception { ArrayList allChildren = new ArrayList(); - - Accessible at = null; - if (a instanceof CAccessible) { - at = CAccessible.getSwingAccessible(a); - } else { - at = a; - } - - if (at instanceof JTree) { - JTree tree = ((JTree) at); - - if (whichChildren == JAVA_AX_ALL_CHILDREN) { - int count = tree.getRowCount(); - for (int i = 0; i < count; i++) { - TreePath path = tree.getPathForRow(i); - Accessible an = createAccessibleTreeNode(tree, path); - if (an != null) { - AccessibleContext ac = an.getAccessibleContext(); - if (ac != null) { - allChildren.add(an); - allChildren.add(ac.getAccessibleRole());; - allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1))); - } - } - } - } - - if (whichChildren == JAVA_AX_SELECTED_CHILDREN) { - int count = tree.getSelectionCount(); - for (int i = 0; i < count; i++) { - TreePath path = tree.getSelectionPaths()[i]; - Accessible an = createAccessibleTreeNode(tree, path); - if (an != null) { - AccessibleContext ac = an.getAccessibleContext(); - if (ac != null) { - allChildren.add(an); - allChildren.add(ac.getAccessibleRole()); - allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1))); - } - } - } - } - - return allChildren.toArray(); - } - ArrayList currentLevelChildren = new ArrayList(); ArrayList parentStack = new ArrayList(); + HashMap> childrenOfParent = new HashMap<>(); parentStack.add(a); ArrayList indexses = new ArrayList(); Integer index = 0; int currentLevel = level; while (!parentStack.isEmpty()) { Accessible p = parentStack.get(parentStack.size() - 1); - - currentLevelChildren.addAll(Arrays.asList(getChildrenAndRolesImpl(p, c, JAVA_AX_ALL_CHILDREN, allowIgnored, ChildrenOperations.COMMON))); + if (!childrenOfParent.containsKey(p)) { + childrenOfParent.put(p, Arrays.asList(getChildrenAndRolesImpl(p, + c, JAVA_AX_ALL_CHILDREN, allowIgnored, + ChildrenOperations.COMMON))); + } + currentLevelChildren.addAll(childrenOfParent.get(p)); if ((currentLevelChildren.size() == 0) || (index >= currentLevelChildren.size())) { if (!parentStack.isEmpty()) parentStack.remove(parentStack.size() - 1); if (!indexses.isEmpty()) index = indexses.remove(indexses.size() - 1); @@ -879,7 +823,6 @@ public Object[] call() throws Exception { currentLevel += 1; continue; } - } return allChildren.toArray(); diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h index 2992d82cbe4..8281f0b0213 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, JetBrains s.r.o.. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,12 @@ // This is a tree representation. See: https://developer.apple.com/documentation/appkit/nsoutlineview @interface OutlineAccessibility : ListAccessibility - +{ + NSMutableArray> *rowCache; + BOOL rowCacheValid; + NSMutableArray> *selectedRowCache; + BOOL selectedRowCacheValid; +} @property(readonly) BOOL isTreeRootVisible; @end diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m index cdf6dbbd4ab..08240614bf7 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, JetBrains s.r.o.. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,4 +55,88 @@ - (NSString *)accessibilityLabel return [[super accessibilityLabel] isEqualToString:@"list"] ? @"tree" : [super accessibilityLabel]; } +- (nullable NSArray> *)accessibilityRows +{ + return [self accessibilityChildren]; +} + +- (nullable NSArray> *)accessibilitySelectedRows +{ + return [self accessibilitySelectedChildren]; +} + +- (nullable NSArray> *)accessibilityChildren +{ + if (![self isCacheValid]) { + NSArray *t = [super accessibilityChildren]; + if (t != nil) { + rowCache = [[NSMutableArray arrayWithArray:t] retain]; + } else { + rowCache = nil; + } + rowCacheValid = YES; + } + return rowCache; +} + +- (nullable NSArray> *)accessibilitySelectedChildren +{ + if (!selectedRowCacheValid) { + NSArray *t = [super accessibilitySelectedChildren]; + if (t != nil) { + selectedRowCache = [[NSMutableArray arrayWithArray:t] retain]; + } else { + selectedRowCache = nil; + } + selectedRowCacheValid = YES; + } + return selectedRowCache; +} + +- (BOOL)isCacheValid +{ + if (rowCacheValid && [[self parent] respondsToSelector:NSSelectorFromString(@"isCacheValid")]) { + return [[self parent] isCacheValid]; + } + return rowCacheValid; +} + +- (void)invalidateCache +{ + rowCacheValid = NO; +} + +- (void)invalidateSelectionCache +{ + selectedRowCacheValid = NO; +} + +- (void)postSelectionChanged +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateSelectionCache]; + [super postSelectionChanged]; +} + +- (void)postTreeNodeCollapsed +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateCache]; + [super postTreeNodeCollapsed]; +} + +- (void)postTreeNodeExpanded +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateCache]; + [super postTreeNodeExpanded]; +} + +- (void)postSelectedCellsChanged +{ + AWT_ASSERT_APPKIT_THREAD; + [self invalidateSelectionCache]; + [super postSelectedCellsChanged]; +} + @end From 985b9ce79a2d620a8b8675d1ae6c9730d72a757f Mon Sep 17 00:00:00 2001 From: Lei Zaakjyu Date: Sat, 25 May 2024 02:10:05 +0000 Subject: [PATCH 43/99] 8330694: Rename 'HeapRegion' to 'G1HeapRegion' Reviewed-by: cjplummer, kbarrett, tschatzl --- .../gc/g1/g1BarrierSetAssembler_aarch64.cpp | 2 +- .../arm/gc/g1/g1BarrierSetAssembler_arm.cpp | 2 +- .../ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp | 2 +- .../gc/g1/g1BarrierSetAssembler_riscv.cpp | 2 +- .../s390/gc/g1/g1BarrierSetAssembler_s390.cpp | 2 +- .../x86/gc/g1/g1BarrierSetAssembler_x86.cpp | 2 +- src/hotspot/share/cds/archiveHeapWriter.cpp | 6 +- src/hotspot/share/cds/filemap.cpp | 8 +- src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp | 4 +- src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp | 4 +- src/hotspot/share/gc/g1/g1AllocRegion.cpp | 42 ++-- src/hotspot/share/gc/g1/g1AllocRegion.hpp | 45 ++-- .../share/gc/g1/g1AllocRegion.inline.hpp | 8 +- src/hotspot/share/gc/g1/g1Allocator.cpp | 8 +- src/hotspot/share/gc/g1/g1Allocator.hpp | 6 +- src/hotspot/share/gc/g1/g1Arguments.cpp | 16 +- src/hotspot/share/gc/g1/g1BarrierSet.cpp | 2 +- src/hotspot/share/gc/g1/g1CardSet.cpp | 12 +- src/hotspot/share/gc/g1/g1CardTable.cpp | 2 +- .../share/gc/g1/g1CardTable.inline.hpp | 2 +- src/hotspot/share/gc/g1/g1CodeRootSet.cpp | 8 +- src/hotspot/share/gc/g1/g1CodeRootSet.hpp | 4 +- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 202 +++++++++--------- src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 96 ++++----- .../share/gc/g1/g1CollectedHeap.inline.hpp | 38 ++-- src/hotspot/share/gc/g1/g1CollectionSet.cpp | 28 +-- src/hotspot/share/gc/g1/g1CollectionSet.hpp | 10 +- .../share/gc/g1/g1CollectionSetCandidates.cpp | 26 +-- .../share/gc/g1/g1CollectionSetCandidates.hpp | 34 +-- .../g1/g1CollectionSetCandidates.inline.hpp | 2 +- .../share/gc/g1/g1CollectionSetChooser.cpp | 8 +- .../share/gc/g1/g1CollectionSetChooser.hpp | 2 +- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 58 ++--- src/hotspot/share/gc/g1/g1ConcurrentMark.hpp | 28 +-- .../share/gc/g1/g1ConcurrentMark.inline.hpp | 12 +- .../share/gc/g1/g1ConcurrentMarkBitMap.cpp | 2 +- .../share/gc/g1/g1ConcurrentMarkBitMap.hpp | 1 - .../g1/g1ConcurrentMarkObjArrayProcessor.cpp | 2 +- .../gc/g1/g1ConcurrentRebuildAndScrub.cpp | 18 +- .../share/gc/g1/g1ConcurrentRefine.cpp | 4 +- .../gc/g1/g1ConcurrentRefineThreadsNeeded.cpp | 2 +- src/hotspot/share/gc/g1/g1EdenRegions.hpp | 2 +- .../gc/g1/g1EvacFailureRegions.inline.hpp | 2 +- src/hotspot/share/gc/g1/g1FullCollector.cpp | 12 +- src/hotspot/share/gc/g1/g1FullCollector.hpp | 14 +- .../share/gc/g1/g1FullCollector.inline.hpp | 8 +- .../share/gc/g1/g1FullGCAdjustTask.cpp | 2 +- .../share/gc/g1/g1FullGCCompactTask.cpp | 16 +- .../share/gc/g1/g1FullGCCompactTask.hpp | 4 +- .../share/gc/g1/g1FullGCCompactionPoint.cpp | 28 +-- .../share/gc/g1/g1FullGCCompactionPoint.hpp | 26 +-- .../share/gc/g1/g1FullGCHeapRegionAttr.hpp | 2 +- .../share/gc/g1/g1FullGCPrepareTask.cpp | 6 +- .../share/gc/g1/g1FullGCPrepareTask.hpp | 14 +- .../gc/g1/g1FullGCPrepareTask.inline.hpp | 10 +- .../share/gc/g1/g1FullGCResetMetadataTask.cpp | 8 +- .../share/gc/g1/g1FullGCResetMetadataTask.hpp | 8 +- src/hotspot/share/gc/g1/g1FullGCScope.cpp | 4 +- src/hotspot/share/gc/g1/g1HeapRegion.cpp | 104 ++++----- src/hotspot/share/gc/g1/g1HeapRegion.hpp | 42 ++-- .../share/gc/g1/g1HeapRegion.inline.hpp | 88 ++++---- src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp | 6 +- .../share/gc/g1/g1HeapRegionEventSender.cpp | 2 +- .../share/gc/g1/g1HeapRegionManager.cpp | 50 ++--- .../share/gc/g1/g1HeapRegionManager.hpp | 58 ++--- .../gc/g1/g1HeapRegionManager.inline.hpp | 20 +- .../share/gc/g1/g1HeapRegionPrinter.hpp | 28 +-- .../share/gc/g1/g1HeapRegionRemSet.cpp | 4 +- .../share/gc/g1/g1HeapRegionRemSet.hpp | 6 +- src/hotspot/share/gc/g1/g1HeapRegionSet.cpp | 32 +-- src/hotspot/share/gc/g1/g1HeapRegionSet.hpp | 42 ++-- .../share/gc/g1/g1HeapRegionSet.inline.hpp | 30 +-- .../share/gc/g1/g1HeapSizingPolicy.cpp | 4 +- src/hotspot/share/gc/g1/g1HeapTransition.cpp | 8 +- src/hotspot/share/gc/g1/g1HeapVerifier.cpp | 24 +-- src/hotspot/share/gc/g1/g1HeapVerifier.hpp | 4 +- .../share/gc/g1/g1MonitoringSupport.cpp | 6 +- src/hotspot/share/gc/g1/g1NMethodClosure.cpp | 2 +- src/hotspot/share/gc/g1/g1NUMA.cpp | 16 +- src/hotspot/share/gc/g1/g1NUMA.hpp | 10 +- src/hotspot/share/gc/g1/g1OopClosures.hpp | 1 - .../share/gc/g1/g1OopClosures.inline.hpp | 10 +- .../share/gc/g1/g1ParScanThreadState.cpp | 12 +- .../share/gc/g1/g1ParScanThreadState.hpp | 6 +- .../gc/g1/g1ParScanThreadState.inline.hpp | 10 +- src/hotspot/share/gc/g1/g1Policy.cpp | 50 ++--- src/hotspot/share/gc/g1/g1Policy.hpp | 20 +- src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp | 2 +- src/hotspot/share/gc/g1/g1RegionsOnNodes.hpp | 4 +- src/hotspot/share/gc/g1/g1RemSet.cpp | 62 +++--- src/hotspot/share/gc/g1/g1RemSet.hpp | 2 +- src/hotspot/share/gc/g1/g1RemSetSummary.cpp | 10 +- .../share/gc/g1/g1RemSetTrackingPolicy.cpp | 16 +- .../share/gc/g1/g1RemSetTrackingPolicy.hpp | 12 +- src/hotspot/share/gc/g1/g1SurvRateGroup.cpp | 2 +- src/hotspot/share/gc/g1/g1SurvivorRegions.cpp | 8 +- src/hotspot/share/gc/g1/g1SurvivorRegions.hpp | 8 +- .../share/gc/g1/g1UncommitRegionTask.cpp | 8 +- src/hotspot/share/gc/g1/g1YoungCollector.cpp | 10 +- .../g1/g1YoungGCAllocationFailureInjector.cpp | 2 +- .../gc/g1/g1YoungGCPostEvacuateTasks.cpp | 44 ++-- src/hotspot/share/gc/g1/g1YoungGenSizer.cpp | 8 +- src/hotspot/share/gc/g1/vmStructs_g1.hpp | 18 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 2 +- src/hotspot/share/prims/whitebox.cpp | 14 +- .../share/classes/sun/jvm/hotspot/HSDB.java | 2 +- .../jvm/hotspot/gc/g1/G1CollectedHeap.java | 18 +- .../g1/{HeapRegion.java => G1HeapRegion.java} | 10 +- .../jvm/hotspot/gc/g1/G1HeapRegionTable.java | 32 +-- .../hotspot/gc/g1/G1MonitoringSupport.java | 4 +- .../jvm/hotspot/gc/g1/HeapRegionClosure.java | 2 +- .../jvm/hotspot/gc/g1/HeapRegionManager.java | 6 +- .../jvm/hotspot/gc/g1/PrintRegionClosure.java | 4 +- .../sun/jvm/hotspot/tools/HeapSummary.java | 2 +- .../jvm/hotspot/utilities/PointerFinder.java | 4 +- .../hotspot/utilities/PointerLocation.java | 8 +- .../gtest/gc/g1/test_freeRegionList.cpp | 28 +-- test/hotspot/gtest/gc/g1/test_heapRegion.cpp | 6 +- .../TestHumongousAllocNearlyFullRegion.java | 4 +- .../gc/g1/numa/TestG1NUMATouchRegions.java | 2 +- .../sharedStrings/SharedStringsHumongous.java | 4 +- .../serviceability/sa/TestG1HeapRegion.java | 8 +- .../sa/TestObjectAlignment.java | 2 +- 123 files changed, 999 insertions(+), 1002 deletions(-) rename src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/{HeapRegion.java => G1HeapRegion.java} (93%) diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp index 427987da971..d02038b6e91 100644 --- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp @@ -207,7 +207,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, // Does store cross heap regions? __ eor(tmp1, store_addr, new_val); - __ lsr(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes); + __ lsr(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); __ cbz(tmp1, done); // crosses regions, storing null? diff --git a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp index 6d724c750aa..3c5e29aa871 100644 --- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp @@ -207,7 +207,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, // Does store cross heap regions? __ eor(tmp1, store_addr, new_val); - __ movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes)); + __ movs(tmp1, AsmOperand(tmp1, lsr, G1HeapRegion::LogOfHRGrainBytes)); __ b(done, eq); // crosses regions, storing null? diff --git a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp index ab520162d35..45438f81345 100644 --- a/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/g1/g1BarrierSetAssembler_ppc.cpp @@ -243,7 +243,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato // Does store cross heap regions? __ xorr(tmp1, store_addr, new_val); - __ srdi_(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes); + __ srdi_(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); __ beq(CCR0, filtered); // Crosses regions, storing null? diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp index fa7df32d7e9..062f8029062 100644 --- a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp @@ -194,7 +194,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, // Does store cross heap regions? __ xorr(tmp1, store_addr, new_val); - __ srli(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes); + __ srli(tmp1, tmp1, G1HeapRegion::LogOfHRGrainBytes); __ beqz(tmp1, done); // crosses regions, storing null? diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp index 8ce9305a865..37631298920 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp @@ -282,7 +282,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Decorato __ z_lgr(Rtmp1, Rstore_addr); __ z_xgr(Rtmp1, Rnew_val); } - __ z_srag(Rtmp1, Rtmp1, HeapRegion::LogOfHRGrainBytes); + __ z_srag(Rtmp1, Rtmp1, G1HeapRegion::LogOfHRGrainBytes); __ z_bre(filtered); // Crosses regions, storing null? diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index 0ea93ec067e..b52be627776 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -286,7 +286,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, __ movptr(tmp, store_addr); __ xorptr(tmp, new_val); - __ shrptr(tmp, HeapRegion::LogOfHRGrainBytes); + __ shrptr(tmp, G1HeapRegion::LogOfHRGrainBytes); __ jcc(Assembler::equal, done); // crosses regions, storing null? diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index d526a961b7f..bf49805658c 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -89,7 +89,7 @@ void ArchiveHeapWriter::init() { _source_objs = new GrowableArrayCHeap(10000); guarantee(UseG1GC, "implementation limitation"); - guarantee(MIN_GC_REGION_ALIGNMENT <= /*G1*/HeapRegion::min_region_size_in_words() * HeapWordSize, "must be"); + guarantee(MIN_GC_REGION_ALIGNMENT <= G1HeapRegion::min_region_size_in_words() * HeapWordSize, "must be"); } } @@ -439,7 +439,7 @@ void ArchiveHeapWriter::set_requested_address(ArchiveHeapInfo* info) { if (UseCompressedOops) { - _requested_bottom = align_down(heap_end - heap_region_byte_size, HeapRegion::GrainBytes); + _requested_bottom = align_down(heap_end - heap_region_byte_size, G1HeapRegion::GrainBytes); } else { // We always write the objects as if the heap started at this address. This // makes the contents of the archive heap deterministic. @@ -449,7 +449,7 @@ void ArchiveHeapWriter::set_requested_address(ArchiveHeapInfo* info) { _requested_bottom = (address)NOCOOPS_REQUESTED_BASE; } - assert(is_aligned(_requested_bottom, HeapRegion::GrainBytes), "sanity"); + assert(is_aligned(_requested_bottom, G1HeapRegion::GrainBytes), "sanity"); _requested_top = _requested_bottom + _buffer_used; diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 2182865ebaa..5d56eb2153f 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -2064,8 +2064,8 @@ bool FileMapInfo::can_use_heap_region() { archive_narrow_klass_shift); log_info(cds)(" narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift()); - log_info(cds)("The current max heap size = " SIZE_FORMAT "M, HeapRegion::GrainBytes = " SIZE_FORMAT, - MaxHeapSize/M, HeapRegion::GrainBytes); + log_info(cds)("The current max heap size = " SIZE_FORMAT "M, G1HeapRegion::GrainBytes = " SIZE_FORMAT, + MaxHeapSize/M, G1HeapRegion::GrainBytes); log_info(cds)(" narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d", p2i(CompressedKlassPointers::base()), CompressedKlassPointers::shift()); log_info(cds)(" narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d", @@ -2130,7 +2130,7 @@ bool FileMapInfo::map_heap_region() { #ifdef ASSERT // The "old" regions must be parsable -- we cannot have any unused space // at the start of the lowest G1 region that contains archived objects. - assert(is_aligned(_mapped_heap_memregion.start(), HeapRegion::GrainBytes), "must be"); + assert(is_aligned(_mapped_heap_memregion.start(), G1HeapRegion::GrainBytes), "must be"); // Make sure we map at the very top of the heap - see comments in // init_heap_region_relocation(). @@ -2140,7 +2140,7 @@ bool FileMapInfo::map_heap_region() { address heap_end = (address)heap_range.end(); address mapped_heap_region_end = (address)_mapped_heap_memregion.end(); assert(heap_end >= mapped_heap_region_end, "must be"); - assert(heap_end - mapped_heap_region_end < (intx)(HeapRegion::GrainBytes), + assert(heap_end - mapped_heap_region_end < (intx)(G1HeapRegion::GrainBytes), "must be at the top of the heap to avoid fragmentation"); #endif diff --git a/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp b/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp index 53d4aa221f2..f82b5cfcc55 100644 --- a/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp +++ b/src/hotspot/share/gc/g1/c1/g1BarrierSetC1.cpp @@ -158,13 +158,13 @@ void G1BarrierSetC1::post_barrier(LIRAccess& access, LIR_Opr addr, LIR_Opr new_v __ logical_xor(xor_res, new_val, xor_res); __ move(xor_res, xor_shift_res); __ unsigned_shift_right(xor_shift_res, - LIR_OprFact::intConst(checked_cast(HeapRegion::LogOfHRGrainBytes)), + LIR_OprFact::intConst(checked_cast(G1HeapRegion::LogOfHRGrainBytes)), xor_shift_res, LIR_Opr::illegalOpr()); } else { __ logical_xor(addr, new_val, xor_res); __ unsigned_shift_right(xor_res, - LIR_OprFact::intConst(checked_cast(HeapRegion::LogOfHRGrainBytes)), + LIR_OprFact::intConst(checked_cast(G1HeapRegion::LogOfHRGrainBytes)), xor_shift_res, LIR_Opr::illegalOpr()); } diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 807e9aa9c59..13b993546cd 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -453,8 +453,8 @@ void G1BarrierSetC2::post_barrier(GraphKit* kit, // 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 << HeapRegion::LogOfHRGrainBytes); - Node* xor_res = __ URShiftX ( __ XorX( cast, __ CastPX(__ ctrl(), val)), __ ConI(checked_cast(HeapRegion::LogOfHRGrainBytes))); + // 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); { diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.cpp b/src/hotspot/share/gc/g1/g1AllocRegion.cpp index b86fe1099ac..a205cf71ee6 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.cpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.cpp @@ -34,9 +34,9 @@ #include "utilities/align.hpp" G1CollectedHeap* G1AllocRegion::_g1h = nullptr; -HeapRegion* G1AllocRegion::_dummy_region = nullptr; +G1HeapRegion* G1AllocRegion::_dummy_region = nullptr; -void G1AllocRegion::setup(G1CollectedHeap* g1h, HeapRegion* dummy_region) { +void G1AllocRegion::setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region) { assert(_dummy_region == nullptr, "should be set once"); assert(dummy_region != nullptr, "pre-condition"); assert(dummy_region->free() == 0, "pre-condition"); @@ -50,7 +50,7 @@ void G1AllocRegion::setup(G1CollectedHeap* g1h, HeapRegion* dummy_region) { _dummy_region = dummy_region; } -size_t G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region) { +size_t G1AllocRegion::fill_up_remaining_space(G1HeapRegion* alloc_region) { assert(alloc_region != nullptr && alloc_region != _dummy_region, "pre-condition"); size_t result = 0; @@ -94,7 +94,7 @@ size_t G1AllocRegion::fill_up_remaining_space(HeapRegion* alloc_region) { return result; } -size_t G1AllocRegion::retire_internal(HeapRegion* alloc_region, bool fill_up) { +size_t G1AllocRegion::retire_internal(G1HeapRegion* alloc_region, bool fill_up) { // We never have to check whether the active region is empty or not, // and potentially free it if it is, given that it's guaranteed that // it will never be empty. @@ -120,7 +120,7 @@ size_t G1AllocRegion::retire(bool fill_up) { size_t waste = 0; trace("retiring"); - HeapRegion* alloc_region = _alloc_region; + G1HeapRegion* alloc_region = _alloc_region; if (alloc_region != _dummy_region) { waste = retire_internal(alloc_region, fill_up); reset_alloc_region(); @@ -135,7 +135,7 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size) { assert_alloc_region(_used_bytes_before == 0, "pre-condition"); trace("attempting region allocation"); - HeapRegion* new_alloc_region = allocate_new_region(word_size); + G1HeapRegion* new_alloc_region = allocate_new_region(word_size); if (new_alloc_region != nullptr) { new_alloc_region->reset_pre_dummy_top(); // Need to do this before the allocation @@ -166,7 +166,7 @@ void G1AllocRegion::init() { trace("initialized"); } -void G1AllocRegion::set(HeapRegion* alloc_region) { +void G1AllocRegion::set(G1HeapRegion* alloc_region) { trace("setting"); // We explicitly check that the region is not empty to make sure we // maintain the "the alloc region cannot be empty" invariant. @@ -181,7 +181,7 @@ void G1AllocRegion::set(HeapRegion* alloc_region) { trace("set"); } -void G1AllocRegion::update_alloc_region(HeapRegion* alloc_region) { +void G1AllocRegion::update_alloc_region(G1HeapRegion* alloc_region) { trace("update"); // We explicitly check that the region is not empty to make sure we // maintain the "the alloc region cannot be empty" invariant. @@ -192,9 +192,9 @@ void G1AllocRegion::update_alloc_region(HeapRegion* alloc_region) { trace("updated"); } -HeapRegion* G1AllocRegion::release() { +G1HeapRegion* G1AllocRegion::release() { trace("releasing"); - HeapRegion* alloc_region = _alloc_region; + G1HeapRegion* alloc_region = _alloc_region; retire(false /* fill_up */); assert_alloc_region(_alloc_region == _dummy_region, "post-condition of retire()"); _alloc_region = nullptr; @@ -257,11 +257,11 @@ G1AllocRegion::G1AllocRegion(const char* name, _node_index(node_index) { } -HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size) { +G1HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size) { return _g1h->new_mutator_alloc_region(word_size, _node_index); } -void MutatorAllocRegion::retire_region(HeapRegion* alloc_region, +void MutatorAllocRegion::retire_region(G1HeapRegion* alloc_region, size_t allocated_bytes) { _g1h->retire_mutator_alloc_region(alloc_region, allocated_bytes); } @@ -272,7 +272,7 @@ void MutatorAllocRegion::init() { _wasted_bytes = 0; } -bool MutatorAllocRegion::should_retain(HeapRegion* region) { +bool MutatorAllocRegion::should_retain(G1HeapRegion* region) { size_t free_bytes = region->free(); if (free_bytes < MinTLABSize) { return false; @@ -289,7 +289,7 @@ bool MutatorAllocRegion::should_retain(HeapRegion* region) { size_t MutatorAllocRegion::retire(bool fill_up) { size_t waste = 0; trace("retiring"); - HeapRegion* current_region = get(); + G1HeapRegion* current_region = get(); if (current_region != nullptr) { // Retain the current region if it fits a TLAB and has more // free than the currently retained region. @@ -312,7 +312,7 @@ size_t MutatorAllocRegion::retire(bool fill_up) { size_t MutatorAllocRegion::used_in_alloc_regions() { size_t used = 0; - HeapRegion* hr = get(); + G1HeapRegion* hr = get(); if (hr != nullptr) { used += hr->used(); } @@ -324,8 +324,8 @@ size_t MutatorAllocRegion::used_in_alloc_regions() { return used; } -HeapRegion* MutatorAllocRegion::release() { - HeapRegion* ret = G1AllocRegion::release(); +G1HeapRegion* MutatorAllocRegion::release() { + G1HeapRegion* ret = G1AllocRegion::release(); // The retained alloc region must be retired and this must be // done after the above call to release the mutator alloc region, @@ -338,21 +338,21 @@ HeapRegion* MutatorAllocRegion::release() { count(), byte_size_in_proper_unit(_wasted_bytes), proper_unit_for_byte_size(_wasted_bytes), - percent_of(_wasted_bytes, count() * HeapRegion::GrainBytes)); + percent_of(_wasted_bytes, count() * G1HeapRegion::GrainBytes)); return ret; } -HeapRegion* G1GCAllocRegion::allocate_new_region(size_t word_size) { +G1HeapRegion* G1GCAllocRegion::allocate_new_region(size_t word_size) { return _g1h->new_gc_alloc_region(word_size, _purpose, _node_index); } -void G1GCAllocRegion::retire_region(HeapRegion* alloc_region, +void G1GCAllocRegion::retire_region(G1HeapRegion* alloc_region, size_t allocated_bytes) { _g1h->retire_gc_alloc_region(alloc_region, allocated_bytes, _purpose); } size_t G1GCAllocRegion::retire(bool fill_up) { - HeapRegion* retired = get(); + G1HeapRegion* retired = get(); size_t end_waste = G1AllocRegion::retire(fill_up); // Do not count retirement of the dummy allocation region. if (retired != nullptr) { diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.hpp index 9ea20c676f4..a8903fd54f1 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.hpp @@ -52,7 +52,7 @@ class G1AllocRegion : public CHeapObj { // then _alloc_region is null and this object should not be used to // satisfy allocation requests (it was done this way to force the // correct use of init() and release()). - HeapRegion* volatile _alloc_region; + G1HeapRegion* volatile _alloc_region; // It keeps track of the distinct number of regions that are used // for allocation in the active interval of this object, i.e., @@ -76,11 +76,11 @@ class G1AllocRegion : public CHeapObj { // == end()). When we don't have a valid active region we make // _alloc_region point to this. This allows us to skip checking // whether the _alloc_region is null or not. - static HeapRegion* _dummy_region; + static G1HeapRegion* _dummy_region; // After a region is allocated by alloc_new_region, this // method is used to set it as the active alloc_region - void update_alloc_region(HeapRegion* alloc_region); + void update_alloc_region(G1HeapRegion* alloc_region); // Allocate a new active region and use it to perform a word_size // allocation. @@ -98,17 +98,17 @@ class G1AllocRegion : public CHeapObj { void reset_alloc_region(); // Perform a non-MT-safe allocation out of the given region. - inline HeapWord* allocate(HeapRegion* alloc_region, + inline HeapWord* allocate(G1HeapRegion* alloc_region, size_t word_size); // Perform a MT-safe allocation out of the given region. - inline HeapWord* par_allocate(HeapRegion* alloc_region, + inline HeapWord* par_allocate(G1HeapRegion* alloc_region, size_t word_size); // Perform a MT-safe allocation out of the given region, with the given // minimum and desired size. Returns the actual size allocated (between // minimum and desired size) in actual_word_size if the allocation has been // successful. - inline HeapWord* par_allocate(HeapRegion* alloc_region, + inline HeapWord* par_allocate(G1HeapRegion* alloc_region, size_t min_word_size, size_t desired_word_size, size_t* actual_word_size); @@ -117,7 +117,7 @@ class G1AllocRegion : public CHeapObj { // so that no one else can allocate out of it any more. // Returns the number of bytes that have been wasted by filled up // the space. - size_t fill_up_remaining_space(HeapRegion* alloc_region); + size_t fill_up_remaining_space(G1HeapRegion* alloc_region); // Retire the active allocating region. If fill_up is true then make // sure that the region is full before we retire it so that no one @@ -125,22 +125,22 @@ class G1AllocRegion : public CHeapObj { // Returns the number of bytes that have been filled up during retire. virtual size_t retire(bool fill_up); - size_t retire_internal(HeapRegion* alloc_region, bool fill_up); + size_t retire_internal(G1HeapRegion* alloc_region, bool fill_up); // For convenience as subclasses use it. static G1CollectedHeap* _g1h; - virtual HeapRegion* allocate_new_region(size_t word_size) = 0; - virtual void retire_region(HeapRegion* alloc_region, + virtual G1HeapRegion* allocate_new_region(size_t word_size) = 0; + virtual void retire_region(G1HeapRegion* alloc_region, size_t allocated_bytes) = 0; G1AllocRegion(const char* name, bool bot_updates, uint node_index); public: - static void setup(G1CollectedHeap* g1h, HeapRegion* dummy_region); + static void setup(G1CollectedHeap* g1h, G1HeapRegion* dummy_region); - HeapRegion* get() const { - HeapRegion * hr = _alloc_region; + G1HeapRegion* get() const { + G1HeapRegion * hr = _alloc_region; // Make sure that the dummy region does not escape this class. return (hr == _dummy_region) ? nullptr : hr; } @@ -177,11 +177,11 @@ class G1AllocRegion : public CHeapObj { // region. (Use Example: we try to retain the last old GC alloc // region that we've used during a GC and we can use set() to // re-instate it at the beginning of the next GC.) - void set(HeapRegion* alloc_region); + void set(G1HeapRegion* alloc_region); // Should be called when we want to release the active region which // is returned after it's been retired. - virtual HeapRegion* release(); + virtual G1HeapRegion* release(); void trace(const char* str, size_t min_word_size = 0, @@ -199,15 +199,16 @@ class MutatorAllocRegion : public G1AllocRegion { // Retained allocation region. Used to lower the waste generated // during mutation by having two active regions if the free space // in a region about to be retired still could fit a TLAB. - HeapRegion* volatile _retained_alloc_region; + G1HeapRegion* volatile _retained_alloc_region; // Decide if the region should be retained, based on the free size // in it and the free size in the currently retained region, if any. - bool should_retain(HeapRegion* region); + bool should_retain(G1HeapRegion* region); protected: - virtual HeapRegion* allocate_new_region(size_t word_size); - virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes); + virtual G1HeapRegion* allocate_new_region(size_t word_size); + virtual void retire_region(G1HeapRegion* alloc_region, size_t allocated_bytes); virtual size_t retire(bool fill_up); + public: MutatorAllocRegion(uint node_index) : G1AllocRegion("Mutator Alloc Region", false /* bot_updates */, node_index), @@ -230,7 +231,7 @@ class MutatorAllocRegion : public G1AllocRegion { // This specialization of release() makes sure that the retained alloc // region is retired and set to null. - virtual HeapRegion* release(); + virtual G1HeapRegion* release(); virtual void init(); }; @@ -241,8 +242,8 @@ class G1GCAllocRegion : public G1AllocRegion { G1EvacStats* _stats; G1HeapRegionAttr::region_type_t _purpose; - virtual HeapRegion* allocate_new_region(size_t word_size); - virtual void retire_region(HeapRegion* alloc_region, size_t allocated_bytes); + virtual G1HeapRegion* allocate_new_region(size_t word_size); + virtual void retire_region(G1HeapRegion* alloc_region, size_t allocated_bytes); virtual size_t retire(bool fill_up); diff --git a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp index 9e702a4f8c9..ba4f1a12628 100644 --- a/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1AllocRegion.inline.hpp @@ -41,19 +41,19 @@ inline void G1AllocRegion::reset_alloc_region() { _alloc_region = _dummy_region; } -inline HeapWord* G1AllocRegion::allocate(HeapRegion* alloc_region, +inline HeapWord* G1AllocRegion::allocate(G1HeapRegion* alloc_region, size_t word_size) { assert(alloc_region != nullptr, "pre-condition"); return alloc_region->allocate(word_size); } -inline HeapWord* G1AllocRegion::par_allocate(HeapRegion* alloc_region, size_t word_size) { +inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t word_size) { size_t temp; return par_allocate(alloc_region, word_size, word_size, &temp); } -inline HeapWord* G1AllocRegion::par_allocate(HeapRegion* alloc_region, +inline HeapWord* G1AllocRegion::par_allocate(G1HeapRegion* alloc_region, size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { @@ -66,7 +66,7 @@ inline HeapWord* G1AllocRegion::par_allocate(HeapRegion* alloc_region, inline HeapWord* G1AllocRegion::attempt_allocation(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { - HeapRegion* alloc_region = _alloc_region; + G1HeapRegion* alloc_region = _alloc_region; assert_alloc_region(alloc_region != nullptr, "not initialized properly"); HeapWord* result = par_allocate(alloc_region, min_word_size, desired_word_size, actual_word_size); diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index 2a028f480c0..05c64287ec0 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -89,14 +89,14 @@ void G1Allocator::release_mutator_alloc_regions() { } } -bool G1Allocator::is_retained_old_region(HeapRegion* hr) { +bool G1Allocator::is_retained_old_region(G1HeapRegion* hr) { return _retained_old_gc_alloc_region == hr; } void G1Allocator::reuse_retained_old_region(G1EvacInfo* evacuation_info, OldGCAllocRegion* old, - HeapRegion** retained_old) { - HeapRegion* retained_region = *retained_old; + G1HeapRegion** retained_old) { + G1HeapRegion* retained_region = *retained_old; *retained_old = nullptr; // We will discard the current GC alloc region if: @@ -190,7 +190,7 @@ size_t G1Allocator::unsafe_max_tlab_alloc() { // humongous objects. uint node_index = current_node_index(); - HeapRegion* hr = mutator_alloc_region(node_index)->get(); + G1HeapRegion* hr = mutator_alloc_region(node_index)->get(); size_t max_tlab = _g1h->max_tlab_size() * wordSize; if (hr == nullptr || hr->free() < MinTLABSize) { diff --git a/src/hotspot/share/gc/g1/g1Allocator.hpp b/src/hotspot/share/gc/g1/g1Allocator.hpp index e273365b12f..f9038071bd9 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.hpp @@ -60,7 +60,7 @@ class G1Allocator : public CHeapObj { // old objects. OldGCAllocRegion _old_gc_alloc_region; - HeapRegion* _retained_old_gc_alloc_region; + G1HeapRegion* _retained_old_gc_alloc_region; bool survivor_is_full() const; bool old_is_full() const; @@ -70,7 +70,7 @@ class G1Allocator : public CHeapObj { void reuse_retained_old_region(G1EvacInfo* evacuation_info, OldGCAllocRegion* old, - HeapRegion** retained); + G1HeapRegion** retained); // Accessors to the allocation regions. inline MutatorAllocRegion* mutator_alloc_region(uint node_index); @@ -108,7 +108,7 @@ class G1Allocator : public CHeapObj { void init_gc_alloc_regions(G1EvacInfo* evacuation_info); void release_gc_alloc_regions(G1EvacInfo* evacuation_info); void abandon_gc_alloc_regions(); - bool is_retained_old_region(HeapRegion* hr); + bool is_retained_old_region(G1HeapRegion* hr); // Allocate blocks of memory during mutator time. diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index d0d9cd31297..a62eb994486 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -55,9 +55,9 @@ void G1Arguments::initialize_alignments() { // There is a circular dependency here. We base the region size on the heap // size, but the heap size should be aligned with the region size. To get // around this we use the unaligned values for the heap. - HeapRegion::setup_heap_region_size(MaxHeapSize); + G1HeapRegion::setup_heap_region_size(MaxHeapSize); - SpaceAlignment = HeapRegion::GrainBytes; + SpaceAlignment = G1HeapRegion::GrainBytes; HeapAlignment = calculate_heap_alignment(SpaceAlignment); // We need to initialize card set configuration as soon as heap region size is @@ -71,7 +71,7 @@ void G1Arguments::initialize_alignments() { } size_t G1Arguments::conservative_max_heap_alignment() { - return HeapRegion::max_region_size(); + return G1HeapRegion::max_region_size(); } void G1Arguments::initialize_verification_types() { @@ -130,22 +130,22 @@ void G1Arguments::initialize_mark_stack_size() { void G1Arguments::initialize_card_set_configuration() { - assert(HeapRegion::LogOfHRGrainBytes != 0, "not initialized"); + assert(G1HeapRegion::LogOfHRGrainBytes != 0, "not initialized"); // Array of Cards card set container globals. const uint LOG_M = 20; assert(log2i_exact(HeapRegionBounds::min_size()) == LOG_M, "inv"); - assert(HeapRegion::LogOfHRGrainBytes >= LOG_M, "from the above"); - uint region_size_log_mb = HeapRegion::LogOfHRGrainBytes - LOG_M; + assert(G1HeapRegion::LogOfHRGrainBytes >= LOG_M, "from the above"); + uint region_size_log_mb = G1HeapRegion::LogOfHRGrainBytes - LOG_M; if (FLAG_IS_DEFAULT(G1RemSetArrayOfCardsEntries)) { - uint max_cards_in_inline_ptr = G1CardSetConfiguration::max_cards_in_inline_ptr(HeapRegion::LogCardsPerRegion); + uint max_cards_in_inline_ptr = G1CardSetConfiguration::max_cards_in_inline_ptr(G1HeapRegion::LogCardsPerRegion); FLAG_SET_ERGO(G1RemSetArrayOfCardsEntries, MAX2(max_cards_in_inline_ptr * 2, G1RemSetArrayOfCardsEntriesBase << region_size_log_mb)); } // Howl card set container globals. if (FLAG_IS_DEFAULT(G1RemSetHowlNumBuckets)) { - FLAG_SET_ERGO(G1RemSetHowlNumBuckets, G1CardSetHowl::num_buckets(HeapRegion::CardsPerRegion, + FLAG_SET_ERGO(G1RemSetHowlNumBuckets, G1CardSetHowl::num_buckets(G1HeapRegion::CardsPerRegion, G1RemSetArrayOfCardsEntries, G1RemSetHowlMaxNumBuckets)); } diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.cpp b/src/hotspot/share/gc/g1/g1BarrierSet.cpp index 8b87fc3d78a..019cfb8cb98 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.cpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.cpp @@ -112,7 +112,7 @@ void G1BarrierSet::write_region(JavaThread* thread, MemRegion mr) { // skip young gen cards if (*byte == G1CardTable::g1_young_card_val()) { // MemRegion should not span multiple regions for the young gen. - DEBUG_ONLY(HeapRegion* containing_hr = G1CollectedHeap::heap()->heap_region_containing(mr.start());) + DEBUG_ONLY(G1HeapRegion* containing_hr = G1CollectedHeap::heap()->heap_region_containing(mr.start());) assert(containing_hr->is_young(), "it should be young"); assert(containing_hr->is_in(mr.start()), "it should contain start"); assert(containing_hr->is_in(mr.last()), "it should also contain last"); diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 3202859907c..7ab739e0196 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -57,24 +57,24 @@ static uint default_log2_card_regions_per_region() { uint log2_card_regions_per_heap_region = 0; const uint card_container_limit = G1CardSetContainer::LogCardsPerRegionLimit; - if (card_container_limit < (uint)HeapRegion::LogCardsPerRegion) { - log2_card_regions_per_heap_region = (uint)HeapRegion::LogCardsPerRegion - card_container_limit; + if (card_container_limit < (uint)G1HeapRegion::LogCardsPerRegion) { + log2_card_regions_per_heap_region = (uint)G1HeapRegion::LogCardsPerRegion - card_container_limit; } return log2_card_regions_per_heap_region; } G1CardSetConfiguration::G1CardSetConfiguration() : - G1CardSetConfiguration(HeapRegion::LogCardsPerRegion - default_log2_card_regions_per_region(), /* inline_ptr_bits_per_card */ + G1CardSetConfiguration(G1HeapRegion::LogCardsPerRegion - default_log2_card_regions_per_region(), /* inline_ptr_bits_per_card */ G1RemSetArrayOfCardsEntries, /* max_cards_in_array */ (double)G1RemSetCoarsenHowlBitmapToHowlFullPercent / 100, /* cards_in_bitmap_threshold_percent */ G1RemSetHowlNumBuckets, /* num_buckets_in_howl */ (double)G1RemSetCoarsenHowlToFullPercent / 100, /* cards_in_howl_threshold_percent */ - (uint)HeapRegion::CardsPerRegion >> default_log2_card_regions_per_region(), + (uint)G1HeapRegion::CardsPerRegion >> default_log2_card_regions_per_region(), /* max_cards_in_card_set */ default_log2_card_regions_per_region()) /* log2_card_regions_per_region */ { - assert((_log2_card_regions_per_heap_region + _log2_cards_per_card_region) == (uint)HeapRegion::LogCardsPerRegion, + assert((_log2_card_regions_per_heap_region + _log2_cards_per_card_region) == (uint)G1HeapRegion::LogCardsPerRegion, "inconsistent heap region virtualization setup"); } @@ -395,7 +395,7 @@ G1CardSet::~G1CardSet() { void G1CardSet::initialize(MemRegion reserved) { const uint BitsInUint = sizeof(uint) * BitsPerByte; - const uint CardBitsWithinCardRegion = MIN2((uint)HeapRegion::LogCardsPerRegion, G1CardSetContainer::LogCardsPerRegionLimit); + const uint CardBitsWithinCardRegion = MIN2((uint)G1HeapRegion::LogCardsPerRegion, G1CardSetContainer::LogCardsPerRegionLimit); // Check if the number of cards within a region fits an uint. if (CardBitsWithinCardRegion > BitsInUint) { diff --git a/src/hotspot/share/gc/g1/g1CardTable.cpp b/src/hotspot/share/gc/g1/g1CardTable.cpp index 467ba6c56a9..56352865e37 100644 --- a/src/hotspot/share/gc/g1/g1CardTable.cpp +++ b/src/hotspot/share/gc/g1/g1CardTable.cpp @@ -43,7 +43,7 @@ void G1CardTable::verify_g1_young_region(MemRegion mr) { void G1CardTableChangedListener::on_commit(uint start_idx, size_t num_regions, bool zero_filled) { // Default value for a clean card on the card table is -1. So we cannot take advantage of the zero_filled parameter. - MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_idx), num_regions * HeapRegion::GrainWords); + MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_idx), num_regions * G1HeapRegion::GrainWords); _card_table->clear_MemRegion(mr); } diff --git a/src/hotspot/share/gc/g1/g1CardTable.inline.hpp b/src/hotspot/share/gc/g1/g1CardTable.inline.hpp index 0585b68e336..295eea242f7 100644 --- a/src/hotspot/share/gc/g1/g1CardTable.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardTable.inline.hpp @@ -31,7 +31,7 @@ inline uint G1CardTable::region_idx_for(CardValue* p) { size_t const card_idx = pointer_delta(p, _byte_map, sizeof(CardValue)); - return (uint)(card_idx >> HeapRegion::LogCardsPerRegion); + return (uint)(card_idx >> G1HeapRegion::LogCardsPerRegion); } inline bool G1CardTable::mark_clean_as_dirty(CardValue* card) { diff --git a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp index 4b933d9a85f..e72e5e8d377 100644 --- a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp +++ b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp @@ -298,7 +298,7 @@ class CleanCallback : public StackObj { NONCOPYABLE(CleanCallback); // can not copy, _blobs will point to old copy class PointsIntoHRDetectionClosure : public OopClosure { - HeapRegion* _hr; + G1HeapRegion* _hr; template void do_oop_work(T* p) { @@ -309,7 +309,7 @@ class CleanCallback : public StackObj { public: bool _points_into; - PointsIntoHRDetectionClosure(HeapRegion* hr) : _hr(hr), _points_into(false) {} + PointsIntoHRDetectionClosure(G1HeapRegion* hr) : _hr(hr), _points_into(false) {} void do_oop(narrowOop* o) { do_oop_work(o); } @@ -320,7 +320,7 @@ class CleanCallback : public StackObj { NMethodToOopClosure _nmethod_cl; public: - CleanCallback(HeapRegion* hr) : _detector(hr), _nmethod_cl(&_detector, !NMethodToOopClosure::FixRelocations) {} + CleanCallback(G1HeapRegion* hr) : _detector(hr), _nmethod_cl(&_detector, !NMethodToOopClosure::FixRelocations) {} bool operator()(nmethod** value) { _detector._points_into = false; @@ -329,7 +329,7 @@ class CleanCallback : public StackObj { } }; -void G1CodeRootSet::clean(HeapRegion* owner) { +void G1CodeRootSet::clean(G1HeapRegion* owner) { assert(!_is_iterating, "should not mutate while iterating the table"); CleanCallback eval(owner); diff --git a/src/hotspot/share/gc/g1/g1CodeRootSet.hpp b/src/hotspot/share/gc/g1/g1CodeRootSet.hpp index a4c425109b2..01de2ec48ff 100644 --- a/src/hotspot/share/gc/g1/g1CodeRootSet.hpp +++ b/src/hotspot/share/gc/g1/g1CodeRootSet.hpp @@ -29,7 +29,7 @@ #include "utilities/globalDefinitions.hpp" class G1CodeRootSetHashTable; -class HeapRegion; +class G1HeapRegion; class nmethod; // Implements storage for a set of code roots. @@ -53,7 +53,7 @@ class G1CodeRootSet { void nmethods_do(NMethodClosure* blk) const; // Remove all nmethods which no longer contain pointers into our "owner" region. - void clean(HeapRegion* owner); + void clean(G1HeapRegion* owner); bool is_empty() { return length() == 0;} diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index a7b9852f551..258f3f667c5 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -145,7 +145,7 @@ void G1CollectedHeap::run_batch_task(G1BatchedTask* cl) { } uint G1CollectedHeap::get_chunks_per_region() { - uint log_region_size = HeapRegion::LogOfHRGrainBytes; + uint log_region_size = G1HeapRegion::LogOfHRGrainBytes; // Limit the expected input values to current known possible values of the // (log) region size. Adjust as necessary after testing if changing the permissible // values for region size. @@ -154,22 +154,22 @@ uint G1CollectedHeap::get_chunks_per_region() { return 1u << (log_region_size / 2 - 4); } -HeapRegion* G1CollectedHeap::new_heap_region(uint hrs_index, - MemRegion mr) { - return new HeapRegion(hrs_index, bot(), mr, &_card_set_config); +G1HeapRegion* G1CollectedHeap::new_heap_region(uint hrs_index, + MemRegion mr) { + return new G1HeapRegion(hrs_index, bot(), mr, &_card_set_config); } // Private methods. -HeapRegion* G1CollectedHeap::new_region(size_t word_size, - HeapRegionType type, - bool do_expand, - uint node_index) { - assert(!is_humongous(word_size) || word_size <= HeapRegion::GrainWords, +G1HeapRegion* G1CollectedHeap::new_region(size_t word_size, + HeapRegionType type, + bool do_expand, + uint node_index) { + assert(!is_humongous(word_size) || word_size <= G1HeapRegion::GrainWords, "the only time we use this to allocate a humongous region is " "when we are allocating a single humongous region"); - HeapRegion* res = _hrm.allocate_free_region(type, node_index); + G1HeapRegion* res = _hrm.allocate_free_region(type, node_index); if (res == nullptr && do_expand) { // Currently, only attempts to allocate GC alloc regions set @@ -180,7 +180,7 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, log_debug(gc, ergo, heap)("Attempt heap expansion (region allocation request failed). Allocation request: " SIZE_FORMAT "B", word_size * HeapWordSize); - assert(word_size * HeapWordSize < HeapRegion::GrainBytes, + assert(word_size * HeapWordSize < G1HeapRegion::GrainBytes, "This kind of expansion should never be more than one region. Size: " SIZE_FORMAT, word_size * HeapWordSize); if (expand_single_region(node_index)) { @@ -194,14 +194,14 @@ HeapRegion* G1CollectedHeap::new_region(size_t word_size, return res; } -void G1CollectedHeap::set_humongous_metadata(HeapRegion* first_hr, +void G1CollectedHeap::set_humongous_metadata(G1HeapRegion* first_hr, uint num_regions, size_t word_size, bool update_remsets) { // Calculate the new top of the humongous object. HeapWord* obj_top = first_hr->bottom() + word_size; // The word size sum of all the regions used - size_t word_size_sum = num_regions * HeapRegion::GrainWords; + size_t word_size_sum = num_regions * G1HeapRegion::GrainWords; assert(word_size <= word_size_sum, "sanity"); // How many words memory we "waste" which cannot hold a filler object. @@ -236,7 +236,7 @@ void G1CollectedHeap::set_humongous_metadata(HeapRegion* first_hr, uint first = first_hr->hrm_index(); uint last = first + num_regions - 1; - HeapRegion* hr = nullptr; + G1HeapRegion* hr = nullptr; for (uint i = first + 1; i <= last; ++i) { hr = region_at(i); hr->hr_clear(false /* clear_space */); @@ -277,12 +277,12 @@ void G1CollectedHeap::set_humongous_metadata(HeapRegion* first_hr, } HeapWord* -G1CollectedHeap::humongous_obj_allocate_initialize_regions(HeapRegion* first_hr, +G1CollectedHeap::humongous_obj_allocate_initialize_regions(G1HeapRegion* first_hr, uint num_regions, size_t word_size) { assert(first_hr != nullptr, "pre-condition"); assert(is_humongous(word_size), "word_size should be humongous"); - assert(num_regions * HeapRegion::GrainWords >= word_size, "pre-condition"); + assert(num_regions * G1HeapRegion::GrainWords >= word_size, "pre-condition"); // Index of last region in the series. uint first = first_hr->hrm_index(); @@ -318,13 +318,13 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(HeapRegion* first_hr, // Next, update the metadata for the regions. set_humongous_metadata(first_hr, num_regions, word_size, true); - HeapRegion* last_hr = region_at(last); + G1HeapRegion* last_hr = region_at(last); size_t used = byte_size(first_hr->bottom(), last_hr->top()); increase_used(used); for (uint i = first; i <= last; ++i) { - HeapRegion *hr = region_at(i); + G1HeapRegion *hr = region_at(i); _humongous_set.add(hr); G1HeapRegionPrinter::alloc(hr); } @@ -334,7 +334,7 @@ G1CollectedHeap::humongous_obj_allocate_initialize_regions(HeapRegion* first_hr, size_t G1CollectedHeap::humongous_obj_size_in_regions(size_t word_size) { assert(is_humongous(word_size), "Object of size " SIZE_FORMAT " must be humongous here", word_size); - return align_up(word_size, HeapRegion::GrainWords) / HeapRegion::GrainWords; + return align_up(word_size, G1HeapRegion::GrainWords) / G1HeapRegion::GrainWords; } // If could fit into free regions w/o expansion, try. @@ -348,7 +348,7 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size) { uint obj_regions = (uint) humongous_obj_size_in_regions(word_size); // Policy: First try to allocate a humongous object in the free list. - HeapRegion* humongous_start = _hrm.allocate_humongous(obj_regions); + G1HeapRegion* humongous_start = _hrm.allocate_humongous(obj_regions); if (humongous_start == nullptr) { // Policy: We could not find enough regions for the humongous object in the // free list. Look through the heap to find a mix of free and uncommitted regions. @@ -473,12 +473,12 @@ template void G1CollectedHeap::iterate_regions_in_range(MemRegion range, const Func& func) { // Mark each G1 region touched by the range as old, add it to // the old set, and set top. - HeapRegion* curr_region = _hrm.addr_to_region(range.start()); - HeapRegion* end_region = _hrm.addr_to_region(range.last()); + G1HeapRegion* curr_region = _hrm.addr_to_region(range.start()); + G1HeapRegion* end_region = _hrm.addr_to_region(range.last()); while (curr_region != nullptr) { bool is_last = curr_region == end_region; - HeapRegion* next_region = is_last ? nullptr : _hrm.next_region_in_heap(curr_region); + G1HeapRegion* next_region = is_last ? nullptr : _hrm.next_region_in_heap(curr_region); func(curr_region, is_last); @@ -504,7 +504,7 @@ HeapWord* G1CollectedHeap::alloc_archive_region(size_t word_size, HeapWord* pref size_t commits = 0; // Attempt to allocate towards the end of the heap. - HeapWord* start_addr = reserved.end() - align_up(word_size, HeapRegion::GrainWords); + HeapWord* start_addr = reserved.end() - align_up(word_size, G1HeapRegion::GrainWords); MemRegion range = MemRegion(start_addr, word_size); HeapWord* last_address = range.last(); if (!_hrm.allocate_containing_regions(range, &commits, workers())) { @@ -513,12 +513,12 @@ HeapWord* G1CollectedHeap::alloc_archive_region(size_t word_size, HeapWord* pref increase_used(word_size * HeapWordSize); if (commits != 0) { log_debug(gc, ergo, heap)("Attempt heap expansion (allocate archive regions). Total size: " SIZE_FORMAT "B", - HeapRegion::GrainWords * HeapWordSize * commits); + G1HeapRegion::GrainWords * HeapWordSize * commits); } // Mark each G1 region touched by the range as old, add it to // the old set, and set top. - auto set_region_to_old = [&] (HeapRegion* r, bool is_last) { + auto set_region_to_old = [&] (G1HeapRegion* r, bool is_last) { assert(r->is_empty(), "Region already in use (%u)", r->hrm_index()); HeapWord* top = is_last ? last_address + 1 : r->end(); @@ -537,7 +537,7 @@ void G1CollectedHeap::populate_archive_regions_bot(MemRegion range) { assert(!is_init_completed(), "Expect to be called at JVM init time"); iterate_regions_in_range(range, - [&] (HeapRegion* r, bool is_last) { + [&] (G1HeapRegion* r, bool is_last) { r->update_bot(); }); } @@ -559,7 +559,7 @@ void G1CollectedHeap::dealloc_archive_regions(MemRegion range) { size_used += range.byte_size(); // Free, empty and uncommit regions with CDS archive content. - auto dealloc_archive_region = [&] (HeapRegion* r, bool is_last) { + auto dealloc_archive_region = [&] (G1HeapRegion* r, bool is_last) { guarantee(r->is_old(), "Expected old region at index %u", r->hrm_index()); _old_set.remove(r); r->set_free(); @@ -572,7 +572,7 @@ void G1CollectedHeap::dealloc_archive_regions(MemRegion range) { if (shrink_count != 0) { log_debug(gc, ergo, heap)("Attempt heap shrinking (CDS archive regions). Total size: " SIZE_FORMAT "B", - HeapRegion::GrainWords * HeapWordSize * shrink_count); + G1HeapRegion::GrainWords * HeapWordSize * shrink_count); // Explicit uncommit. uncommit_regions(shrink_count); } @@ -650,7 +650,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) { result = humongous_obj_allocate(word_size); if (result != nullptr) { policy()->old_gen_alloc_tracker()-> - add_allocated_humongous_bytes_since_last_gc(size_in_regions * HeapRegion::GrainBytes); + add_allocated_humongous_bytes_since_last_gc(size_in_regions * G1HeapRegion::GrainBytes); return result; } @@ -666,7 +666,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) { if (result != nullptr) { size_t size_in_regions = humongous_obj_size_in_regions(word_size); policy()->old_gen_alloc_tracker()-> - record_collection_pause_humongous_allocation(size_in_regions * HeapRegion::GrainBytes); + record_collection_pause_humongous_allocation(size_in_regions * G1HeapRegion::GrainBytes); } return result; } @@ -712,7 +712,7 @@ HeapWord* G1CollectedHeap::attempt_allocation_at_safepoint(size_t word_size, class PostCompactionPrinterClosure: public HeapRegionClosure { public: - bool do_heap_region(HeapRegion* hr) { + bool do_heap_region(G1HeapRegion* hr) { assert(!hr->is_young(), "not expecting to find young regions"); G1HeapRegionPrinter::post_compaction(hr); return false; @@ -991,8 +991,7 @@ HeapWord* G1CollectedHeap::expand_and_allocate(size_t word_size) { bool G1CollectedHeap::expand(size_t expand_bytes, WorkerThreads* pretouch_workers, double* expand_time_ms) { size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); - aligned_expand_bytes = align_up(aligned_expand_bytes, - HeapRegion::GrainBytes); + aligned_expand_bytes = align_up(aligned_expand_bytes, G1HeapRegion::GrainBytes); log_debug(gc, ergo, heap)("Expand the heap. requested expansion amount: " SIZE_FORMAT "B expansion amount: " SIZE_FORMAT "B", expand_bytes, aligned_expand_bytes); @@ -1003,7 +1002,7 @@ bool G1CollectedHeap::expand(size_t expand_bytes, WorkerThreads* pretouch_worker } double expand_heap_start_time_sec = os::elapsedTime(); - uint regions_to_expand = (uint)(aligned_expand_bytes / HeapRegion::GrainBytes); + uint regions_to_expand = (uint)(aligned_expand_bytes / G1HeapRegion::GrainBytes); assert(regions_to_expand > 0, "Must expand by at least one region"); uint expanded_by = _hrm.expand_by(regions_to_expand, pretouch_workers); @@ -1013,7 +1012,7 @@ bool G1CollectedHeap::expand(size_t expand_bytes, WorkerThreads* pretouch_worker assert(expanded_by > 0, "must have failed during commit."); - size_t actual_expand_bytes = expanded_by * HeapRegion::GrainBytes; + size_t actual_expand_bytes = expanded_by * G1HeapRegion::GrainBytes; assert(actual_expand_bytes <= aligned_expand_bytes, "post-condition"); policy()->record_new_heap_size(num_regions()); @@ -1036,12 +1035,11 @@ bool G1CollectedHeap::expand_single_region(uint node_index) { void G1CollectedHeap::shrink_helper(size_t shrink_bytes) { size_t aligned_shrink_bytes = ReservedSpace::page_align_size_down(shrink_bytes); - aligned_shrink_bytes = align_down(aligned_shrink_bytes, - HeapRegion::GrainBytes); - uint num_regions_to_remove = (uint)(shrink_bytes / HeapRegion::GrainBytes); + aligned_shrink_bytes = align_down(aligned_shrink_bytes, G1HeapRegion::GrainBytes); + uint num_regions_to_remove = (uint)(shrink_bytes / G1HeapRegion::GrainBytes); uint num_regions_removed = _hrm.shrink_by(num_regions_to_remove); - size_t shrunk_bytes = num_regions_removed * HeapRegion::GrainBytes; + size_t shrunk_bytes = num_regions_removed * G1HeapRegion::GrainBytes; log_debug(gc, ergo, heap)("Shrink the heap. requested shrinking amount: " SIZE_FORMAT "B aligned shrinking amount: " SIZE_FORMAT "B actual amount shrunk: " SIZE_FORMAT "B", shrink_bytes, aligned_shrink_bytes, shrunk_bytes); @@ -1096,7 +1094,7 @@ class OldRegionSetChecker : public HeapRegionSetChecker { guarantee(Heap_lock->owned_by_self(), "master old set MT safety protocol outside a safepoint"); } } - bool is_correct_type(HeapRegion* hr) { return hr->is_old(); } + bool is_correct_type(G1HeapRegion* hr) { return hr->is_old(); } const char* get_description() { return "Old Regions"; } }; @@ -1120,7 +1118,7 @@ class HumongousRegionSetChecker : public HeapRegionSetChecker { "master humongous set MT safety protocol outside a safepoint"); } } - bool is_correct_type(HeapRegion* hr) { return hr->is_humongous(); } + bool is_correct_type(G1HeapRegion* hr) { return hr->is_humongous(); } const char* get_description() { return "Humongous Regions"; } }; @@ -1179,13 +1177,13 @@ G1CollectedHeap::G1CollectedHeap() : _heap_sizing_policy = G1HeapSizingPolicy::create(this, _policy->analytics()); - _humongous_object_threshold_in_words = humongous_threshold_for(HeapRegion::GrainWords); + _humongous_object_threshold_in_words = humongous_threshold_for(G1HeapRegion::GrainWords); // Since filler arrays are never referenced, we can make them region sized. // This simplifies filling up the region in case we have some potentially // unreferenced (by Java code, but still in use by native code) pinned objects // in there. - _filler_array_max_size = HeapRegion::GrainWords; + _filler_array_max_size = G1HeapRegion::GrainWords; // Override the default _stack_chunk_max_size so that no humongous stack chunks are created _stack_chunk_max_size = _humongous_object_threshold_in_words; @@ -1214,7 +1212,7 @@ G1RegionToSpaceMapper* G1CollectedHeap::create_aux_memory_mapper(const char* des G1RegionToSpaceMapper::create_mapper(rs, size, page_size, - HeapRegion::GrainBytes, + G1HeapRegion::GrainBytes, translation_factor, mtGC); @@ -1260,8 +1258,8 @@ jint G1CollectedHeap::initialize() { size_t reserved_byte_size = G1Arguments::heap_reserved_size_bytes(); // Ensure that the sizes are properly aligned. - Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap"); - Universe::check_alignment(reserved_byte_size, HeapRegion::GrainBytes, "g1 heap"); + Universe::check_alignment(init_byte_size, G1HeapRegion::GrainBytes, "g1 heap"); + Universe::check_alignment(reserved_byte_size, G1HeapRegion::GrainBytes, "g1 heap"); Universe::check_alignment(reserved_byte_size, HeapAlignment, "g1 heap"); // Reserve the maximum. @@ -1270,7 +1268,7 @@ jint G1CollectedHeap::initialize() { // is calculated by subtracting the requested size from the // 32Gb boundary and using the result as the base address for // heap reservation. If the requested size is not aligned to - // HeapRegion::GrainBytes (i.e. the alignment that is passed + // G1HeapRegion::GrainBytes (i.e. the alignment that is passed // into the ReservedHeapSpace constructor) then the actual // base of the reserved heap may end up differing from the // address that was requested (i.e. the preferred heap base). @@ -1302,7 +1300,7 @@ jint G1CollectedHeap::initialize() { G1RegionToSpaceMapper::create_mapper(heap_rs, heap_rs.size(), page_size, - HeapRegion::GrainBytes, + G1HeapRegion::GrainBytes, 1, mtJavaHeap); if(heap_storage == nullptr) { @@ -1350,8 +1348,8 @@ jint G1CollectedHeap::initialize() { _rem_set->initialize(max_reserved_regions()); size_t max_cards_per_region = ((size_t)1 << (sizeof(CardIdx_t)*BitsPerByte-1)) - 1; - guarantee(HeapRegion::CardsPerRegion > 0, "make sure it's initialized"); - guarantee(HeapRegion::CardsPerRegion < max_cards_per_region, + guarantee(G1HeapRegion::CardsPerRegion > 0, "make sure it's initialized"); + guarantee(G1HeapRegion::CardsPerRegion < max_cards_per_region, "too many cards per region"); HeapRegionRemSet::initialize(_reserved); @@ -1361,7 +1359,7 @@ jint G1CollectedHeap::initialize() { _bot = new G1BlockOffsetTable(reserved(), bot_storage); { - size_t granularity = HeapRegion::GrainBytes; + size_t granularity = G1HeapRegion::GrainBytes; _region_attr.initialize(reserved(), granularity); } @@ -1372,7 +1370,7 @@ jint G1CollectedHeap::initialize() { } _workers->initialize_workers(); - _numa->set_region_info(HeapRegion::GrainBytes, page_size); + _numa->set_region_info(G1HeapRegion::GrainBytes, page_size); // Create the G1ConcurrentMark data structure and thread. // (Must do this late, so that "max_[reserved_]regions" is defined.) @@ -1405,9 +1403,9 @@ jint G1CollectedHeap::initialize() { _free_arena_memory_task = new G1MonotonicArenaFreeMemoryTask("Card Set Free Memory Task"); _service_thread->register_task(_free_arena_memory_task); - // Here we allocate the dummy HeapRegion that is required by the + // Here we allocate the dummy G1HeapRegion that is required by the // G1AllocRegion class. - HeapRegion* dummy_region = _hrm.get_dummy_region(); + G1HeapRegion* dummy_region = _hrm.get_dummy_region(); // We'll re-use the same region whether the alloc region will // require BOT updates or not and, if it doesn't, then a non-young @@ -1521,7 +1519,7 @@ void G1CollectedHeap::ref_processing_init() { } size_t G1CollectedHeap::capacity() const { - return _hrm.length() * HeapRegion::GrainBytes; + return _hrm.length() * G1HeapRegion::GrainBytes; } size_t G1CollectedHeap::unused_committed_regions_in_bytes() const { @@ -1542,7 +1540,7 @@ class SumUsedClosure: public HeapRegionClosure { size_t _used; public: SumUsedClosure() : _used(0) {} - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { _used += r->used(); return false; } @@ -1887,13 +1885,13 @@ bool G1CollectedHeap::is_in(const void* p) const { // Iteration functions. -// Iterates an ObjectClosure over all objects within a HeapRegion. +// Iterates an ObjectClosure over all objects within a G1HeapRegion. class IterateObjectClosureRegionClosure: public HeapRegionClosure { ObjectClosure* _cl; public: IterateObjectClosureRegionClosure(ObjectClosure* cl) : _cl(cl) {} - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { if (!r->is_continues_humongous()) { r->object_iterate(_cl); } @@ -1986,7 +1984,7 @@ void G1CollectedHeap::par_iterate_regions_array(HeapRegionClosure* cl, do { uint region_idx = regions[cur_pos]; if (hr_claimer == nullptr || hr_claimer->claim_region(region_idx)) { - HeapRegion* r = region_at(region_idx); + G1HeapRegion* r = region_at(region_idx); bool result = cl->do_heap_region(r); guarantee(!result, "Must not cancel iteration"); } @@ -1999,9 +1997,9 @@ void G1CollectedHeap::par_iterate_regions_array(HeapRegionClosure* cl, } HeapWord* G1CollectedHeap::block_start(const void* addr) const { - HeapRegion* hr = heap_region_containing(addr); + G1HeapRegion* hr = heap_region_containing(addr); // The CollectedHeap API requires us to not fail for any given address within - // the heap. HeapRegion::block_start() has been optimized to not accept addresses + // the heap. G1HeapRegion::block_start() has been optimized to not accept addresses // outside of the allocated area. if (addr >= hr->top()) { return nullptr; @@ -2010,16 +2008,16 @@ HeapWord* G1CollectedHeap::block_start(const void* addr) const { } bool G1CollectedHeap::block_is_obj(const HeapWord* addr) const { - HeapRegion* hr = heap_region_containing(addr); + G1HeapRegion* hr = heap_region_containing(addr); return hr->block_is_obj(addr, hr->parsable_bottom_acquire()); } size_t G1CollectedHeap::tlab_capacity(Thread* ignored) const { - return (_policy->young_list_target_length() - _survivor.length()) * HeapRegion::GrainBytes; + return (_policy->young_list_target_length() - _survivor.length()) * G1HeapRegion::GrainBytes; } size_t G1CollectedHeap::tlab_used(Thread* ignored) const { - return _eden.length() * HeapRegion::GrainBytes; + return _eden.length() * G1HeapRegion::GrainBytes; } // For G1 TLABs should not contain humongous objects, so the maximum TLAB size @@ -2033,7 +2031,7 @@ size_t G1CollectedHeap::unsafe_max_tlab_alloc(Thread* ignored) const { } size_t G1CollectedHeap::max_capacity() const { - return max_regions() * HeapRegion::GrainBytes; + return max_regions() * G1HeapRegion::GrainBytes; } void G1CollectedHeap::prepare_for_verify() { @@ -2052,14 +2050,14 @@ class PrintRegionClosure: public HeapRegionClosure { outputStream* _st; public: PrintRegionClosure(outputStream* st) : _st(st) {} - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { r->print_on(_st); return false; } }; bool G1CollectedHeap::is_obj_dead_cond(const oop obj, - const HeapRegion* hr, + const G1HeapRegion* hr, const VerifyOption vo) const { switch (vo) { case VerifyOption::G1UseConcMarking: return is_obj_dead(obj, hr); @@ -2096,13 +2094,13 @@ void G1CollectedHeap::print_on(outputStream* st) const { p2i(_hrm.reserved().start()), p2i(_hrm.reserved().end())); st->cr(); - st->print(" region size " SIZE_FORMAT "K, ", HeapRegion::GrainBytes / K); + st->print(" region size " SIZE_FORMAT "K, ", G1HeapRegion::GrainBytes / K); uint young_regions = young_regions_count(); st->print("%u young (" SIZE_FORMAT "K), ", young_regions, - (size_t) young_regions * HeapRegion::GrainBytes / K); + (size_t) young_regions * G1HeapRegion::GrainBytes / K); uint survivor_regions = survivor_regions_count(); st->print("%u survivors (" SIZE_FORMAT "K)", survivor_regions, - (size_t) survivor_regions * HeapRegion::GrainBytes / K); + (size_t) survivor_regions * G1HeapRegion::GrainBytes / K); st->cr(); if (_numa->is_enabled()) { uint num_nodes = _numa->num_active_nodes(); @@ -2169,7 +2167,7 @@ G1HeapSummary G1CollectedHeap::create_g1_heap_summary() { size_t heap_used = Heap_lock->owned_by_self() ? used() : used_unlocked(); size_t eden_capacity_bytes = - (policy()->young_list_target_length() * HeapRegion::GrainBytes) - survivor_used_bytes; + (policy()->young_list_target_length() * G1HeapRegion::GrainBytes) - survivor_used_bytes; VirtualSpaceSummary heap_summary = create_heap_space_summary(); return G1HeapSummary(heap_summary, heap_used, eden_used_bytes, eden_capacity_bytes, @@ -2280,7 +2278,7 @@ void G1CollectedHeap::start_concurrent_cycle(bool concurrent_operation_is_full_m CGC_lock->notify(); } -bool G1CollectedHeap::is_potential_eager_reclaim_candidate(HeapRegion* r) const { +bool G1CollectedHeap::is_potential_eager_reclaim_candidate(G1HeapRegion* r) const { // We don't nominate objects with many remembered set entries, on // the assumption that such objects are likely still live. HeapRegionRemSet* rem_set = r->rem_set(); @@ -2292,7 +2290,7 @@ bool G1CollectedHeap::is_potential_eager_reclaim_candidate(HeapRegion* r) const void G1CollectedHeap::verify_region_attr_remset_is_tracked() { class VerifyRegionAttrRemSet : public HeapRegionClosure { public: - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); bool const remset_is_tracked = g1h->region_attr(r->bottom()).remset_is_tracked(); assert(r->rem_set()->is_tracked() == remset_is_tracked, @@ -2545,7 +2543,7 @@ class G1BulkUnregisterNMethodTask : public WorkerTask { class UnregisterNMethodsHeapRegionClosure : public HeapRegionClosure { public: - bool do_heap_region(HeapRegion* hr) { + bool do_heap_region(G1HeapRegion* hr) { hr->rem_set()->bulk_remove_code_roots(); return false; } @@ -2612,11 +2610,11 @@ void G1CollectedHeap::record_obj_copy_mem_stats() { create_g1_evac_summary(&_old_evac_stats)); } -void G1CollectedHeap::clear_bitmap_for_region(HeapRegion* hr) { +void G1CollectedHeap::clear_bitmap_for_region(G1HeapRegion* hr) { concurrent_mark()->clear_bitmap_for_region(hr); } -void G1CollectedHeap::free_region(HeapRegion* hr, FreeRegionList* free_list) { +void G1CollectedHeap::free_region(G1HeapRegion* hr, FreeRegionList* free_list) { assert(!hr->is_free(), "the region should not be free"); assert(!hr->is_empty(), "the region should not be empty"); assert(_hrm.is_available(hr->hrm_index()), "region should be committed"); @@ -2632,12 +2630,12 @@ void G1CollectedHeap::free_region(HeapRegion* hr, FreeRegionList* free_list) { } } -void G1CollectedHeap::retain_region(HeapRegion* hr) { +void G1CollectedHeap::retain_region(G1HeapRegion* hr) { MutexLocker x(G1RareEvent_lock, Mutex::_no_safepoint_check_flag); collection_set()->candidates()->add_retained_region_unsorted(hr); } -void G1CollectedHeap::free_humongous_region(HeapRegion* hr, +void G1CollectedHeap::free_humongous_region(G1HeapRegion* hr, FreeRegionList* free_list) { assert(hr->is_humongous(), "this is only for humongous regions"); hr->clear_humongous(); @@ -2682,7 +2680,7 @@ void G1CollectedHeap::rebuild_free_region_list() { class G1AbandonCollectionSetClosure : public HeapRegionClosure { public: - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { assert(r->in_collection_set(), "Region %u must have been in collection set", r->hrm_index()); G1CollectedHeap::heap()->clear_region_attr(r); r->clear_young_index_in_cset(); @@ -2698,11 +2696,11 @@ void G1CollectedHeap::abandon_collection_set(G1CollectionSet* collection_set) { collection_set->stop_incremental_building(); } -bool G1CollectedHeap::is_old_gc_alloc_region(HeapRegion* hr) { +bool G1CollectedHeap::is_old_gc_alloc_region(G1HeapRegion* hr) { return _allocator->is_retained_old_region(hr); } -void G1CollectedHeap::set_region_short_lived_locked(HeapRegion* hr) { +void G1CollectedHeap::set_region_short_lived_locked(G1HeapRegion* hr) { _eden.add(hr); _policy->set_region_eden(hr); } @@ -2714,7 +2712,7 @@ class NoYoungRegionsClosure: public HeapRegionClosure { bool _success; public: NoYoungRegionsClosure() : _success(true) { } - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { if (r->is_young()) { log_error(gc, verify)("Region [" PTR_FORMAT ", " PTR_FORMAT ") tagged as young", p2i(r->bottom()), p2i(r->end())); @@ -2737,8 +2735,8 @@ bool G1CollectedHeap::check_young_list_empty() { #endif // ASSERT -// Remove the given HeapRegion from the appropriate region set. -void G1CollectedHeap::prepare_region_for_full_compaction(HeapRegion* hr) { +// Remove the given G1HeapRegion from the appropriate region set. +void G1CollectedHeap::prepare_region_for_full_compaction(G1HeapRegion* hr) { if (hr->is_humongous()) { _humongous_set.remove(hr); } else if (hr->is_old()) { @@ -2795,7 +2793,7 @@ class RebuildRegionSetsClosure : public HeapRegionClosure { } } - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { if (r->is_empty()) { assert(r->rem_set()->is_empty(), "Empty regions should have empty remembered sets."); // Add free regions to the free list @@ -2845,15 +2843,15 @@ void G1CollectedHeap::rebuild_region_sets(bool free_list_only) { // Methods for the mutator alloc region -HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size, +G1HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size, uint node_index) { assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); bool should_allocate = policy()->should_allocate_mutator_region(); if (should_allocate) { - HeapRegion* new_alloc_region = new_region(word_size, - HeapRegionType::Eden, - false /* do_expand */, - node_index); + G1HeapRegion* new_alloc_region = new_region(word_size, + HeapRegionType::Eden, + false /* do_expand */, + node_index); if (new_alloc_region != nullptr) { set_region_short_lived_locked(new_alloc_region); G1HeapRegionPrinter::alloc(new_alloc_region); @@ -2864,7 +2862,7 @@ HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size, return nullptr; } -void G1CollectedHeap::retire_mutator_alloc_region(HeapRegion* alloc_region, +void G1CollectedHeap::retire_mutator_alloc_region(G1HeapRegion* alloc_region, size_t allocated_bytes) { assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */); assert(alloc_region->is_eden(), "all mutator alloc regions should be eden"); @@ -2890,7 +2888,7 @@ bool G1CollectedHeap::has_more_regions(G1HeapRegionAttr dest) { } } -HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegionAttr dest, uint node_index) { +G1HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegionAttr dest, uint node_index) { assert(FreeList_lock->owned_by_self(), "pre-condition"); if (!has_more_regions(dest)) { @@ -2904,10 +2902,10 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegionA type = HeapRegionType::Old; } - HeapRegion* new_alloc_region = new_region(word_size, - type, - true /* do_expand */, - node_index); + G1HeapRegion* new_alloc_region = new_region(word_size, + type, + true /* do_expand */, + node_index); if (new_alloc_region != nullptr) { if (type.is_survivor()) { @@ -2925,7 +2923,7 @@ HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size, G1HeapRegionA return nullptr; } -void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region, +void G1CollectedHeap::retire_gc_alloc_region(G1HeapRegion* alloc_region, size_t allocated_bytes, G1HeapRegionAttr dest) { _bytes_used_during_gc += allocated_bytes; @@ -2943,14 +2941,14 @@ void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region, G1HeapRegionPrinter::retire(alloc_region); } -HeapRegion* G1CollectedHeap::alloc_highest_free_region() { +G1HeapRegion* G1CollectedHeap::alloc_highest_free_region() { bool expanded = false; uint index = _hrm.find_highest_free(&expanded); if (index != G1_NO_HRM_INDEX) { if (expanded) { log_debug(gc, ergo, heap)("Attempt heap expansion (requested address range outside heap bounds). region size: " SIZE_FORMAT "B", - HeapRegion::GrainWords * HeapWordSize); + G1HeapRegion::GrainWords * HeapWordSize); } return _hrm.allocate_free_regions_starting_at(index, 1); } @@ -2976,7 +2974,7 @@ class RegisterNMethodOopClosure: public OopClosure { oop heap_oop = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(heap_oop)) { oop obj = CompressedOops::decode_not_null(heap_oop); - HeapRegion* hr = _g1h->heap_region_containing(obj); + G1HeapRegion* hr = _g1h->heap_region_containing(obj); assert(!hr->is_continues_humongous(), "trying to add code root " PTR_FORMAT " in continuation of humongous region " HR_FORMAT " starting at " HR_FORMAT, @@ -3045,7 +3043,7 @@ GrowableArray G1CollectedHeap::memory_pools() { } void G1CollectedHeap::fill_with_dummy_object(HeapWord* start, HeapWord* end, bool zap) { - HeapRegion* region = heap_region_containing(start); + G1HeapRegion* region = heap_region_containing(start); region->fill_with_dummy_object(start, pointer_delta(end, start), zap); } diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 4695d12b435..1cf89879fd7 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -79,7 +79,7 @@ class G1RemSet; class G1ServiceTask; class G1ServiceThread; class GCMemoryManager; -class HeapRegion; +class G1HeapRegion; class MemoryPool; class nmethod; class ReferenceProcessor; @@ -196,7 +196,7 @@ class G1CollectedHeap : public CollectedHeap { // Start a new incremental collection set for the next pause. void start_new_collection_set(); - void prepare_region_for_full_compaction(HeapRegion* hr); + void prepare_region_for_full_compaction(G1HeapRegion* hr); private: // Rebuilds the region sets / lists so that they are repopulated to @@ -382,20 +382,20 @@ class G1CollectedHeap : public CollectedHeap { G1CollectionSet _collection_set; - // Try to allocate a single non-humongous HeapRegion sufficient for + // Try to allocate a single non-humongous G1HeapRegion sufficient for // an allocation of the given word_size. If do_expand is true, // attempt to expand the heap if necessary to satisfy the allocation // request. 'type' takes the type of region to be allocated. (Use constants // Old, Eden, Humongous, Survivor defined in HeapRegionType.) - HeapRegion* new_region(size_t word_size, - HeapRegionType type, - bool do_expand, - uint node_index = G1NUMA::AnyNodeIndex); + G1HeapRegion* new_region(size_t word_size, + HeapRegionType type, + bool do_expand, + uint node_index = G1NUMA::AnyNodeIndex); // Initialize a contiguous set of free regions of length num_regions // and starting at index first so that they appear as a single // humongous region. - HeapWord* humongous_obj_allocate_initialize_regions(HeapRegion* first_hr, + HeapWord* humongous_obj_allocate_initialize_regions(G1HeapRegion* first_hr, uint num_regions, size_t word_size); @@ -465,14 +465,14 @@ class G1CollectedHeap : public CollectedHeap { // These methods are the "callbacks" from the G1AllocRegion class. // For mutator alloc regions. - HeapRegion* new_mutator_alloc_region(size_t word_size, uint node_index); - void retire_mutator_alloc_region(HeapRegion* alloc_region, + G1HeapRegion* new_mutator_alloc_region(size_t word_size, uint node_index); + void retire_mutator_alloc_region(G1HeapRegion* alloc_region, size_t allocated_bytes); // For GC alloc regions. bool has_more_regions(G1HeapRegionAttr dest); - HeapRegion* new_gc_alloc_region(size_t word_size, G1HeapRegionAttr dest, uint node_index); - void retire_gc_alloc_region(HeapRegion* alloc_region, + G1HeapRegion* new_gc_alloc_region(size_t word_size, G1HeapRegionAttr dest, uint node_index); + void retire_gc_alloc_region(G1HeapRegion* alloc_region, size_t allocated_bytes, G1HeapRegionAttr dest); // - if clear_all_soft_refs is true, all soft references should be @@ -572,7 +572,7 @@ class G1CollectedHeap : public CollectedHeap { // Expand the garbage-first heap by at least the given size (in bytes!). // Returns true if the heap was expanded by the requested amount; // false otherwise. - // (Rounds up to a HeapRegion boundary.) + // (Rounds up to a G1HeapRegion boundary.) bool expand(size_t expand_bytes, WorkerThreads* pretouch_workers = nullptr, double* expand_time_ms = nullptr); bool expand_single_region(uint node_index); @@ -593,7 +593,7 @@ class G1CollectedHeap : public CollectedHeap { void gc_epilogue(bool full); // Does the given region fulfill remembered set based eager reclaim candidate requirements? - bool is_potential_eager_reclaim_candidate(HeapRegion* r) const; + bool is_potential_eager_reclaim_candidate(G1HeapRegion* r) const; inline bool is_humongous_reclaim_candidate(uint region); @@ -604,22 +604,22 @@ class G1CollectedHeap : public CollectedHeap { // Register the given region to be part of the collection set. inline void register_humongous_candidate_region_with_region_attr(uint index); - void set_humongous_metadata(HeapRegion* first_hr, + void set_humongous_metadata(G1HeapRegion* first_hr, uint num_regions, size_t word_size, bool update_remsets); // We register a region with the fast "in collection set" test. We // simply set to true the array slot corresponding to this region. - void register_young_region_with_region_attr(HeapRegion* r) { + void register_young_region_with_region_attr(G1HeapRegion* r) { _region_attr.set_in_young(r->hrm_index(), r->has_pinned_objects()); } - inline void register_new_survivor_region_with_region_attr(HeapRegion* r); - inline void register_region_with_region_attr(HeapRegion* r); - inline void register_old_region_with_region_attr(HeapRegion* r); - inline void register_optional_region_with_region_attr(HeapRegion* r); + inline void register_new_survivor_region_with_region_attr(G1HeapRegion* r); + inline void register_region_with_region_attr(G1HeapRegion* r); + inline void register_old_region_with_region_attr(G1HeapRegion* r); + inline void register_optional_region_with_region_attr(G1HeapRegion* r); - void clear_region_attr(const HeapRegion* hr) { + void clear_region_attr(const G1HeapRegion* hr) { _region_attr.clear(hr); } @@ -631,7 +631,7 @@ class G1CollectedHeap : public CollectedHeap { // for all regions. void verify_region_attr_remset_is_tracked() PRODUCT_RETURN; - void clear_bitmap_for_region(HeapRegion* hr); + void clear_bitmap_for_region(G1HeapRegion* hr); bool is_user_requested_concurrent_full_gc(GCCause::Cause cause); @@ -667,11 +667,11 @@ class G1CollectedHeap : public CollectedHeap { } // Allocates a new heap region instance. - HeapRegion* new_heap_region(uint hrs_index, MemRegion mr); + G1HeapRegion* new_heap_region(uint hrs_index, MemRegion mr); // Allocate the highest free region in the reserved heap. This will commit // regions as necessary. - HeapRegion* alloc_highest_free_region(); + G1HeapRegion* alloc_highest_free_region(); // Frees a region by resetting its metadata and adding it to the free list // passed as a parameter (this is usually a local list which will be appended @@ -679,10 +679,10 @@ class G1CollectedHeap : public CollectedHeap { // in another way). // Callers must ensure they are the only one calling free on the given region // at the same time. - void free_region(HeapRegion* hr, FreeRegionList* free_list); + void free_region(G1HeapRegion* hr, FreeRegionList* free_list); // Add the given region to the retained regions collection set candidates. - void retain_region(HeapRegion* hr); + void retain_region(G1HeapRegion* hr); // It dirties the cards that cover the block so that the post // write barrier never queues anything when updating objects on this // block. It is assumed (and in fact we assert) that the block @@ -696,10 +696,10 @@ class G1CollectedHeap : public CollectedHeap { // list later). // The method assumes that only a single thread is ever calling // this for a particular region at once. - void free_humongous_region(HeapRegion* hr, + void free_humongous_region(G1HeapRegion* hr, FreeRegionList* free_list); - // Execute func(HeapRegion* r, bool is_last) on every region covered by the + // Execute func(G1HeapRegion* r, bool is_last) on every region covered by the // given range. template void iterate_regions_in_range(MemRegion range, const Func& func); @@ -725,7 +725,7 @@ class G1CollectedHeap : public CollectedHeap { private: // Shrink the garbage-first heap by at most the given size (in bytes!). - // (Rounds down to a HeapRegion boundary.) + // (Rounds down to a G1HeapRegion boundary.) void shrink(size_t shrink_bytes); void shrink_helper(size_t expand_bytes); @@ -918,7 +918,7 @@ class G1CollectedHeap : public CollectedHeap { const G1CollectionSet* collection_set() const { return &_collection_set; } G1CollectionSet* collection_set() { return &_collection_set; } - inline bool is_collection_set_candidate(const HeapRegion* r) const; + inline bool is_collection_set_candidate(const G1HeapRegion* r) const; void initialize_serviceability() override; MemoryUsage memory_usage() override; @@ -993,21 +993,21 @@ class G1CollectedHeap : public CollectedHeap { uint num_used_regions() const { return num_regions() - num_free_regions(); } #ifdef ASSERT - bool is_on_master_free_list(HeapRegion* hr) { + bool is_on_master_free_list(G1HeapRegion* hr) { return _hrm.is_free(hr); } #endif // ASSERT - inline void old_set_add(HeapRegion* hr); - inline void old_set_remove(HeapRegion* hr); + inline void old_set_add(G1HeapRegion* hr); + inline void old_set_remove(G1HeapRegion* hr); size_t non_young_capacity_bytes() { - return (old_regions_count() + humongous_regions_count()) * HeapRegion::GrainBytes; + return (old_regions_count() + humongous_regions_count()) * G1HeapRegion::GrainBytes; } // Determine whether the given region is one that we are using as an // old GC alloc region. - bool is_old_gc_alloc_region(HeapRegion* hr); + bool is_old_gc_alloc_region(G1HeapRegion* hr); // Perform a collection of the heap; intended for use in implementing // "System.gc". This probably implies as full a collection as the @@ -1029,7 +1029,7 @@ class G1CollectedHeap : public CollectedHeap { // Return "TRUE" iff the given object address is within the collection // set. Assumes that the reference points into the heap. - inline bool is_in_cset(const HeapRegion* hr) const; + inline bool is_in_cset(const G1HeapRegion* hr) const; inline bool is_in_cset(oop obj) const; inline bool is_in_cset(HeapWord* addr) const; @@ -1076,13 +1076,13 @@ class G1CollectedHeap : public CollectedHeap { void heap_region_iterate(HeapRegionIndexClosure* blk) const; // Return the region with the given index. It assumes the index is valid. - inline HeapRegion* region_at(uint index) const; - inline HeapRegion* region_at_or_null(uint index) const; + inline G1HeapRegion* region_at(uint index) const; + inline G1HeapRegion* region_at_or_null(uint index) const; // Iterate over the regions that the humongous object starting at the given - // region and apply the given method with the signature f(HeapRegion*) on them. + // region and apply the given method with the signature f(G1HeapRegion*) on them. template - void humongous_obj_regions_iterate(HeapRegion* start, const Func& f); + void humongous_obj_regions_iterate(G1HeapRegion* start, const Func& f); // Calculate the region index of the given address. Given address must be // within the heap. @@ -1130,12 +1130,12 @@ class G1CollectedHeap : public CollectedHeap { size_t length, uint worker_id) const; - // Returns the HeapRegion that contains addr. addr must not be null. - inline HeapRegion* heap_region_containing(const void* addr) const; + // Returns the G1HeapRegion that contains addr. addr must not be null. + inline G1HeapRegion* heap_region_containing(const void* addr) const; - // Returns the HeapRegion that contains addr, or null if that is an uncommitted + // Returns the G1HeapRegion that contains addr, or null if that is an uncommitted // region. addr must not be null. - inline HeapRegion* heap_region_containing_or_null(const void* addr) const; + inline G1HeapRegion* heap_region_containing_or_null(const void* addr) const; // A CollectedHeap is divided into a dense sequence of "blocks"; that is, // each address in the (reserved) heap is a member of exactly @@ -1197,7 +1197,7 @@ class G1CollectedHeap : public CollectedHeap { return named_heap(CollectedHeap::G1); } - void set_region_short_lived_locked(HeapRegion* hr); + void set_region_short_lived_locked(G1HeapRegion* hr); // add appropriate methods for any other surv rate groups G1SurvivorRegions* survivor() { return &_survivor; } @@ -1221,7 +1221,7 @@ class G1CollectedHeap : public CollectedHeap { inline static bool is_obj_filler(const oop obj); // Determine if an object is dead, given the object and also // the region to which the object belongs. - inline bool is_obj_dead(const oop obj, const HeapRegion* hr) const; + inline bool is_obj_dead(const oop obj, const G1HeapRegion* hr) const; // Determine if an object is dead, given only the object itself. // This will find the region to which the object belongs and @@ -1229,7 +1229,7 @@ class G1CollectedHeap : public CollectedHeap { // If obj is null it is not dead. inline bool is_obj_dead(const oop obj) const; - inline bool is_obj_dead_full(const oop obj, const HeapRegion* hr) const; + inline bool is_obj_dead_full(const oop obj, const G1HeapRegion* hr) const; inline bool is_obj_dead_full(const oop obj) const; // Mark the live object that failed evacuation in the bitmap. @@ -1286,7 +1286,7 @@ class G1CollectedHeap : public CollectedHeap { // are the same as those above. bool is_obj_dead_cond(const oop obj, - const HeapRegion* hr, + const G1HeapRegion* hr, const VerifyOption vo) const; bool is_obj_dead_cond(const oop obj, diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 0a4ee053548..ed594d72d06 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -103,17 +103,17 @@ inline size_t G1CollectedHeap::clamp_plab_size(size_t value) const { // Inline functions for G1CollectedHeap // Return the region with the given index. It assumes the index is valid. -inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm.at(index); } +inline G1HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm.at(index); } // Return the region with the given index, or null if unmapped. It assumes the index is valid. -inline HeapRegion* G1CollectedHeap::region_at_or_null(uint index) const { return _hrm.at_or_null(index); } +inline G1HeapRegion* G1CollectedHeap::region_at_or_null(uint index) const { return _hrm.at_or_null(index); } template -inline void G1CollectedHeap::humongous_obj_regions_iterate(HeapRegion* start, const Func& f) { +inline void G1CollectedHeap::humongous_obj_regions_iterate(G1HeapRegion* start, const Func& f) { assert(start->is_starts_humongous(), "must be"); do { - HeapRegion* next = _hrm.next_region_in_humongous(start); + G1HeapRegion* next = _hrm.next_region_in_humongous(start); f(start); start = next; } while (start != nullptr); @@ -123,29 +123,29 @@ inline uint G1CollectedHeap::addr_to_region(const void* addr) const { assert(is_in_reserved(addr), "Cannot calculate region index for address " PTR_FORMAT " that is outside of the heap [" PTR_FORMAT ", " PTR_FORMAT ")", p2i(addr), p2i(reserved().start()), p2i(reserved().end())); - return (uint)(pointer_delta(addr, reserved().start(), sizeof(uint8_t)) >> HeapRegion::LogOfHRGrainBytes); + return (uint)(pointer_delta(addr, reserved().start(), sizeof(uint8_t)) >> G1HeapRegion::LogOfHRGrainBytes); } inline HeapWord* G1CollectedHeap::bottom_addr_for_region(uint index) const { - return _hrm.reserved().start() + index * HeapRegion::GrainWords; + return _hrm.reserved().start() + index * G1HeapRegion::GrainWords; } -inline HeapRegion* G1CollectedHeap::heap_region_containing(const void* addr) const { +inline G1HeapRegion* G1CollectedHeap::heap_region_containing(const void* addr) const { uint const region_idx = addr_to_region(addr); return region_at(region_idx); } -inline HeapRegion* G1CollectedHeap::heap_region_containing_or_null(const void* addr) const { +inline G1HeapRegion* G1CollectedHeap::heap_region_containing_or_null(const void* addr) const { uint const region_idx = addr_to_region(addr); return region_at_or_null(region_idx); } -inline void G1CollectedHeap::old_set_add(HeapRegion* hr) { +inline void G1CollectedHeap::old_set_add(G1HeapRegion* hr) { _old_set.add(hr); } -inline void G1CollectedHeap::old_set_remove(HeapRegion* hr) { +inline void G1CollectedHeap::old_set_remove(G1HeapRegion* hr) { _old_set.remove(hr); } @@ -160,7 +160,7 @@ G1CollectedHeap::dirty_young_block(HeapWord* start, size_t word_size) { // Assign the containing region to containing_hr so that we don't // have to keep calling heap_region_containing() in the // asserts below. - DEBUG_ONLY(HeapRegion* containing_hr = heap_region_containing(start);) + DEBUG_ONLY(G1HeapRegion* containing_hr = heap_region_containing(start);) assert(word_size > 0, "pre-condition"); assert(containing_hr->is_in(start), "it should contain start"); assert(containing_hr->is_young(), "it should be young"); @@ -193,7 +193,7 @@ inline bool G1CollectedHeap::is_in_cset(HeapWord* addr) const { return _region_attr.is_in_cset(addr); } -bool G1CollectedHeap::is_in_cset(const HeapRegion* hr) const { +bool G1CollectedHeap::is_in_cset(const G1HeapRegion* hr) const { return _region_attr.is_in_cset(hr); } @@ -215,23 +215,23 @@ void G1CollectedHeap::register_humongous_candidate_region_with_region_attr(uint _region_attr.set_humongous_candidate(index); } -void G1CollectedHeap::register_new_survivor_region_with_region_attr(HeapRegion* r) { +void G1CollectedHeap::register_new_survivor_region_with_region_attr(G1HeapRegion* r) { _region_attr.set_new_survivor_region(r->hrm_index()); } -void G1CollectedHeap::register_region_with_region_attr(HeapRegion* r) { +void G1CollectedHeap::register_region_with_region_attr(G1HeapRegion* r) { _region_attr.set_remset_is_tracked(r->hrm_index(), r->rem_set()->is_tracked()); _region_attr.set_is_pinned(r->hrm_index(), r->has_pinned_objects()); } -void G1CollectedHeap::register_old_region_with_region_attr(HeapRegion* r) { +void G1CollectedHeap::register_old_region_with_region_attr(G1HeapRegion* r) { assert(!r->has_pinned_objects(), "must be"); assert(r->rem_set()->is_complete(), "must be"); _region_attr.set_in_old(r->hrm_index(), r->rem_set()->is_tracked()); _rem_set->exclude_region_from_scan(r->hrm_index()); } -void G1CollectedHeap::register_optional_region_with_region_attr(HeapRegion* r) { +void G1CollectedHeap::register_optional_region_with_region_attr(G1HeapRegion* r) { _region_attr.set_optional(r->hrm_index(), r->rem_set()->is_tracked()); } @@ -252,7 +252,7 @@ inline bool G1CollectedHeap::is_obj_filler(const oop obj) { return k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(); } -inline bool G1CollectedHeap::is_obj_dead(const oop obj, const HeapRegion* hr) const { +inline bool G1CollectedHeap::is_obj_dead(const oop obj, const G1HeapRegion* hr) const { if (hr->is_in_parsable_area(obj)) { // This object is in the parsable part of the heap, live unless scrubbed. return is_obj_filler(obj); @@ -286,7 +286,7 @@ inline bool G1CollectedHeap::is_obj_dead(const oop obj) const { return is_obj_dead(obj, heap_region_containing(obj)); } -inline bool G1CollectedHeap::is_obj_dead_full(const oop obj, const HeapRegion* hr) const { +inline bool G1CollectedHeap::is_obj_dead_full(const oop obj, const G1HeapRegion* hr) const { return !is_marked(obj); } @@ -311,7 +311,7 @@ inline void G1CollectedHeap::set_humongous_is_live(oop obj) { } } -inline bool G1CollectedHeap::is_collection_set_candidate(const HeapRegion* r) const { +inline bool G1CollectedHeap::is_collection_set_candidate(const G1HeapRegion* r) const { const G1CollectionSetCandidates* candidates = collection_set()->candidates(); return candidates->contains(r); } diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index 9174221b21e..a70d003ab53 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -95,7 +95,7 @@ void G1CollectionSet::abandon_all_candidates() { _optional_old_regions.clear(); } -void G1CollectionSet::add_old_region(HeapRegion* hr) { +void G1CollectionSet::add_old_region(G1HeapRegion* hr) { assert_at_safepoint_on_vm_thread(); assert(_inc_build_state == Active, @@ -134,7 +134,7 @@ void G1CollectionSet::iterate(HeapRegionClosure* cl) const { OrderAccess::loadload(); for (uint i = 0; i < len; i++) { - HeapRegion* r = _g1h->region_at(_collection_set_regions[i]); + G1HeapRegion* r = _g1h->region_at(_collection_set_regions[i]); bool result = cl->do_heap_region(r); if (result) { cl->set_incomplete(); @@ -152,7 +152,7 @@ void G1CollectionSet::par_iterate(HeapRegionClosure* cl, void G1CollectionSet::iterate_optional(HeapRegionClosure* cl) const { assert_at_safepoint(); - for (HeapRegion* r : _optional_old_regions) { + for (G1HeapRegion* r : _optional_old_regions) { bool result = cl->do_heap_region(r); guarantee(!result, "Must not cancel iteration"); } @@ -176,7 +176,7 @@ void G1CollectionSet::iterate_part_from(HeapRegionClosure* cl, worker_id); } -void G1CollectionSet::add_young_region_common(HeapRegion* hr) { +void G1CollectionSet::add_young_region_common(G1HeapRegion* hr) { assert(hr->is_young(), "invariant"); assert(_inc_build_state == Active, "Precondition"); @@ -196,12 +196,12 @@ void G1CollectionSet::add_young_region_common(HeapRegion* hr) { _collection_set_cur_length++; } -void G1CollectionSet::add_survivor_regions(HeapRegion* hr) { +void G1CollectionSet::add_survivor_regions(G1HeapRegion* hr) { assert(hr->is_survivor(), "Must only add survivor regions, but is %s", hr->get_type_str()); add_young_region_common(hr); } -void G1CollectionSet::add_eden_region(HeapRegion* hr) { +void G1CollectionSet::add_eden_region(G1HeapRegion* hr) { assert(hr->is_eden(), "Must only add eden regions, but is %s", hr->get_type_str()); add_young_region_common(hr); } @@ -213,7 +213,7 @@ class G1VerifyYoungAgesClosure : public HeapRegionClosure { G1VerifyYoungAgesClosure() : HeapRegionClosure(), _valid(true) { } - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { guarantee(r->is_young(), "Region must be young but is %s", r->get_type_str()); if (!r->has_surv_rate_group()) { @@ -251,7 +251,7 @@ class G1PrintCollectionSetDetailClosure : public HeapRegionClosure { public: G1PrintCollectionSetDetailClosure(outputStream* st) : HeapRegionClosure(), _st(st) { } - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { assert(r->in_collection_set(), "Region %u should be in collection set", r->hrm_index()); G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); _st->print_cr(" " HR_FORMAT ", TAMS: " PTR_FORMAT " PB: " PTR_FORMAT ", age: %4d", @@ -387,7 +387,7 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { } void G1CollectionSet::move_candidates_to_collection_set(G1CollectionCandidateRegionList* regions) { - for (HeapRegion* r : *regions) { + for (G1HeapRegion* r : *regions) { _g1h->clear_region_attr(r); add_old_region(r); } @@ -396,7 +396,7 @@ void G1CollectionSet::move_candidates_to_collection_set(G1CollectionCandidateReg void G1CollectionSet::prepare_optional_regions(G1CollectionCandidateRegionList* regions){ uint cur_index = 0; - for (HeapRegion* r : *regions) { + for (G1HeapRegion* r : *regions) { assert(r->is_old(), "the region should be old"); assert(!r->in_collection_set(), "should not already be in the CSet"); @@ -412,7 +412,7 @@ void G1CollectionSet::move_pinned_marking_to_retained(G1CollectionCandidateRegio } candidates()->remove(regions); - for (HeapRegion* r : *regions) { + for (G1HeapRegion* r : *regions) { assert(r->has_pinned_objects(), "must be pinned"); assert(r->rem_set()->is_complete(), "must be complete"); candidates()->add_retained_region_unsorted(r); @@ -427,7 +427,7 @@ void G1CollectionSet::drop_pinned_retained_regions(G1CollectionCandidateRegionLi candidates()->remove(regions); // We can now drop these region's remembered sets. - for (HeapRegion* r : *regions) { + for (G1HeapRegion* r : *regions) { r->rem_set()->clear(true /* only_cardset */); } } @@ -457,7 +457,7 @@ bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_ti } void G1CollectionSet::abandon_optional_collection_set(G1ParScanThreadStateSet* pss) { - for (HeapRegion* r : _optional_old_regions) { + for (G1HeapRegion* r : _optional_old_regions) { pss->record_unused_optional_region(r); // Clear collection set marker and make sure that the remembered set information // is correct as we still need it later. @@ -486,7 +486,7 @@ class G1VerifyYoungCSetIndicesClosure : public HeapRegionClosure { FREE_C_HEAP_ARRAY(int, _heap_region_indices); } - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { const uint idx = r->young_index_in_cset(); assert(idx > 0, "Young index must be set for all regions in the incremental collection set but is not for region %u.", r->hrm_index()); diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.hpp b/src/hotspot/share/gc/g1/g1CollectionSet.hpp index fba166e9c75..e78a426e403 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.hpp @@ -35,7 +35,7 @@ class G1GCPhaseTimes; class G1ParScanThreadStateSet; class G1Policy; class G1SurvivorRegions; -class HeapRegion; +class G1HeapRegion; class HeapRegionClaimer; class HeapRegionClosure; @@ -168,10 +168,10 @@ class G1CollectionSet { void verify_young_cset_indices() const NOT_DEBUG_RETURN; // Update the incremental collection set information when adding a region. - void add_young_region_common(HeapRegion* hr); + void add_young_region_common(G1HeapRegion* hr); // Add the given old region to the head of the current collection set. - void add_old_region(HeapRegion* hr); + void add_old_region(G1HeapRegion* hr); void move_candidates_to_collection_set(G1CollectionCandidateRegionList* regions); // Prepares old regions in the given set for optional collection later. Does not @@ -271,10 +271,10 @@ class G1CollectionSet { void abandon_optional_collection_set(G1ParScanThreadStateSet* pss); // Add eden region to the collection set. - void add_eden_region(HeapRegion* hr); + void add_eden_region(G1HeapRegion* hr); // Add survivor region to the collection set. - void add_survivor_regions(HeapRegion* hr); + void add_survivor_regions(G1HeapRegion* hr); #ifndef PRODUCT bool verify_young_ages(); diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 36a194bdfb0..809f1ce9ce8 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -38,7 +38,7 @@ void G1CollectionCandidateList::set(G1CollectionSetCandidateInfo* candidate_info _candidates.appendAll(&a); } -void G1CollectionCandidateList::append_unsorted(HeapRegion* r) { +void G1CollectionCandidateList::append_unsorted(G1HeapRegion* r) { G1CollectionSetCandidateInfo c(r, r->calc_gc_efficiency()); _candidates.append(c); } @@ -135,7 +135,7 @@ int G1CollectionCandidateList::compare_reclaimble_bytes(G1CollectionSetCandidate G1CollectionCandidateRegionList::G1CollectionCandidateRegionList() : _regions(2, mtGC) { } -void G1CollectionCandidateRegionList::append(HeapRegion* r) { +void G1CollectionCandidateRegionList::append(G1HeapRegion* r) { assert(!_regions.contains(r), "must be"); _regions.append(r); } @@ -144,7 +144,7 @@ void G1CollectionCandidateRegionList::remove_prefix(G1CollectionCandidateRegionL #ifdef ASSERT // Check that the given list is a prefix of this list. int i = 0; - for (HeapRegion* r : *other) { + for (G1HeapRegion* r : *other) { assert(_regions.at(i) == r, "must be in order, but element %d is not", i); i++; } @@ -156,7 +156,7 @@ void G1CollectionCandidateRegionList::remove_prefix(G1CollectionCandidateRegionL _regions.remove_till(other->length()); } -HeapRegion* G1CollectionCandidateRegionList::at(uint index) { +G1HeapRegion* G1CollectionCandidateRegionList::at(uint index) { return _regions.at(index); } @@ -176,7 +176,7 @@ G1CollectionSetCandidates::~G1CollectionSetCandidates() { FREE_C_HEAP_ARRAY(CandidateOrigin, _contains_map); } -bool G1CollectionSetCandidates::is_from_marking(HeapRegion* r) const { +bool G1CollectionSetCandidates::is_from_marking(G1HeapRegion* r) const { assert(contains(r), "must be"); return _contains_map[r->hrm_index()] == CandidateOrigin::Marking; } @@ -200,7 +200,7 @@ void G1CollectionSetCandidates::clear() { void G1CollectionSetCandidates::sort_marking_by_efficiency() { G1CollectionCandidateListIterator iter = _marking_regions.begin(); for (; iter != _marking_regions.end(); ++iter) { - HeapRegion* hr = (*iter)->_r; + G1HeapRegion* hr = (*iter)->_r; (*iter)->_gc_efficiency = hr->calc_gc_efficiency(); } _marking_regions.sort_by_efficiency(); @@ -216,7 +216,7 @@ void G1CollectionSetCandidates::set_candidates_from_marking(G1CollectionSetCandi _marking_regions.set(candidate_infos, num_infos); for (uint i = 0; i < num_infos; i++) { - HeapRegion* r = candidate_infos[i]._r; + G1HeapRegion* r = candidate_infos[i]._r; assert(!contains(r), "must not contain region %u", r->hrm_index()); _contains_map[r->hrm_index()] = CandidateOrigin::Marking; } @@ -233,7 +233,7 @@ void G1CollectionSetCandidates::sort_by_efficiency() { _retained_regions.verify(); } -void G1CollectionSetCandidates::add_retained_region_unsorted(HeapRegion* r) { +void G1CollectionSetCandidates::add_retained_region_unsorted(G1HeapRegion* r) { assert(!contains(r), "must not contain region %u", r->hrm_index()); _contains_map[r->hrm_index()] = CandidateOrigin::Retained; _retained_regions.append_unsorted(r); @@ -249,7 +249,7 @@ void G1CollectionSetCandidates::remove(G1CollectionCandidateRegionList* other) { G1CollectionCandidateRegionList other_marking_regions; G1CollectionCandidateRegionList other_retained_regions; - for (HeapRegion* r : *other) { + for (G1HeapRegion* r : *other) { if (is_from_marking(r)) { other_marking_regions.append(r); } else { @@ -260,7 +260,7 @@ void G1CollectionSetCandidates::remove(G1CollectionCandidateRegionList* other) { _marking_regions.remove(&other_marking_regions); _retained_regions.remove(&other_retained_regions); - for (HeapRegion* r : *other) { + for (G1HeapRegion* r : *other) { assert(contains(r), "must contain region %u", r->hrm_index()); _contains_map[r->hrm_index()] = CandidateOrigin::Invalid; } @@ -289,7 +289,7 @@ void G1CollectionSetCandidates::verify_helper(G1CollectionCandidateList* list, u list->verify(); for (uint i = 0; i < (uint)list->length(); i++) { - HeapRegion* r = list->at(i)._r; + G1HeapRegion* r = list->at(i)._r; if (is_from_marking(r)) { from_marking++; @@ -334,13 +334,13 @@ void G1CollectionSetCandidates::verify() { } #endif -bool G1CollectionSetCandidates::contains(const HeapRegion* r) const { +bool G1CollectionSetCandidates::contains(const G1HeapRegion* r) const { const uint index = r->hrm_index(); assert(index < _max_regions, "must be"); return _contains_map[index] != CandidateOrigin::Invalid; } -const char* G1CollectionSetCandidates::get_short_type_str(const HeapRegion* r) const { +const char* G1CollectionSetCandidates::get_short_type_str(const G1HeapRegion* r) const { static const char* type_strings[] = { "Ci", // Invalid "Cm", // Marking diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp index 531559545d7..7d24f022461 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp @@ -35,29 +35,29 @@ class G1CollectionCandidateList; class G1CollectionSetCandidates; -class HeapRegion; +class G1HeapRegion; class HeapRegionClosure; -using G1CollectionCandidateRegionListIterator = GrowableArrayIterator; +using G1CollectionCandidateRegionListIterator = GrowableArrayIterator; -// A set of HeapRegion*, a thin wrapper around GrowableArray. +// A set of G1HeapRegion*, a thin wrapper around GrowableArray. class G1CollectionCandidateRegionList { - GrowableArray _regions; + GrowableArray _regions; public: G1CollectionCandidateRegionList(); - // Append a HeapRegion to the end of this list. The region must not be in the list + // Append a G1HeapRegion to the end of this list. The region must not be in the list // already. - void append(HeapRegion* r); - // Remove the given list of HeapRegion* from this list. The given list must be a prefix + void append(G1HeapRegion* r); + // Remove the given list of G1HeapRegion* from this list. The given list must be a prefix // of this list. void remove_prefix(G1CollectionCandidateRegionList* list); // Empty contents of the list. void clear(); - HeapRegion* at(uint index); + G1HeapRegion* at(uint index); uint length() const { return (uint)_regions.length(); } @@ -66,12 +66,12 @@ class G1CollectionCandidateRegionList { }; struct G1CollectionSetCandidateInfo { - HeapRegion* _r; + G1HeapRegion* _r; double _gc_efficiency; uint _num_unreclaimed; // Number of GCs this region has been found unreclaimable. G1CollectionSetCandidateInfo() : G1CollectionSetCandidateInfo(nullptr, 0.0) { } - G1CollectionSetCandidateInfo(HeapRegion* r, double gc_efficiency) : _r(r), _gc_efficiency(gc_efficiency), _num_unreclaimed(0) { } + G1CollectionSetCandidateInfo(G1HeapRegion* r, double gc_efficiency) : _r(r), _gc_efficiency(gc_efficiency), _num_unreclaimed(0) { } bool update_num_unreclaimed() { ++_num_unreclaimed; @@ -105,8 +105,8 @@ class G1CollectionCandidateList : public CHeapObj { // Put the given set of candidates into this list, preserving the efficiency ordering. void set(G1CollectionSetCandidateInfo* candidate_infos, uint num_infos); - // Add the given HeapRegion to this list at the end, (potentially) making the list unsorted. - void append_unsorted(HeapRegion* r); + // Add the given G1HeapRegion to this list at the end, (potentially) making the list unsorted. + void append_unsorted(G1HeapRegion* r); // Restore sorting order by decreasing gc efficiency, using the existing efficiency // values. void sort_by_efficiency(); @@ -151,7 +151,7 @@ class G1CollectionSetCandidatesIterator : public StackObj { G1CollectionSetCandidatesIterator(G1CollectionSetCandidates* which, uint position); G1CollectionSetCandidatesIterator& operator++(); - HeapRegion* operator*(); + G1HeapRegion* operator*(); bool operator==(const G1CollectionSetCandidatesIterator& rhs); bool operator!=(const G1CollectionSetCandidatesIterator& rhs); @@ -190,7 +190,7 @@ class G1CollectionSetCandidates : public CHeapObj { // The number of regions from the last merge of candidates from the marking. uint _last_marking_candidates_length; - bool is_from_marking(HeapRegion* r) const; + bool is_from_marking(G1HeapRegion* r) const; public: G1CollectionSetCandidates(); @@ -218,14 +218,14 @@ class G1CollectionSetCandidates : public CHeapObj { // Add the given region to the set of retained regions without regards to the // gc efficiency sorting. The retained regions must be re-sorted manually later. - void add_retained_region_unsorted(HeapRegion* r); + void add_retained_region_unsorted(G1HeapRegion* r); // Remove the given regions from the candidates. All given regions must be part // of the candidates. void remove(G1CollectionCandidateRegionList* other); - bool contains(const HeapRegion* r) const; + bool contains(const G1HeapRegion* r) const; - const char* get_short_type_str(const HeapRegion* r) const; + const char* get_short_type_str(const G1HeapRegion* r) const; bool is_empty() const; diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.inline.hpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.inline.hpp index 638a50b4745..9d602ace8c3 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.inline.hpp @@ -61,7 +61,7 @@ inline G1CollectionSetCandidatesIterator& G1CollectionSetCandidatesIterator::ope return *this; } -inline HeapRegion* G1CollectionSetCandidatesIterator::operator*() { +inline G1HeapRegion* G1CollectionSetCandidatesIterator::operator*() { uint length = _which->marking_regions_length(); if (_position < length) { return _which->_marking_regions.at(_position)._r; diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp index df3e72cb22f..a45e7de67bf 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.cpp @@ -91,7 +91,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { } // Set element in array. - void set(uint idx, HeapRegion* hr) { + void set(uint idx, G1HeapRegion* hr) { assert(idx < _max_size, "Index %u out of bounds %u", idx, _max_size); assert(_data[idx]._r == nullptr, "Value must not have been set."); _data[idx] = CandidateInfo(hr, 0.0); @@ -124,7 +124,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { uint _regions_added; - void add_region(HeapRegion* hr) { + void add_region(G1HeapRegion* hr) { if (_cur_chunk_idx == _cur_chunk_end) { _array->claim_chunk(_cur_chunk_idx, _cur_chunk_end); } @@ -143,7 +143,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { _cur_chunk_end(0), _regions_added(0) { } - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { // Candidates from marking are always old; also keep regions that are already // collection set candidates (some retained regions) in that list. if (!r->is_old() || r->is_collection_set_candidate()) { @@ -212,7 +212,7 @@ class G1BuildCandidateRegionsTask : public WorkerTask { uint max_to_prune = num_candidates - min_old_cset_length; while (true) { - HeapRegion* r = data[num_candidates - num_pruned - 1]._r; + G1HeapRegion* r = data[num_candidates - num_pruned - 1]._r; size_t const reclaimable = r->reclaimable_bytes(); if (num_pruned >= max_to_prune || wasted_bytes + reclaimable > allowed_waste) { diff --git a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp index 62f9b2a5cef..f49287f823b 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetChooser.hpp @@ -40,7 +40,7 @@ class G1CollectionSetChooser : public AllStatic { public: static size_t mixed_gc_live_threshold_bytes() { - return HeapRegion::GrainBytes * (size_t) G1MixedGCLiveThresholdPercent / 100; + return G1HeapRegion::GrainBytes * (size_t)G1MixedGCLiveThresholdPercent / 100; } static bool region_occupancy_low_enough_for_evac(size_t live_bytes) { diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index e3ab84e9555..827c538a2e5 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -580,7 +580,7 @@ void G1ConcurrentMark::reset() { _root_regions.reset(); } -void G1ConcurrentMark::clear_statistics(HeapRegion* r) { +void G1ConcurrentMark::clear_statistics(G1HeapRegion* r) { uint region_idx = r->hrm_index(); for (uint j = 0; j < _max_num_tasks; ++j) { _tasks[j]->clear_mark_stats_cache(region_idx); @@ -589,7 +589,7 @@ void G1ConcurrentMark::clear_statistics(HeapRegion* r) { _region_mark_stats[region_idx].clear(); } -void G1ConcurrentMark::humongous_object_eagerly_reclaimed(HeapRegion* r) { +void G1ConcurrentMark::humongous_object_eagerly_reclaimed(G1HeapRegion* r) { assert_at_safepoint(); assert(r->is_starts_humongous(), "Got humongous continues region here"); @@ -602,7 +602,7 @@ void G1ConcurrentMark::humongous_object_eagerly_reclaimed(HeapRegion* r) { // Clear any statistics about the region gathered so far. _g1h->humongous_obj_regions_iterate(r, - [&] (HeapRegion* r) { + [&] (G1HeapRegion* r) { clear_statistics(r); }); } @@ -697,7 +697,7 @@ class G1ClearBitMapTask : public WorkerTask { return false; } - HeapWord* region_clear_limit(HeapRegion* r) { + HeapWord* region_clear_limit(G1HeapRegion* r) { // During a Concurrent Undo Mark cycle, the per region top_at_mark_start and // live_words data are current wrt to the _mark_bitmap. We use this information // to only clear ranges of the bitmap that require clearing. @@ -721,7 +721,7 @@ class G1ClearBitMapTask : public WorkerTask { _suspendible(suspendible) { } - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { if (has_aborted()) { return true; } @@ -783,7 +783,7 @@ class G1ClearBitMapTask : public WorkerTask { void G1ConcurrentMark::clear_bitmap(WorkerThreads* workers, bool may_yield) { assert(may_yield || SafepointSynchronize::is_at_safepoint(), "Non-yielding bitmap clear only allowed at safepoint."); - size_t const num_bytes_to_clear = (HeapRegion::GrainBytes * _g1h->num_regions()) / G1CMBitMap::heap_map_factor(); + size_t const num_bytes_to_clear = (G1HeapRegion::GrainBytes * _g1h->num_regions()) / G1CMBitMap::heap_map_factor(); size_t const num_chunks = align_up(num_bytes_to_clear, G1ClearBitMapTask::chunk_size()) / G1ClearBitMapTask::chunk_size(); uint const num_workers = (uint)MIN2(num_chunks, (size_t)workers->active_workers()); @@ -869,7 +869,7 @@ class NoteStartOfMarkHRClosure : public HeapRegionClosure { public: NoteStartOfMarkHRClosure() : HeapRegionClosure(), _cm(G1CollectedHeap::heap()->concurrent_mark()) { } - bool do_heap_region(HeapRegion* r) override { + bool do_heap_region(G1HeapRegion* r) override { if (r->is_old_or_humongous() && !r->is_collection_set_candidate() && !r->in_collection_set()) { _cm->update_top_at_mark_start(r); } @@ -1035,7 +1035,7 @@ uint G1ConcurrentMark::calc_active_marking_workers() { void G1ConcurrentMark::scan_root_region(const MemRegion* region, uint worker_id) { #ifdef ASSERT HeapWord* last = region->last(); - HeapRegion* hr = _g1h->heap_region_containing(last); + G1HeapRegion* hr = _g1h->heap_region_containing(last); assert(hr->is_old() || top_at_mark_start(hr) == hr->bottom(), "Root regions must be old or survivor/eden but region %u is %s", hr->hrm_index(), hr->get_type_str()); assert(top_at_mark_start(hr) == region->start(), @@ -1099,11 +1099,11 @@ bool G1ConcurrentMark::wait_until_root_region_scan_finished() { return root_regions()->wait_until_scan_finished(); } -void G1ConcurrentMark::add_root_region(HeapRegion* r) { +void G1ConcurrentMark::add_root_region(G1HeapRegion* r) { root_regions()->add(top_at_mark_start(r), r->top()); } -bool G1ConcurrentMark::is_root_region(HeapRegion* r) { +bool G1ConcurrentMark::is_root_region(G1HeapRegion* r) { return root_regions()->contains(MemRegion(top_at_mark_start(r), r->top())); } @@ -1233,11 +1233,11 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { _num_humongous_regions_removed(0), _local_cleanup_list(local_cleanup_list) {} - void reclaim_empty_humongous_region(HeapRegion* hr) { + void reclaim_empty_humongous_region(G1HeapRegion* hr) { assert(!hr->has_pinned_objects(), "precondition"); assert(hr->is_starts_humongous(), "precondition"); - auto on_humongous_region = [&] (HeapRegion* hr) { + auto on_humongous_region = [&] (G1HeapRegion* hr) { assert(hr->used() > 0, "precondition"); assert(!hr->has_pinned_objects(), "precondition"); assert(hr->is_humongous(), "precondition"); @@ -1254,7 +1254,7 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { _g1h->humongous_obj_regions_iterate(hr, on_humongous_region); } - void reclaim_empty_old_region(HeapRegion* hr) { + void reclaim_empty_old_region(G1HeapRegion* hr) { assert(hr->used() > 0, "precondition"); assert(!hr->has_pinned_objects(), "precondition"); assert(hr->is_old(), "precondition"); @@ -1268,7 +1268,7 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { _g1h->free_region(hr, _local_cleanup_list); } - bool do_heap_region(HeapRegion* hr) override { + bool do_heap_region(G1HeapRegion* hr) override { G1RemSetTrackingPolicy* tracker = _g1h->policy()->remset_tracker(); if (hr->is_starts_humongous()) { // The liveness of this humongous obj decided by either its allocation @@ -1277,7 +1277,7 @@ class G1UpdateRegionLivenessAndSelectForRebuildTask : public WorkerTask { || _cm->contains_live_object(hr->hrm_index()); if (is_live) { const bool selected_for_rebuild = tracker->update_humongous_before_rebuild(hr); - auto on_humongous_region = [&] (HeapRegion* hr) { + auto on_humongous_region = [&] (G1HeapRegion* hr) { if (selected_for_rebuild) { _num_selected_for_rebuild++; } @@ -1360,7 +1360,7 @@ class G1UpdateRegionsAfterRebuild : public HeapRegionClosure { _g1h(g1h) { } - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { // Update the remset tracking state from updating to complete // if remembered sets have been rebuilt. _g1h->policy()->remset_tracker()->update_after_rebuild(r); @@ -1902,24 +1902,24 @@ void G1ConcurrentMark::flush_all_task_caches() { hits, misses, percent_of(hits, sum)); } -void G1ConcurrentMark::clear_bitmap_for_region(HeapRegion* hr) { +void G1ConcurrentMark::clear_bitmap_for_region(G1HeapRegion* hr) { assert_at_safepoint(); _mark_bitmap.clear_range(MemRegion(hr->bottom(), hr->end())); } -HeapRegion* G1ConcurrentMark::claim_region(uint worker_id) { +G1HeapRegion* G1ConcurrentMark::claim_region(uint worker_id) { // "checkpoint" the finger HeapWord* finger = _finger; while (finger < _heap.end()) { assert(_g1h->is_in_reserved(finger), "invariant"); - HeapRegion* curr_region = _g1h->heap_region_containing_or_null(finger); + G1HeapRegion* curr_region = _g1h->heap_region_containing_or_null(finger); // Make sure that the reads below do not float before loading curr_region. OrderAccess::loadload(); // Above heap_region_containing may return null as we always scan claim // until the end of the heap. In this case, just jump to the next region. - HeapWord* end = curr_region != nullptr ? curr_region->end() : finger + HeapRegion::GrainWords; + HeapWord* end = curr_region != nullptr ? curr_region->end() : finger + G1HeapRegion::GrainWords; // Is the gap between reading the finger and doing the CAS too long? HeapWord* res = Atomic::cmpxchg(&_finger, finger, end); @@ -1973,7 +1973,7 @@ class VerifyNoCSetOops { guarantee(oopDesc::is_oop(task_entry.obj()), "Non-oop " PTR_FORMAT ", phase: %s, info: %d", p2i(task_entry.obj()), _phase, _info); - HeapRegion* r = _g1h->heap_region_containing(task_entry.obj()); + G1HeapRegion* r = _g1h->heap_region_containing(task_entry.obj()); guarantee(!(r->in_collection_set() || r->has_index_in_opt_cset()), "obj " PTR_FORMAT " from %s (%d) in region %u in (optional) collection set", p2i(task_entry.obj()), _phase, _info, r->hrm_index()); @@ -1998,9 +1998,9 @@ void G1ConcurrentMark::verify_no_collection_set_oops() { // Verify the global finger HeapWord* global_finger = finger(); if (global_finger != nullptr && global_finger < _heap.end()) { - // Since we always iterate over all regions, we might get a null HeapRegion + // Since we always iterate over all regions, we might get a null G1HeapRegion // here. - HeapRegion* global_hr = _g1h->heap_region_containing_or_null(global_finger); + G1HeapRegion* global_hr = _g1h->heap_region_containing_or_null(global_finger); guarantee(global_hr == nullptr || global_finger == global_hr->bottom(), "global finger: " PTR_FORMAT " region: " HR_FORMAT, p2i(global_finger), HR_FORMAT_PARAMS(global_hr)); @@ -2013,7 +2013,7 @@ void G1ConcurrentMark::verify_no_collection_set_oops() { HeapWord* task_finger = task->finger(); if (task_finger != nullptr && task_finger < _heap.end()) { // See above note on the global finger verification. - HeapRegion* r = _g1h->heap_region_containing_or_null(task_finger); + G1HeapRegion* r = _g1h->heap_region_containing_or_null(task_finger); guarantee(r == nullptr || task_finger == r->bottom() || !r->in_collection_set() || !r->has_index_in_opt_cset(), "task finger: " PTR_FORMAT " region: " HR_FORMAT, @@ -2140,7 +2140,7 @@ G1CMOopClosure::G1CMOopClosure(G1CollectedHeap* g1h, _g1h(g1h), _task(task) { } -void G1CMTask::setup_for_region(HeapRegion* hr) { +void G1CMTask::setup_for_region(G1HeapRegion* hr) { assert(hr != nullptr, "claim_region() should have filtered out null regions"); _curr_region = hr; @@ -2149,7 +2149,7 @@ void G1CMTask::setup_for_region(HeapRegion* hr) { } void G1CMTask::update_region_limit() { - HeapRegion* hr = _curr_region; + G1HeapRegion* hr = _curr_region; HeapWord* bottom = hr->bottom(); HeapWord* limit = _cm->top_at_mark_start(hr); @@ -2741,7 +2741,7 @@ void G1CMTask::do_marking_step(double time_target_ms, assert(_curr_region == nullptr, "invariant"); assert(_finger == nullptr, "invariant"); assert(_region_limit == nullptr, "invariant"); - HeapRegion* claimed_region = _cm->claim_region(_worker_id); + G1HeapRegion* claimed_region = _cm->claim_region(_worker_id); if (claimed_region != nullptr) { // Yes, we managed to claim one setup_for_region(claimed_region); @@ -2996,7 +2996,7 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p G1PPRL_SUM_ADDR_FORMAT("reserved") G1PPRL_SUM_BYTE_FORMAT("region-size"), p2i(reserved.start()), p2i(reserved.end()), - HeapRegion::GrainBytes); + G1HeapRegion::GrainBytes); log_trace(gc, liveness)(G1PPRL_LINE_PREFIX); log_trace(gc, liveness)(G1PPRL_LINE_PREFIX G1PPRL_TYPE_H_FORMAT @@ -3024,7 +3024,7 @@ G1PrintRegionLivenessInfoClosure::G1PrintRegionLivenessInfoClosure(const char* p "(bytes)", "", "(bytes)"); } -bool G1PrintRegionLivenessInfoClosure::do_heap_region(HeapRegion* r) { +bool G1PrintRegionLivenessInfoClosure::do_heap_region(G1HeapRegion* r) { if (!log_is_enabled(Trace, gc, liveness)) { return false; } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index b2376025b16..f2206664b25 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -507,7 +507,7 @@ class G1ConcurrentMark : public CHeapObj { // method. So, this way, each task will spend very little time in // claim_region() and is allowed to call the regular clock method // frequently. - HeapRegion* claim_region(uint worker_id); + G1HeapRegion* claim_region(uint worker_id); // Determines whether we've run out of regions to scan. Note that // the finger can point past the heap end in case the heap was expanded @@ -564,25 +564,25 @@ class G1ConcurrentMark : public CHeapObj { void set_live_bytes(uint region, size_t live_bytes) { _region_mark_stats[region]._live_words = live_bytes / HeapWordSize; } // Update the TAMS for the given region to the current top. - inline void update_top_at_mark_start(HeapRegion* r); + inline void update_top_at_mark_start(G1HeapRegion* r); // Reset the TAMS for the given region to bottom of that region. - inline void reset_top_at_mark_start(HeapRegion* r); + inline void reset_top_at_mark_start(G1HeapRegion* r); - inline HeapWord* top_at_mark_start(const HeapRegion* r) const; + inline HeapWord* top_at_mark_start(const G1HeapRegion* r) const; inline HeapWord* top_at_mark_start(uint region) const; // Returns whether the given object been allocated since marking start (i.e. >= TAMS in that region). inline bool obj_allocated_since_mark_start(oop obj) const; // Sets the internal top_at_region_start for the given region to current top of the region. - inline void update_top_at_rebuild_start(HeapRegion* r); + inline void update_top_at_rebuild_start(G1HeapRegion* r); // TARS for the given region during remembered set rebuilding. - inline HeapWord* top_at_rebuild_start(HeapRegion* r) const; + inline HeapWord* top_at_rebuild_start(G1HeapRegion* r) const; // Clear statistics gathered during the concurrent cycle for the given region after // it has been reclaimed. - void clear_statistics(HeapRegion* r); + void clear_statistics(G1HeapRegion* r); // Notification for eagerly reclaimed regions to clean up. - void humongous_object_eagerly_reclaimed(HeapRegion* r); + void humongous_object_eagerly_reclaimed(G1HeapRegion* r); // Manipulation of the global mark stack. // The push and pop operations are used by tasks for transfers // between task-local queues and the global mark stack. @@ -659,8 +659,8 @@ class G1ConcurrentMark : public CHeapObj { // them. void scan_root_regions(); bool wait_until_root_region_scan_finished(); - void add_root_region(HeapRegion* r); - bool is_root_region(HeapRegion* r); + void add_root_region(G1HeapRegion* r); + bool is_root_region(G1HeapRegion* r); void root_region_scan_abort_and_wait(); private: @@ -688,7 +688,7 @@ class G1ConcurrentMark : public CHeapObj { // Clears marks for all objects in the given region in the marking // bitmap. This should only be used to clean the bitmap during a // safepoint. - void clear_bitmap_for_region(HeapRegion* hr); + void clear_bitmap_for_region(G1HeapRegion* hr); // Verify that there are no collection set oops on the stacks (taskqueues / // global mark stack) and fingers (global / per-task). @@ -758,7 +758,7 @@ class G1CMTask : public TerminatorTerminator { G1CMOopClosure* _cm_oop_closure; // Region this task is scanning, null if we're not scanning any - HeapRegion* _curr_region; + G1HeapRegion* _curr_region; // Local finger of this task, null if we're not scanning a region HeapWord* _finger; // Limit of the region this task is scanning, null if we're not scanning one @@ -806,7 +806,7 @@ class G1CMTask : public TerminatorTerminator { // Updates the local fields after this task has claimed // a new region to scan - void setup_for_region(HeapRegion* hr); + void setup_for_region(G1HeapRegion* hr); // Makes the limit of the region up-to-date void update_region_limit(); @@ -969,7 +969,7 @@ class G1PrintRegionLivenessInfoClosure : public HeapRegionClosure { // The header and footer are printed in the constructor and // destructor respectively. G1PrintRegionLivenessInfoClosure(const char* phase_name); - virtual bool do_heap_region(HeapRegion* r); + virtual bool do_heap_region(G1HeapRegion* r); ~G1PrintRegionLivenessInfoClosure(); }; #endif // SHARE_GC_G1_G1CONCURRENTMARK_HPP diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp index 4e1b4e63fe8..9f165cf1d22 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp @@ -71,7 +71,7 @@ inline bool G1ConcurrentMark::mark_in_bitmap(uint const worker_id, oop const obj // Some callers may have stale objects to mark above TAMS after humongous reclaim. // Can't assert that this is a valid object at this point, since it might be in the process of being copied by another thread. - DEBUG_ONLY(HeapRegion* const hr = _g1h->heap_region_containing(obj);) + DEBUG_ONLY(G1HeapRegion* const hr = _g1h->heap_region_containing(obj);) assert(!hr->is_continues_humongous(), "Should not try to mark object " PTR_FORMAT " in Humongous continues region %u above TAMS " PTR_FORMAT, p2i(obj), hr->hrm_index(), p2i(top_at_mark_start(hr))); @@ -184,17 +184,17 @@ inline size_t G1CMTask::scan_objArray(objArrayOop obj, MemRegion mr) { return mr.word_size(); } -inline void G1ConcurrentMark::update_top_at_mark_start(HeapRegion* r) { +inline void G1ConcurrentMark::update_top_at_mark_start(G1HeapRegion* r) { uint const region = r->hrm_index(); assert(region < _g1h->max_reserved_regions(), "Tried to access TAMS for region %u out of bounds", region); _top_at_mark_starts[region] = r->top(); } -inline void G1ConcurrentMark::reset_top_at_mark_start(HeapRegion* r) { +inline void G1ConcurrentMark::reset_top_at_mark_start(G1HeapRegion* r) { _top_at_mark_starts[r->hrm_index()] = r->bottom(); } -inline HeapWord* G1ConcurrentMark::top_at_mark_start(const HeapRegion* r) const { +inline HeapWord* G1ConcurrentMark::top_at_mark_start(const G1HeapRegion* r) const { return top_at_mark_start(r->hrm_index()); } @@ -209,11 +209,11 @@ inline bool G1ConcurrentMark::obj_allocated_since_mark_start(oop obj) const { return cast_from_oop(obj) >= top_at_mark_start(region); } -inline HeapWord* G1ConcurrentMark::top_at_rebuild_start(HeapRegion* r) const { +inline HeapWord* G1ConcurrentMark::top_at_rebuild_start(G1HeapRegion* r) const { return _top_at_rebuild_starts[r->hrm_index()]; } -inline void G1ConcurrentMark::update_top_at_rebuild_start(HeapRegion* r) { +inline void G1ConcurrentMark::update_top_at_rebuild_start(G1HeapRegion* r) { uint const region = r->hrm_index(); assert(region < _g1h->max_reserved_regions(), "Tried to access TARS for region %u out of bounds", region); assert(_top_at_rebuild_starts[region] == nullptr, diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.cpp index 438b58c2c02..b76ab6b867c 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.cpp @@ -42,6 +42,6 @@ void G1CMBitMapMappingChangedListener::on_commit(uint start_region, size_t num_r return; } // We need to clear the bitmap on commit, removing any existing information. - MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_region), num_regions * HeapRegion::GrainWords); + MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_region), num_regions * G1HeapRegion::GrainWords); _bm->clear_range(mr); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.hpp index 3df68aaf6c2..6a141a7919b 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.hpp @@ -36,7 +36,6 @@ class G1CMBitMap; class G1CMTask; class G1ConcurrentMark; -class HeapRegion; // Closure for iteration over bitmaps class G1CMBitMapClosure { diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp index 84823f8bf83..ebf06be94c8 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkObjArrayProcessor.cpp @@ -60,7 +60,7 @@ size_t G1CMObjArrayProcessor::process_slice(HeapWord* slice) { // slide is fast enough for "smaller" objects in non-humongous regions, but is slower // than directly using heap region table. G1CollectedHeap* g1h = G1CollectedHeap::heap(); - HeapRegion* r = g1h->heap_region_containing(slice); + G1HeapRegion* r = g1h->heap_region_containing(slice); HeapWord* const start_address = r->is_humongous() ? r->humongous_start_region()->bottom() : diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp index ba309c97ca5..cacb28f84b1 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRebuildAndScrub.cpp @@ -104,7 +104,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { // the value may be changed to null during rebuilding if the region has either: // - been allocated after rebuild start, or // - been reclaimed by a collection. - bool should_rebuild_or_scrub(HeapRegion* hr) const { + bool should_rebuild_or_scrub(G1HeapRegion* hr) const { return _cm->top_at_rebuild_start(hr) != nullptr; } @@ -112,7 +112,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { // G1RebuildRemSetChunkSize. The heap region is needed check whether the region has // been reclaimed during yielding. // Returns true if marking has been aborted or false if completed. - bool scan_large_object(HeapRegion* hr, const oop obj, MemRegion scan_range) { + bool scan_large_object(G1HeapRegion* hr, const oop obj, MemRegion scan_range) { HeapWord* start = scan_range.start(); HeapWord* limit = scan_range.end(); do { @@ -140,7 +140,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { // Scan for references into regions that need remembered set update for the given // live object. Returns the offset to the next object. - size_t scan_object(HeapRegion* hr, HeapWord* current) { + size_t scan_object(G1HeapRegion* hr, HeapWord* current) { oop obj = cast_to_oop(current); size_t obj_size = obj->size(); @@ -166,7 +166,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { } // Scrub a range of dead objects starting at scrub_start. Will never scrub past limit. - HeapWord* scrub_to_next_live(HeapRegion* hr, HeapWord* scrub_start, HeapWord* limit) { + HeapWord* scrub_to_next_live(G1HeapRegion* hr, HeapWord* scrub_start, HeapWord* limit) { assert(!_bitmap->is_marked(scrub_start), "Should not scrub live object"); HeapWord* scrub_end = _bitmap->get_next_marked_addr(scrub_start, limit); @@ -178,7 +178,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { // Scan the given region from bottom to parsable_bottom. Returns whether marking has // been aborted. - bool scan_and_scrub_to_pb(HeapRegion* hr, HeapWord* start, HeapWord* const limit) { + bool scan_and_scrub_to_pb(G1HeapRegion* hr, HeapWord* start, HeapWord* const limit) { while (start < limit) { if (_bitmap->is_marked(start)) { @@ -205,7 +205,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { // Scan the given region from parsable_bottom to tars. Returns whether marking has // been aborted. - bool scan_from_pb_to_tars(HeapRegion* hr, HeapWord* start, HeapWord* const limit) { + bool scan_from_pb_to_tars(G1HeapRegion* hr, HeapWord* start, HeapWord* const limit) { while (start < limit) { start += scan_object(hr, start); @@ -225,7 +225,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { // Scan and scrub the given region to tars. Returns whether marking has // been aborted. - bool scan_and_scrub_region(HeapRegion* hr, HeapWord* const pb) { + bool scan_and_scrub_region(G1HeapRegion* hr, HeapWord* const pb) { assert(should_rebuild_or_scrub(hr), "must be"); log_trace(gc, marking)("Scrub and rebuild region: " HR_FORMAT " pb: " PTR_FORMAT " TARS: " PTR_FORMAT " TAMS: " PTR_FORMAT, @@ -255,7 +255,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { // Scan a humongous region for remembered set updates. Scans in chunks to avoid // stalling safepoints. Returns whether the concurrent marking phase has been aborted. - bool scan_humongous_region(HeapRegion* hr, HeapWord* const pb) { + bool scan_humongous_region(G1HeapRegion* hr, HeapWord* const pb) { assert(should_rebuild_or_scrub(hr), "must be"); if (!_should_rebuild_remset) { @@ -294,7 +294,7 @@ class G1RebuildRSAndScrubTask : public WorkerTask { _should_rebuild_remset(should_rebuild_remset), _processed_words(0) { } - bool do_heap_region(HeapRegion* hr) { + bool do_heap_region(G1HeapRegion* hr) { // Avoid stalling safepoints and stop iteration if mark cycle has been aborted. _cm->do_yield_check(); if (_cm->has_aborted()) { diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp index 9ae9ad793c4..2fabeec9805 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefine.cpp @@ -262,7 +262,7 @@ class G1ConcurrentRefine::RemSetSamplingClosure : public HeapRegionClosure { explicit RemSetSamplingClosure(G1CollectionSet* cset) : _cset(cset), _sampled_card_rs_length(0), _sampled_code_root_rs_length(0) {} - bool do_heap_region(HeapRegion* r) override { + bool do_heap_region(G1HeapRegion* r) override { HeapRegionRemSet* rem_set = r->rem_set(); _sampled_card_rs_length += rem_set->occupied(); _sampled_code_root_rs_length += rem_set->code_roots_list_length(); @@ -317,7 +317,7 @@ bool G1ConcurrentRefine::adjust_threads_periodically() { size_t used_bytes = _policy->estimate_used_young_bytes_locked(); Heap_lock->unlock(); adjust_young_list_target_length(); - size_t young_bytes = _policy->young_list_target_length() * HeapRegion::GrainBytes; + size_t young_bytes = _policy->young_list_target_length() * G1HeapRegion::GrainBytes; size_t available_bytes = young_bytes - MIN2(young_bytes, used_bytes); adjust_threads_wanted(available_bytes); _needs_adjust = false; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineThreadsNeeded.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineThreadsNeeded.cpp index 33943eb5113..b2bb5c73ad5 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineThreadsNeeded.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineThreadsNeeded.cpp @@ -60,7 +60,7 @@ void G1ConcurrentRefineThreadsNeeded::update(uint active_threads, // Estimate time until next GC, based on remaining bytes available for // allocation and the allocation rate. double alloc_region_rate = analytics->predict_alloc_rate_ms(); - double alloc_bytes_rate = alloc_region_rate * HeapRegion::GrainBytes; + double alloc_bytes_rate = alloc_region_rate * G1HeapRegion::GrainBytes; if (alloc_bytes_rate == 0.0) { // A zero rate indicates we don't yet have data to use for predictions. // Since we don't have any idea how long until the next GC, use a time of diff --git a/src/hotspot/share/gc/g1/g1EdenRegions.hpp b/src/hotspot/share/gc/g1/g1EdenRegions.hpp index c76099c284a..ef37619c140 100644 --- a/src/hotspot/share/gc/g1/g1EdenRegions.hpp +++ b/src/hotspot/share/gc/g1/g1EdenRegions.hpp @@ -41,7 +41,7 @@ class G1EdenRegions { public: G1EdenRegions() : _length(0), _used_bytes(0), _regions_on_node() { } - uint add(HeapRegion* hr) { + uint add(G1HeapRegion* hr) { assert(!hr->is_eden(), "should not already be set"); _length++; return _regions_on_node.add(hr); diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp index 28be8562b52..0d4f5091d9e 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.inline.hpp @@ -60,7 +60,7 @@ bool G1EvacFailureRegions::record(uint worker_id, uint region_idx, bool cause_pi _evac_failed_regions[offset] = region_idx; G1CollectedHeap* g1h = G1CollectedHeap::heap(); - HeapRegion* hr = g1h->region_at(region_idx); + G1HeapRegion* hr = g1h->region_at(region_idx); hr->note_evacuation_failure(); } diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 81a54a9c31f..0fba8c1017f 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -149,7 +149,7 @@ G1FullCollector::G1FullCollector(G1CollectedHeap* heap, } _serial_compaction_point.set_preserved_stack(_preserved_marks_set.get(0)); _humongous_compaction_point.set_preserved_stack(_preserved_marks_set.get(0)); - _region_attr_table.initialize(heap->reserved(), HeapRegion::GrainBytes); + _region_attr_table.initialize(heap->reserved(), G1HeapRegion::GrainBytes); } G1FullCollector::~G1FullCollector() { @@ -170,7 +170,7 @@ class PrepareRegionsClosure : public HeapRegionClosure { public: PrepareRegionsClosure(G1FullCollector* collector) : _collector(collector) { } - bool do_heap_region(HeapRegion* hr) { + bool do_heap_region(G1HeapRegion* hr) { hr->prepare_for_full_gc(); G1CollectedHeap::heap()->prepare_region_for_full_compaction(hr); _collector->before_marking_update_attribute_table(hr); @@ -255,7 +255,7 @@ void G1FullCollector::complete_collection() { _heap->print_heap_after_full_collection(); } -void G1FullCollector::before_marking_update_attribute_table(HeapRegion* hr) { +void G1FullCollector::before_marking_update_attribute_table(G1HeapRegion* hr) { if (hr->is_free()) { _region_attr_table.set_free(hr->hrm_index()); } else if (hr->is_humongous() || hr->has_pinned_objects()) { @@ -419,7 +419,7 @@ void G1FullCollector::phase2c_prepare_serial_compaction() { G1FullGCCompactionPoint* serial_cp = serial_compaction_point(); assert(!serial_cp->is_initialized(), "sanity!"); - HeapRegion* start_hr = _heap->region_at(start_serial); + G1HeapRegion* start_hr = _heap->region_at(start_serial); serial_cp->add(start_hr); serial_cp->initialize(start_hr); @@ -428,7 +428,7 @@ void G1FullCollector::phase2c_prepare_serial_compaction() { for (uint i = start_serial + 1; i < _heap->max_reserved_regions(); i++) { if (is_compaction_target(i)) { - HeapRegion* current = _heap->region_at(i); + G1HeapRegion* current = _heap->region_at(i); set_compaction_top(current, current->bottom()); serial_cp->add(current); current->apply_to_marked_objects(mark_bitmap(), &re_prepare); @@ -449,7 +449,7 @@ void G1FullCollector::phase2d_prepare_humongous_compaction() { G1FullGCCompactionPoint* humongous_cp = humongous_compaction_point(); while (region_index < max_reserved_regions) { - HeapRegion* hr = _heap->region_at_or_null(region_index); + G1HeapRegion* hr = _heap->region_at_or_null(region_index); if (hr == nullptr) { region_index++; diff --git a/src/hotspot/share/gc/g1/g1FullCollector.hpp b/src/hotspot/share/gc/g1/g1FullCollector.hpp index b1ceb599fd2..11effe85993 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp @@ -45,7 +45,7 @@ class G1FullGCMarker; class G1FullGCScope; class G1FullGCCompactionPoint; class GCMemoryManager; -class HeapRegion; +class G1HeapRegion; class ReferenceProcessor; // Subject-to-discovery closure for reference processing during Full GC. During @@ -87,7 +87,7 @@ class G1FullCollector : StackObj { G1IsAliveClosure _is_alive; ReferenceProcessorIsAliveMutator _is_alive_mutator; G1RegionMarkStats* _live_stats; - GrowableArrayCHeap _humongous_compaction_regions; + GrowableArrayCHeap _humongous_compaction_regions; static uint calc_active_workers(); @@ -125,7 +125,7 @@ class G1FullCollector : StackObj { return _live_stats[region_index]._live_words; } - void before_marking_update_attribute_table(HeapRegion* hr); + void before_marking_update_attribute_table(G1HeapRegion* hr); inline bool is_compacting(oop obj) const; inline bool is_skip_compacting(uint region_index) const; @@ -138,14 +138,14 @@ class G1FullCollector : StackObj { inline void update_from_compacting_to_skip_compacting(uint region_idx); inline void update_from_skip_compacting_to_compacting(uint region_idx); - inline void set_compaction_top(HeapRegion* r, HeapWord* value); - inline HeapWord* compaction_top(HeapRegion* r) const; + inline void set_compaction_top(G1HeapRegion* r, HeapWord* value); + inline HeapWord* compaction_top(G1HeapRegion* r) const; inline void set_has_compaction_targets(); inline bool has_compaction_targets() const; - inline void add_humongous_region(HeapRegion* hr); - inline GrowableArrayCHeap& humongous_compaction_regions(); + inline void add_humongous_region(G1HeapRegion* hr); + inline GrowableArrayCHeap& humongous_compaction_regions(); uint truncate_parallel_cps(); diff --git a/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp b/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp index 7aa04449bcf..1a8d6257961 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp @@ -62,11 +62,11 @@ void G1FullCollector::update_from_skip_compacting_to_compacting(uint region_idx) _region_attr_table.set_compacting(region_idx); } -void G1FullCollector::set_compaction_top(HeapRegion* r, HeapWord* value) { +void G1FullCollector::set_compaction_top(G1HeapRegion* r, HeapWord* value) { Atomic::store(&_compaction_tops[r->hrm_index()], value); } -HeapWord* G1FullCollector::compaction_top(HeapRegion* r) const { +HeapWord* G1FullCollector::compaction_top(G1HeapRegion* r) const { return Atomic::load(&_compaction_tops[r->hrm_index()]); } @@ -90,11 +90,11 @@ bool G1FullCollector::has_humongous() { return _has_humongous; } -void G1FullCollector::add_humongous_region(HeapRegion* hr) { +void G1FullCollector::add_humongous_region(G1HeapRegion* hr) { _humongous_compaction_regions.append(hr); } -GrowableArrayCHeap& G1FullCollector::humongous_compaction_regions() { +GrowableArrayCHeap& G1FullCollector::humongous_compaction_regions() { return _humongous_compaction_regions; } diff --git a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp index 44e41c3cb89..75da25199eb 100644 --- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp @@ -61,7 +61,7 @@ class G1AdjustRegionClosure : public HeapRegionClosure { _bitmap(collector->mark_bitmap()), _worker_id(worker_id) { } - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { G1AdjustClosure cl(_collector); if (r->is_humongous()) { // Special handling for humongous regions to get somewhat better diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp index 5e3a9687f98..05f66959243 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp @@ -66,7 +66,7 @@ void G1FullGCCompactTask::copy_object_to_new_location(oop obj) { assert(cast_to_oop(destination)->klass() != nullptr, "should have a class"); } -void G1FullGCCompactTask::compact_region(HeapRegion* hr) { +void G1FullGCCompactTask::compact_region(G1HeapRegion* hr) { assert(!hr->has_pinned_objects(), "Should be no region with pinned objects in compaction queue"); assert(!hr->is_humongous(), "Should be no humongous regions in compaction queue"); @@ -87,8 +87,8 @@ void G1FullGCCompactTask::compact_region(HeapRegion* hr) { void G1FullGCCompactTask::work(uint worker_id) { Ticks start = Ticks::now(); - GrowableArray* compaction_queue = collector()->compaction_point(worker_id)->regions(); - for (GrowableArrayIterator it = compaction_queue->begin(); + GrowableArray* compaction_queue = collector()->compaction_point(worker_id)->regions(); + for (GrowableArrayIterator it = compaction_queue->begin(); it != compaction_queue->end(); ++it) { compact_region(*it); @@ -97,8 +97,8 @@ void G1FullGCCompactTask::work(uint worker_id) { void G1FullGCCompactTask::serial_compaction() { GCTraceTime(Debug, gc, phases) tm("Phase 4: Serial Compaction", collector()->scope()->timer()); - GrowableArray* compaction_queue = collector()->serial_compaction_point()->regions(); - for (GrowableArrayIterator it = compaction_queue->begin(); + GrowableArray* compaction_queue = collector()->serial_compaction_point()->regions(); + for (GrowableArrayIterator it = compaction_queue->begin(); it != compaction_queue->end(); ++it) { compact_region(*it); @@ -108,13 +108,13 @@ void G1FullGCCompactTask::serial_compaction() { void G1FullGCCompactTask::humongous_compaction() { GCTraceTime(Debug, gc, phases) tm("Phase 4: Humonguous Compaction", collector()->scope()->timer()); - for (HeapRegion* hr : collector()->humongous_compaction_regions()) { + for (G1HeapRegion* hr : collector()->humongous_compaction_regions()) { assert(collector()->is_compaction_target(hr->hrm_index()), "Sanity"); compact_humongous_obj(hr); } } -void G1FullGCCompactTask::compact_humongous_obj(HeapRegion* src_hr) { +void G1FullGCCompactTask::compact_humongous_obj(G1HeapRegion* src_hr) { assert(src_hr->is_starts_humongous(), "Should be start region of the humongous object"); oop obj = cast_to_oop(src_hr->bottom()); @@ -146,7 +146,7 @@ void G1FullGCCompactTask::free_non_overlapping_regions(uint src_start_idx, uint dest_end_idx + 1; for (uint i = non_overlapping_start; i <= src_end_idx; ++i) { - HeapRegion* hr = _g1h->region_at(i); + G1HeapRegion* hr = _g1h->region_at(i); _g1h->free_humongous_region(hr, nullptr); } } diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp b/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp index 7f7f144397b..341542f6d6f 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp @@ -40,8 +40,8 @@ class G1FullGCCompactTask : public G1FullGCTask { HeapRegionClaimer _claimer; G1CollectedHeap* _g1h; - void compact_region(HeapRegion* hr); - void compact_humongous_obj(HeapRegion* hr); + void compact_region(G1HeapRegion* hr); + void compact_humongous_obj(G1HeapRegion* hr); void free_non_overlapping_regions(uint src_start_idx, uint dest_start_idx, uint num_regions); static void copy_object_to_new_location(oop obj); diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp index 7b19aa431be..019484c810a 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp @@ -35,7 +35,7 @@ G1FullGCCompactionPoint::G1FullGCCompactionPoint(G1FullCollector* collector, Pre _current_region(nullptr), _compaction_top(nullptr), _preserved_stack(preserved_stack) { - _compaction_regions = new (mtGC) GrowableArray(32, mtGC); + _compaction_regions = new (mtGC) GrowableArray(32, mtGC); _compaction_region_iterator = _compaction_regions->begin(); } @@ -61,22 +61,22 @@ bool G1FullGCCompactionPoint::is_initialized() { return _current_region != nullptr; } -void G1FullGCCompactionPoint::initialize(HeapRegion* hr) { +void G1FullGCCompactionPoint::initialize(G1HeapRegion* hr) { _current_region = hr; initialize_values(); } -HeapRegion* G1FullGCCompactionPoint::current_region() { +G1HeapRegion* G1FullGCCompactionPoint::current_region() { return *_compaction_region_iterator; } -HeapRegion* G1FullGCCompactionPoint::next_region() { - HeapRegion* next = *(++_compaction_region_iterator); +G1HeapRegion* G1FullGCCompactionPoint::next_region() { + G1HeapRegion* next = *(++_compaction_region_iterator); assert(next != nullptr, "Must return valid region"); return next; } -GrowableArray* G1FullGCCompactionPoint::regions() { +GrowableArray* G1FullGCCompactionPoint::regions() { return _compaction_regions; } @@ -117,16 +117,16 @@ void G1FullGCCompactionPoint::forward(oop object, size_t size) { _current_region->update_bot_for_block(_compaction_top - size, _compaction_top); } -void G1FullGCCompactionPoint::add(HeapRegion* hr) { +void G1FullGCCompactionPoint::add(G1HeapRegion* hr) { _compaction_regions->append(hr); } void G1FullGCCompactionPoint::remove_at_or_above(uint bottom) { - HeapRegion* cur = current_region(); + G1HeapRegion* cur = current_region(); assert(cur->hrm_index() >= bottom, "Sanity!"); int start_index = 0; - for (HeapRegion* r : *_compaction_regions) { + for (G1HeapRegion* r : *_compaction_regions) { if (r->hrm_index() < bottom) { start_index++; } @@ -136,20 +136,20 @@ void G1FullGCCompactionPoint::remove_at_or_above(uint bottom) { _compaction_regions->trunc_to(start_index); } -void G1FullGCCompactionPoint::add_humongous(HeapRegion* hr) { +void G1FullGCCompactionPoint::add_humongous(G1HeapRegion* hr) { assert(hr->is_starts_humongous(), "Sanity!"); _collector->add_humongous_region(hr); G1CollectedHeap* g1h = G1CollectedHeap::heap(); g1h->humongous_obj_regions_iterate(hr, - [&] (HeapRegion* r) { + [&] (G1HeapRegion* r) { add(r); _collector->update_from_skip_compacting_to_compacting(r->hrm_index()); }); } -void G1FullGCCompactionPoint::forward_humongous(HeapRegion* hr) { +void G1FullGCCompactionPoint::forward_humongous(G1HeapRegion* hr) { assert(hr->is_starts_humongous(), "Sanity!"); oop obj = cast_to_oop(hr->bottom()); @@ -171,7 +171,7 @@ void G1FullGCCompactionPoint::forward_humongous(HeapRegion* hr) { // Preserve the mark for the humongous object as the region was initially not compacting. preserved_stack()->push_if_necessary(obj, obj->mark()); - HeapRegion* dest_hr = _compaction_regions->at(range_begin); + G1HeapRegion* dest_hr = _compaction_regions->at(range_begin); obj->forward_to(cast_to_oop(dest_hr->bottom())); assert(obj->is_forwarded(), "Object must be forwarded!"); @@ -184,7 +184,7 @@ void G1FullGCCompactionPoint::forward_humongous(HeapRegion* hr) { return; } -uint G1FullGCCompactionPoint::find_contiguous_before(HeapRegion* hr, uint num_regions) { +uint G1FullGCCompactionPoint::find_contiguous_before(G1HeapRegion* hr, uint num_regions) { assert(num_regions > 0, "Sanity!"); assert(has_regions(), "Sanity!"); diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.hpp b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.hpp index 6d87e44b213..43131f9092d 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.hpp @@ -31,22 +31,22 @@ #include "utilities/pair.hpp" class G1FullCollector; -class HeapRegion; +class G1HeapRegion; class PreservedMarks; class G1FullGCCompactionPoint : public CHeapObj { G1FullCollector* _collector; - HeapRegion* _current_region; - HeapWord* _compaction_top; + G1HeapRegion* _current_region; + HeapWord* _compaction_top; PreservedMarks* _preserved_stack; - GrowableArray* _compaction_regions; - GrowableArrayIterator _compaction_region_iterator; + GrowableArray* _compaction_regions; + GrowableArrayIterator _compaction_region_iterator; bool object_will_fit(size_t size); void initialize_values(); void switch_region(); - HeapRegion* next_region(); - uint find_contiguous_before(HeapRegion* hr, uint num_regions); + G1HeapRegion* next_region(); + uint find_contiguous_before(G1HeapRegion* hr, uint num_regions); public: G1FullGCCompactionPoint(G1FullCollector* collector, PreservedMarks* preserved_stack); @@ -54,17 +54,17 @@ class G1FullGCCompactionPoint : public CHeapObj { bool has_regions(); bool is_initialized(); - void initialize(HeapRegion* hr); + void initialize(G1HeapRegion* hr); void update(); void forward(oop object, size_t size); - void forward_humongous(HeapRegion* hr); - void add(HeapRegion* hr); - void add_humongous(HeapRegion* hr); + void forward_humongous(G1HeapRegion* hr); + void add(G1HeapRegion* hr); + void add_humongous(G1HeapRegion* hr); void remove_at_or_above(uint bottom); - HeapRegion* current_region(); + G1HeapRegion* current_region(); - GrowableArray* regions(); + GrowableArray* regions(); PreservedMarks* preserved_stack() const { assert(_preserved_stack != nullptr, "must be initialized"); diff --git a/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp index 6acac0b0fa5..2fc7d74f331 100644 --- a/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp @@ -34,7 +34,7 @@ // the table specifies whether a Full GC cycle should be compacting or skip // compacting a region. // Reasons for not compacting a region: -// (1) the HeapRegion itself can not be moved during this phase of the full gc +// (1) the G1HeapRegion itself can not be moved during this phase of the full gc // (e.g. Humongous regions). // (2) the occupancy of the region is too high to be considered eligible for compaction. class G1FullGCHeapRegionAttr : public G1BiasedMappedArray { diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp index e116367133d..88460a07f44 100644 --- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp @@ -43,7 +43,7 @@ G1DetermineCompactionQueueClosure::G1DetermineCompactionQueueClosure(G1FullColle _collector(collector), _cur_worker(0) { } -bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) { +bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(G1HeapRegion* hr) { uint region_idx = hr->hrm_index(); assert(_collector->is_compaction_target(region_idx), "must be"); @@ -78,7 +78,7 @@ void G1FullGCPrepareTask::work(uint worker_id) { G1FullGCCompactionPoint* compaction_point = collector()->compaction_point(worker_id); G1CalculatePointersClosure closure(collector(), compaction_point); - for (GrowableArrayIterator it = compaction_point->regions()->begin(); + for (GrowableArrayIterator it = compaction_point->regions()->begin(); it != compaction_point->regions()->end(); ++it) { closure.do_heap_region(*it); @@ -113,7 +113,7 @@ size_t G1FullGCPrepareTask::G1PrepareCompactLiveClosure::apply(oop object) { return size; } -void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction(HeapRegion* hr) { +void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction(G1HeapRegion* hr) { if (!_collector->is_free(hr->hrm_index())) { G1PrepareCompactLiveClosure prepare_compact(_cp); hr->apply_to_marked_objects(_bitmap, &prepare_compact); diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp index 9618986dcdd..a4dbbf2edba 100644 --- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp @@ -33,7 +33,7 @@ class G1CollectedHeap; class G1CMBitMap; class G1FullCollector; class G1FullGCCompactionPoint; -class HeapRegion; +class G1HeapRegion; // Determines the regions in the heap that should be part of the compaction and // distributes them among the compaction queues in round-robin fashion. @@ -42,9 +42,9 @@ class G1DetermineCompactionQueueClosure : public HeapRegionClosure { G1FullCollector* _collector; uint _cur_worker; - inline void free_empty_humongous_region(HeapRegion* hr); + inline void free_empty_humongous_region(G1HeapRegion* hr); - inline bool should_compact(HeapRegion* hr) const; + inline bool should_compact(G1HeapRegion* hr) const; // Returns the current worker id to assign a compaction point to, and selects // the next one round-robin style. @@ -52,12 +52,12 @@ class G1DetermineCompactionQueueClosure : public HeapRegionClosure { inline G1FullGCCompactionPoint* next_compaction_point(); - inline void add_to_compaction_queue(HeapRegion* hr); + inline void add_to_compaction_queue(G1HeapRegion* hr); public: G1DetermineCompactionQueueClosure(G1FullCollector* collector); - inline bool do_heap_region(HeapRegion* hr) override; + inline bool do_heap_region(G1HeapRegion* hr) override; }; class G1FullGCPrepareTask : public G1FullGCTask { @@ -80,13 +80,13 @@ class G1FullGCPrepareTask : public G1FullGCTask { G1CMBitMap* _bitmap; G1FullGCCompactionPoint* _cp; - void prepare_for_compaction(HeapRegion* hr); + void prepare_for_compaction(G1HeapRegion* hr); public: G1CalculatePointersClosure(G1FullCollector* collector, G1FullGCCompactionPoint* cp); - bool do_heap_region(HeapRegion* hr); + bool do_heap_region(G1HeapRegion* hr); }; class G1PrepareCompactLiveClosure : public StackObj { diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.inline.hpp index 5cff8e5f412..2fb61cc5934 100644 --- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.inline.hpp @@ -33,13 +33,13 @@ #include "gc/g1/g1FullGCScope.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" -void G1DetermineCompactionQueueClosure::free_empty_humongous_region(HeapRegion* hr) { +void G1DetermineCompactionQueueClosure::free_empty_humongous_region(G1HeapRegion* hr) { _g1h->free_humongous_region(hr, nullptr); _collector->set_free(hr->hrm_index()); add_to_compaction_queue(hr); } -inline bool G1DetermineCompactionQueueClosure::should_compact(HeapRegion* hr) const { +inline bool G1DetermineCompactionQueueClosure::should_compact(G1HeapRegion* hr) const { // There is no need to iterate and forward objects in non-movable regions ie. // prepare them for compaction. if (hr->is_humongous() || hr->has_pinned_objects()) { @@ -61,7 +61,7 @@ inline G1FullGCCompactionPoint* G1DetermineCompactionQueueClosure::next_compacti return _collector->compaction_point(next_worker()); } -inline void G1DetermineCompactionQueueClosure::add_to_compaction_queue(HeapRegion* hr) { +inline void G1DetermineCompactionQueueClosure::add_to_compaction_queue(G1HeapRegion* hr) { _collector->set_compaction_top(hr, hr->bottom()); _collector->set_has_compaction_targets(); @@ -73,12 +73,12 @@ inline void G1DetermineCompactionQueueClosure::add_to_compaction_queue(HeapRegio cp->add(hr); } -static bool has_pinned_objects(HeapRegion* hr) { +static bool has_pinned_objects(G1HeapRegion* hr) { return hr->has_pinned_objects() || (hr->is_humongous() && hr->humongous_start_region()->has_pinned_objects()); } -inline bool G1DetermineCompactionQueueClosure::do_heap_region(HeapRegion* hr) { +inline bool G1DetermineCompactionQueueClosure::do_heap_region(G1HeapRegion* hr) { if (should_compact(hr)) { assert(!hr->is_humongous(), "moving humongous objects not supported."); add_to_compaction_queue(hr); diff --git a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp index ddbaaa0b75e..4c93aca8492 100644 --- a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.cpp @@ -31,12 +31,12 @@ G1FullGCResetMetadataTask::G1ResetMetadataClosure::G1ResetMetadataClosure(G1Full _g1h(G1CollectedHeap::heap()), _collector(collector) { } -void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_region_metadata(HeapRegion* hr) { +void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_region_metadata(G1HeapRegion* hr) { hr->rem_set()->clear(); hr->clear_cardtable(); } -bool G1FullGCResetMetadataTask::G1ResetMetadataClosure::do_heap_region(HeapRegion* hr) { +bool G1FullGCResetMetadataTask::G1ResetMetadataClosure::do_heap_region(G1HeapRegion* hr) { uint const region_idx = hr->hrm_index(); if (!_collector->is_compaction_target(region_idx)) { assert(!hr->is_free(), "all free regions should be compaction targets"); @@ -54,7 +54,7 @@ bool G1FullGCResetMetadataTask::G1ResetMetadataClosure::do_heap_region(HeapRegio return false; } -void G1FullGCResetMetadataTask::G1ResetMetadataClosure::scrub_skip_compacting_region(HeapRegion* hr, bool update_bot_for_live) { +void G1FullGCResetMetadataTask::G1ResetMetadataClosure::scrub_skip_compacting_region(G1HeapRegion* hr, bool update_bot_for_live) { assert(hr->needs_scrubbing_during_full_gc(), "must be"); HeapWord* limit = hr->top(); @@ -82,7 +82,7 @@ void G1FullGCResetMetadataTask::G1ResetMetadataClosure::scrub_skip_compacting_re } } -void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_skip_compacting(HeapRegion* hr) { +void G1FullGCResetMetadataTask::G1ResetMetadataClosure::reset_skip_compacting(G1HeapRegion* hr) { #ifdef ASSERT uint region_index = hr->hrm_index(); assert(_collector->is_skip_compacting(region_index), "Only call on is_skip_compacting regions"); diff --git a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp index f424906d563..98d7af6e2f3 100644 --- a/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCResetMetadataTask.hpp @@ -35,18 +35,18 @@ class G1FullGCResetMetadataTask : public G1FullGCTask { G1CollectedHeap* _g1h; G1FullCollector* _collector; - void reset_region_metadata(HeapRegion* hr); + void reset_region_metadata(G1HeapRegion* hr); // Scrub all runs of dead objects within the given region by putting filler // objects and updating the corresponding BOT. If update_bot_for_live is true, // also update the BOT for live objects. - void scrub_skip_compacting_region(HeapRegion* hr, bool update_bot_for_live); + void scrub_skip_compacting_region(G1HeapRegion* hr, bool update_bot_for_live); - void reset_skip_compacting(HeapRegion* r); + void reset_skip_compacting(G1HeapRegion* r); public: G1ResetMetadataClosure(G1FullCollector* collector); - bool do_heap_region(HeapRegion* hr); + bool do_heap_region(G1HeapRegion* hr); }; public: diff --git a/src/hotspot/share/gc/g1/g1FullGCScope.cpp b/src/hotspot/share/gc/g1/g1FullGCScope.cpp index 5bbc5c4e2d4..e0e79e8b60b 100644 --- a/src/hotspot/share/gc/g1/g1FullGCScope.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCScope.cpp @@ -52,8 +52,8 @@ G1FullGCScope::G1FullGCScope(G1MonitoringSupport* monitoring_support, _monitoring_scope(monitoring_support), _heap_printer(_g1h), _region_compaction_threshold(do_maximal_compaction ? - HeapRegion::GrainWords : - (1 - MarkSweepDeadRatio / 100.0) * HeapRegion::GrainWords) { } + G1HeapRegion::GrainWords : + (1 - MarkSweepDeadRatio / 100.0) * G1HeapRegion::GrainWords) { } bool G1FullGCScope::should_clear_soft_refs() { return _soft_refs.should_clear(); diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index 291648393a9..895eba6500f 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -48,21 +48,21 @@ #include "runtime/globals_extension.hpp" #include "utilities/powerOfTwo.hpp" -uint HeapRegion::LogOfHRGrainBytes = 0; -uint HeapRegion::LogCardsPerRegion = 0; -size_t HeapRegion::GrainBytes = 0; -size_t HeapRegion::GrainWords = 0; -size_t HeapRegion::CardsPerRegion = 0; +uint G1HeapRegion::LogOfHRGrainBytes = 0; +uint G1HeapRegion::LogCardsPerRegion = 0; +size_t G1HeapRegion::GrainBytes = 0; +size_t G1HeapRegion::GrainWords = 0; +size_t G1HeapRegion::CardsPerRegion = 0; -size_t HeapRegion::max_region_size() { +size_t G1HeapRegion::max_region_size() { return HeapRegionBounds::max_size(); } -size_t HeapRegion::min_region_size_in_words() { +size_t G1HeapRegion::min_region_size_in_words() { return HeapRegionBounds::min_size() >> LogHeapWordSize; } -void HeapRegion::setup_heap_region_size(size_t max_heap_size) { +void G1HeapRegion::setup_heap_region_size(size_t max_heap_size) { size_t region_size = G1HeapRegionSize; // G1HeapRegionSize = 0 means decide ergonomically. if (region_size == 0) { @@ -98,7 +98,7 @@ void HeapRegion::setup_heap_region_size(size_t max_heap_size) { } } -void HeapRegion::handle_evacuation_failure(bool retain) { +void G1HeapRegion::handle_evacuation_failure(bool retain) { uninstall_surv_rate_group(); clear_young_index_in_cset(); clear_index_in_opt_cset(); @@ -108,13 +108,13 @@ void HeapRegion::handle_evacuation_failure(bool retain) { _rem_set->clear(true /* only_cardset */, retain /* keep_tracked */); } -void HeapRegion::unlink_from_list() { +void G1HeapRegion::unlink_from_list() { set_next(nullptr); set_prev(nullptr); set_containing_set(nullptr); } -void HeapRegion::hr_clear(bool clear_space) { +void G1HeapRegion::hr_clear(bool clear_space) { set_top(bottom()); clear_young_index_in_cset(); clear_index_in_opt_cset(); @@ -132,12 +132,12 @@ void HeapRegion::hr_clear(bool clear_space) { if (clear_space) clear(SpaceDecorator::Mangle); } -void HeapRegion::clear_cardtable() { +void G1HeapRegion::clear_cardtable() { G1CardTable* ct = G1CollectedHeap::heap()->card_table(); ct->clear_MemRegion(MemRegion(bottom(), end())); } -double HeapRegion::calc_gc_efficiency() { +double G1HeapRegion::calc_gc_efficiency() { // GC efficiency is the ratio of how much space would be // reclaimed over how long we predict it would take to reclaim it. G1Policy* policy = G1CollectedHeap::heap()->policy(); @@ -149,38 +149,38 @@ double HeapRegion::calc_gc_efficiency() { return (double)reclaimable_bytes() / region_elapsed_time_ms; } -void HeapRegion::set_free() { +void G1HeapRegion::set_free() { report_region_type_change(G1HeapRegionTraceType::Free); _type.set_free(); } -void HeapRegion::set_eden() { +void G1HeapRegion::set_eden() { report_region_type_change(G1HeapRegionTraceType::Eden); _type.set_eden(); } -void HeapRegion::set_eden_pre_gc() { +void G1HeapRegion::set_eden_pre_gc() { report_region_type_change(G1HeapRegionTraceType::Eden); _type.set_eden_pre_gc(); } -void HeapRegion::set_survivor() { +void G1HeapRegion::set_survivor() { report_region_type_change(G1HeapRegionTraceType::Survivor); _type.set_survivor(); } -void HeapRegion::move_to_old() { +void G1HeapRegion::move_to_old() { if (_type.relabel_as_old()) { report_region_type_change(G1HeapRegionTraceType::Old); } } -void HeapRegion::set_old() { +void G1HeapRegion::set_old() { report_region_type_change(G1HeapRegionTraceType::Old); _type.set_old(); } -void HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) { +void G1HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) { assert(!is_humongous(), "sanity / pre-condition"); assert(top() == bottom(), "should be empty"); @@ -194,7 +194,7 @@ void HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) { } } -void HeapRegion::set_continues_humongous(HeapRegion* first_hr) { +void G1HeapRegion::set_continues_humongous(G1HeapRegion* first_hr) { assert(!is_humongous(), "sanity / pre-condition"); assert(top() == bottom(), "should be empty"); assert(first_hr->is_starts_humongous(), "pre-condition"); @@ -204,18 +204,18 @@ void HeapRegion::set_continues_humongous(HeapRegion* first_hr) { _humongous_start_region = first_hr; } -void HeapRegion::clear_humongous() { +void G1HeapRegion::clear_humongous() { assert(is_humongous(), "pre-condition"); - assert(capacity() == HeapRegion::GrainBytes, "pre-condition"); + assert(capacity() == G1HeapRegion::GrainBytes, "pre-condition"); _humongous_start_region = nullptr; } -void HeapRegion::prepare_remset_for_scan() { +void G1HeapRegion::prepare_remset_for_scan() { _rem_set->reset_table_scanner(); } -HeapRegion::HeapRegion(uint hrm_index, +G1HeapRegion::G1HeapRegion(uint hrm_index, G1BlockOffsetTable* bot, MemRegion mr, G1CardSetConfiguration* config) : @@ -248,7 +248,7 @@ HeapRegion::HeapRegion(uint hrm_index, initialize(); } -void HeapRegion::initialize(bool clear_space, bool mangle_space) { +void G1HeapRegion::initialize(bool clear_space, bool mangle_space) { assert(_rem_set->is_empty(), "Remembered set must be empty"); if (clear_space) { @@ -260,7 +260,7 @@ void HeapRegion::initialize(bool clear_space, bool mangle_space) { hr_clear(false /*clear_space*/); } -void HeapRegion::report_region_type_change(G1HeapRegionTraceType::Type to) { +void G1HeapRegion::report_region_type_change(G1HeapRegionTraceType::Type to) { HeapRegionTracer::send_region_type_change(_hrm_index, get_trace_type(), to, @@ -268,7 +268,7 @@ void HeapRegion::report_region_type_change(G1HeapRegionTraceType::Type to) { used()); } - void HeapRegion::note_evacuation_failure() { + void G1HeapRegion::note_evacuation_failure() { // PB must be bottom - we only evacuate old gen regions after scrubbing, and // young gen regions never have their PB set to anything other than bottom. assert(parsable_bottom_acquire() == bottom(), "must be"); @@ -276,25 +276,25 @@ void HeapRegion::report_region_type_change(G1HeapRegionTraceType::Type to) { _garbage_bytes = 0; } -void HeapRegion::note_self_forward_chunk_done(size_t garbage_bytes) { +void G1HeapRegion::note_self_forward_chunk_done(size_t garbage_bytes) { Atomic::add(&_garbage_bytes, garbage_bytes, memory_order_relaxed); } // Code roots support -void HeapRegion::add_code_root(nmethod* nm) { +void G1HeapRegion::add_code_root(nmethod* nm) { rem_set()->add_code_root(nm); } -void HeapRegion::remove_code_root(nmethod* nm) { +void G1HeapRegion::remove_code_root(nmethod* nm) { rem_set()->remove_code_root(nm); } -void HeapRegion::code_roots_do(NMethodClosure* blk) const { +void G1HeapRegion::code_roots_do(NMethodClosure* blk) const { rem_set()->code_roots_do(blk); } class VerifyCodeRootOopClosure: public OopClosure { - const HeapRegion* _hr; + const G1HeapRegion* _hr; bool _failures; bool _has_oops_in_region; @@ -321,7 +321,7 @@ class VerifyCodeRootOopClosure: public OopClosure { } public: - VerifyCodeRootOopClosure(const HeapRegion* hr): + VerifyCodeRootOopClosure(const G1HeapRegion* hr): _hr(hr), _failures(false), _has_oops_in_region(false) {} void do_oop(narrowOop* p) { do_oop_work(p); } @@ -332,10 +332,10 @@ class VerifyCodeRootOopClosure: public OopClosure { }; class VerifyCodeRootNMethodClosure: public NMethodClosure { - const HeapRegion* _hr; + const G1HeapRegion* _hr; bool _failures; public: - VerifyCodeRootNMethodClosure(const HeapRegion* hr) : + VerifyCodeRootNMethodClosure(const G1HeapRegion* hr) : _hr(hr), _failures(false) {} void do_nmethod(nmethod* nm) { @@ -358,7 +358,7 @@ class VerifyCodeRootNMethodClosure: public NMethodClosure { bool failures() { return _failures; } }; -bool HeapRegion::verify_code_roots(VerifyOption vo) const { +bool G1HeapRegion::verify_code_roots(VerifyOption vo) const { if (!G1VerifyHeapRegionCodeRoots) { // We're not verifying code roots. return false; @@ -403,9 +403,9 @@ bool HeapRegion::verify_code_roots(VerifyOption vo) const { return nm_cl.failures(); } -void HeapRegion::print() const { print_on(tty); } +void G1HeapRegion::print() const { print_on(tty); } -void HeapRegion::print_on(outputStream* st) const { +void G1HeapRegion::print_on(outputStream* st) const { st->print("|%4u", this->_hrm_index); st->print("|" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT, p2i(bottom()), p2i(top()), p2i(end())); @@ -519,13 +519,13 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { return _failures->record_failure(); } - void print_containing_obj(outputStream* out, HeapRegion* from) { + void print_containing_obj(outputStream* out, G1HeapRegion* from) { log_error(gc, verify)("Field " PTR_FORMAT " of obj " PTR_FORMAT " in region " HR_FORMAT, p2i(_p), p2i(_containing_obj), HR_FORMAT_PARAMS(from)); print_object(out, _containing_obj); } - void print_referenced_obj(outputStream* out, HeapRegion* to, const char* explanation) { + void print_referenced_obj(outputStream* out, G1HeapRegion* to, const char* explanation) { log_error(gc, verify)("points to %sobj " PTR_FORMAT " in region " HR_FORMAT " remset %s", explanation, p2i(_obj), HR_FORMAT_PARAMS(to), to->rem_set()->get_state_str()); print_object(out, _obj); @@ -558,13 +558,13 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { log.error("----------"); } - HeapRegion* from = this->_g1h->heap_region_containing(this->_p); + G1HeapRegion* from = this->_g1h->heap_region_containing(this->_p); this->print_containing_obj(&ls, from); if (!_is_in_heap) { log.error("points to address " PTR_FORMAT " outside of heap", p2i(this->_obj)); } else { - HeapRegion* to = this->_g1h->heap_region_containing(this->_obj); + G1HeapRegion* to = this->_g1h->heap_region_containing(this->_obj); this->print_referenced_obj(&ls, to, "dead "); } log.error("----------"); @@ -575,8 +575,8 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { struct RemSetChecker : public Checker { using CardValue = CardTable::CardValue; - HeapRegion* _from; - HeapRegion* _to; + G1HeapRegion* _from; + G1HeapRegion* _to; CardValue _cv_obj; CardValue _cv_field; @@ -658,7 +658,7 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { virtual inline void do_oop(oop* p) { do_oop_work(p); } }; -bool HeapRegion::verify_liveness_and_remset(VerifyOption vo) const { +bool G1HeapRegion::verify_liveness_and_remset(VerifyOption vo) const { G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1VerifyFailureCounter failures; @@ -691,7 +691,7 @@ bool HeapRegion::verify_liveness_and_remset(VerifyOption vo) const { return failures.count() != 0; } -bool HeapRegion::verify(VerifyOption vo) const { +bool G1HeapRegion::verify(VerifyOption vo) const { // We cast p to an oop, so region-bottom must be an obj-start. assert(!is_humongous() || is_starts_humongous(), "invariant"); @@ -710,7 +710,7 @@ bool HeapRegion::verify(VerifyOption vo) const { return verify_code_roots(vo); } -void HeapRegion::clear(bool mangle_space) { +void G1HeapRegion::clear(bool mangle_space) { set_top(bottom()); if (ZapUnusedHeapArea && mangle_space) { @@ -719,12 +719,12 @@ void HeapRegion::clear(bool mangle_space) { } #ifndef PRODUCT -void HeapRegion::mangle_unused_area() { +void G1HeapRegion::mangle_unused_area() { SpaceMangler::mangle_region(MemRegion(top(), end())); } #endif -void HeapRegion::object_iterate(ObjectClosure* blk) { +void G1HeapRegion::object_iterate(ObjectClosure* blk) { HeapWord* p = bottom(); while (p < top()) { if (block_is_obj(p, parsable_bottom())) { @@ -734,7 +734,7 @@ void HeapRegion::object_iterate(ObjectClosure* blk) { } } -void HeapRegion::fill_with_dummy_object(HeapWord* address, size_t word_size, bool zap) { +void G1HeapRegion::fill_with_dummy_object(HeapWord* address, size_t word_size, bool zap) { // Keep the BOT in sync for old generation regions. if (is_old()) { update_bot_for_block(address, address + word_size); @@ -743,7 +743,7 @@ void HeapRegion::fill_with_dummy_object(HeapWord* address, size_t word_size, boo CollectedHeap::fill_with_object(address, word_size, zap); } -void HeapRegion::fill_range_with_dead_objects(HeapWord* start, HeapWord* end) { +void G1HeapRegion::fill_range_with_dead_objects(HeapWord* start, HeapWord* end) { size_t range_size = pointer_delta(end, start); // We must be a bit careful with regions that contain pinned objects. While the diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index d6be0837069..dc2c71bcbb4 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -41,7 +41,7 @@ class G1CollectedHeap; class G1CMBitMap; class G1Predictions; class HeapRegionRemSet; -class HeapRegion; +class G1HeapRegion; class HeapRegionSetBase; class nmethod; @@ -54,7 +54,7 @@ class nmethod; // sentinel value for hrm_index #define G1_NO_HRM_INDEX ((uint) -1) -// A HeapRegion is the smallest piece of a G1CollectedHeap that +// A G1HeapRegion is the smallest piece of a G1CollectedHeap that // can be collected independently. // Each heap region is self contained. top() and end() can never @@ -66,7 +66,7 @@ class nmethod; // the last will point to their own end. The last ContinuesHumongous // region may have top() equal the end of object if there isn't // room for filler objects to pad out to the end of the region. -class HeapRegion : public CHeapObj { +class G1HeapRegion : public CHeapObj { friend class VMStructs; HeapWord* const _bottom; @@ -130,10 +130,10 @@ class HeapRegion : public CHeapObj { // Try to allocate at least min_word_size and up to desired_size from this region. // Returns null if not possible, otherwise sets actual_word_size to the amount of // space allocated. - // This version assumes that all allocation requests to this HeapRegion are properly + // This version assumes that all allocation requests to this G1HeapRegion are properly // synchronized. inline HeapWord* allocate_impl(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size); - // Try to allocate at least min_word_size and up to desired_size from this HeapRegion. + // Try to allocate at least min_word_size and up to desired_size from this G1HeapRegion. // Returns null if not possible, otherwise sets actual_word_size to the amount of // space allocated. // This version synchronizes with other calls to par_allocate_impl(). @@ -177,12 +177,12 @@ class HeapRegion : public CHeapObj { // Update skip-compacting heap region to be consistent after Full GC. void reset_skip_compacting_after_full_gc(); - // All allocated blocks are occupied by objects in a HeapRegion. + // All allocated blocks are occupied by objects in a G1HeapRegion. bool block_is_obj(const HeapWord* p, HeapWord* pb) const; // Returns the object size for all valid block starts. If parsable_bottom (pb) // is given, calculates the block size based on that parsable_bottom, not the - // current value of this HeapRegion. + // current value of this G1HeapRegion. size_t block_size(const HeapWord* p) const; size_t block_size(const HeapWord* p, HeapWord* pb) const; @@ -205,7 +205,7 @@ class HeapRegion : public CHeapObj { HeapRegionType _type; // For a humongous region, region in which it starts. - HeapRegion* _humongous_start_region; + G1HeapRegion* _humongous_start_region; static const uint InvalidCSetIndex = UINT_MAX; @@ -214,8 +214,8 @@ class HeapRegion : public CHeapObj { uint _index_in_opt_cset; // Fields used by the HeapRegionSetBase class and subclasses. - HeapRegion* _next; - HeapRegion* _prev; + G1HeapRegion* _next; + G1HeapRegion* _prev; #ifdef ASSERT HeapRegionSetBase* _containing_set; #endif // ASSERT @@ -273,7 +273,7 @@ class HeapRegion : public CHeapObj { inline HeapWord* next_live_in_unparsable(const HeapWord* p, HeapWord* limit) const; public: - HeapRegion(uint hrm_index, + G1HeapRegion(uint hrm_index, G1BlockOffsetTable* bot, MemRegion mr, G1CardSetConfiguration* config); @@ -282,7 +282,7 @@ class HeapRegion : public CHeapObj { // sequence, otherwise -1. uint hrm_index() const { return _hrm_index; } - // Initializing the HeapRegion not only resets the data structure, but also + // Initializing the G1HeapRegion not only resets the data structure, but also // resets the BOT for that heap region. // The default values for clear_space means that we will do the clearing if // there's clearing to be done ourselves. We also always mangle the space. @@ -400,7 +400,7 @@ class HeapRegion : public CHeapObj { void set_old(); // For a humongous region, region in which it starts. - HeapRegion* humongous_start_region() const { + G1HeapRegion* humongous_start_region() const { return _humongous_start_region; } @@ -415,7 +415,7 @@ class HeapRegion : public CHeapObj { // Makes the current region be a "continues humongous' // region. first_hr is the "start humongous" region of the series // which this region will be part of. - void set_continues_humongous(HeapRegion* first_hr); + void set_continues_humongous(G1HeapRegion* first_hr); // Unsets the humongous-related fields on the region. void clear_humongous(); @@ -434,11 +434,11 @@ class HeapRegion : public CHeapObj { // Getter and setter for the next and prev fields used to link regions into // linked lists. - void set_next(HeapRegion* next) { _next = next; } - HeapRegion* next() { return _next; } + void set_next(G1HeapRegion* next) { _next = next; } + G1HeapRegion* next() { return _next; } - void set_prev(HeapRegion* prev) { _prev = prev; } - HeapRegion* prev() { return _prev; } + void set_prev(G1HeapRegion* prev) { _prev = prev; } + G1HeapRegion* prev() { return _prev; } void unlink_from_list(); @@ -466,8 +466,8 @@ class HeapRegion : public CHeapObj { #endif // ASSERT - // Reset the HeapRegion to default values and clear its remembered set. - // If clear_space is true, clear the HeapRegion's memory. + // Reset the G1HeapRegion to default values and clear its remembered set. + // If clear_space is true, clear the G1HeapRegion's memory. // Callers must ensure this is not called by multiple threads at the same time. void hr_clear(bool clear_space); // Clear the card table corresponding to this region. @@ -568,7 +568,7 @@ class HeapRegionClosure : public StackObj { HeapRegionClosure(): _is_complete(true) {} // Typically called on each region until it returns true. - virtual bool do_heap_region(HeapRegion* r) = 0; + virtual bool do_heap_region(G1HeapRegion* r) = 0; // True after iteration if the closure was applied to all heap regions // and returned "false" in all cases. diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index 401540804ba..8e5e594b5ca 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -42,7 +42,7 @@ #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" -inline HeapWord* HeapRegion::allocate_impl(size_t min_word_size, +inline HeapWord* G1HeapRegion::allocate_impl(size_t min_word_size, size_t desired_word_size, size_t* actual_size) { HeapWord* obj = top(); @@ -59,7 +59,7 @@ inline HeapWord* HeapRegion::allocate_impl(size_t min_word_size, } } -inline HeapWord* HeapRegion::par_allocate_impl(size_t min_word_size, +inline HeapWord* G1HeapRegion::par_allocate_impl(size_t min_word_size, size_t desired_word_size, size_t* actual_size) { do { @@ -83,11 +83,11 @@ inline HeapWord* HeapRegion::par_allocate_impl(size_t min_word_size, } while (true); } -inline HeapWord* HeapRegion::block_start(const void* addr) const { +inline HeapWord* G1HeapRegion::block_start(const void* addr) const { return block_start(addr, parsable_bottom_acquire()); } -inline HeapWord* HeapRegion::advance_to_block_containing_addr(const void* addr, +inline HeapWord* G1HeapRegion::advance_to_block_containing_addr(const void* addr, HeapWord* const pb, HeapWord* first_block) const { HeapWord* cur_block = first_block; @@ -104,25 +104,25 @@ inline HeapWord* HeapRegion::advance_to_block_containing_addr(const void* addr, } } -inline HeapWord* HeapRegion::block_start(const void* addr, HeapWord* const pb) const { +inline HeapWord* G1HeapRegion::block_start(const void* addr, HeapWord* const pb) const { assert(addr >= bottom() && addr < top(), "invalid address"); HeapWord* first_block = _bot->block_start_reaching_into_card(addr); return advance_to_block_containing_addr(addr, pb, first_block); } -inline bool HeapRegion::is_in_parsable_area(const void* const addr) const { +inline bool G1HeapRegion::is_in_parsable_area(const void* const addr) const { return is_in_parsable_area(addr, parsable_bottom()); } -inline bool HeapRegion::is_in_parsable_area(const void* const addr, const void* const pb) { +inline bool G1HeapRegion::is_in_parsable_area(const void* const addr, const void* const pb) { return addr >= pb; } -inline bool HeapRegion::is_marked_in_bitmap(oop obj) const { +inline bool G1HeapRegion::is_marked_in_bitmap(oop obj) const { return G1CollectedHeap::heap()->concurrent_mark()->mark_bitmap()->is_marked(obj); } -inline bool HeapRegion::block_is_obj(const HeapWord* const p, HeapWord* const pb) const { +inline bool G1HeapRegion::block_is_obj(const HeapWord* const p, HeapWord* const pb) const { assert(p >= bottom() && p < top(), "precondition"); assert(!is_continues_humongous(), "p must point to block-start"); @@ -141,24 +141,24 @@ inline bool HeapRegion::block_is_obj(const HeapWord* const p, HeapWord* const pb return is_marked_in_bitmap(cast_to_oop(p)); } -inline HeapWord* HeapRegion::next_live_in_unparsable(G1CMBitMap* const bitmap, const HeapWord* p, HeapWord* const limit) const { +inline HeapWord* G1HeapRegion::next_live_in_unparsable(G1CMBitMap* const bitmap, const HeapWord* p, HeapWord* const limit) const { return bitmap->get_next_marked_addr(p, limit); } -inline HeapWord* HeapRegion::next_live_in_unparsable(const HeapWord* p, HeapWord* const limit) const { +inline HeapWord* G1HeapRegion::next_live_in_unparsable(const HeapWord* p, HeapWord* const limit) const { G1CMBitMap* bitmap = G1CollectedHeap::heap()->concurrent_mark()->mark_bitmap(); return next_live_in_unparsable(bitmap, p, limit); } -inline bool HeapRegion::is_collection_set_candidate() const { +inline bool G1HeapRegion::is_collection_set_candidate() const { return G1CollectedHeap::heap()->is_collection_set_candidate(this); } -inline size_t HeapRegion::block_size(const HeapWord* p) const { +inline size_t G1HeapRegion::block_size(const HeapWord* p) const { return block_size(p, parsable_bottom()); } -inline size_t HeapRegion::block_size(const HeapWord* p, HeapWord* const pb) const { +inline size_t G1HeapRegion::block_size(const HeapWord* p, HeapWord* const pb) const { assert(p < top(), "precondition"); if (!block_is_obj(p, pb)) { @@ -168,26 +168,26 @@ inline size_t HeapRegion::block_size(const HeapWord* p, HeapWord* const pb) cons return cast_to_oop(p)->size(); } -inline void HeapRegion::prepare_for_full_gc() { +inline void G1HeapRegion::prepare_for_full_gc() { // After marking and class unloading the heap temporarily contains dead objects // with unloaded klasses. Moving parsable_bottom makes some (debug) code correctly // skip dead objects. _parsable_bottom = top(); } -inline void HeapRegion::reset_compacted_after_full_gc(HeapWord* new_top) { +inline void G1HeapRegion::reset_compacted_after_full_gc(HeapWord* new_top) { set_top(new_top); reset_after_full_gc_common(); } -inline void HeapRegion::reset_skip_compacting_after_full_gc() { +inline void G1HeapRegion::reset_skip_compacting_after_full_gc() { assert(!is_free(), "must be"); reset_after_full_gc_common(); } -inline void HeapRegion::reset_after_full_gc_common() { +inline void G1HeapRegion::reset_after_full_gc_common() { // After a full gc the mark information in a movable region is invalid. Reset marking // information. G1CollectedHeap::heap()->concurrent_mark()->reset_top_at_mark_start(this); @@ -204,7 +204,7 @@ inline void HeapRegion::reset_after_full_gc_common() { } template -inline void HeapRegion::apply_to_marked_objects(G1CMBitMap* bitmap, ApplyToMarkedClosure* closure) { +inline void G1HeapRegion::apply_to_marked_objects(G1CMBitMap* bitmap, ApplyToMarkedClosure* closure) { HeapWord* limit = top(); HeapWord* next_addr = bottom(); @@ -224,24 +224,24 @@ inline void HeapRegion::apply_to_marked_objects(G1CMBitMap* bitmap, ApplyToMarke assert(next_addr == limit, "Should stop the scan at the limit."); } -inline HeapWord* HeapRegion::par_allocate(size_t min_word_size, +inline HeapWord* G1HeapRegion::par_allocate(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { return par_allocate_impl(min_word_size, desired_word_size, actual_word_size); } -inline HeapWord* HeapRegion::allocate(size_t word_size) { +inline HeapWord* G1HeapRegion::allocate(size_t word_size) { size_t temp; return allocate(word_size, word_size, &temp); } -inline HeapWord* HeapRegion::allocate(size_t min_word_size, +inline HeapWord* G1HeapRegion::allocate(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { return allocate_impl(min_word_size, desired_word_size, actual_word_size); } -inline void HeapRegion::update_bot() { +inline void G1HeapRegion::update_bot() { HeapWord* next_addr = bottom(); HeapWord* prev_addr; @@ -253,7 +253,7 @@ inline void HeapRegion::update_bot() { assert(next_addr == top(), "Should stop the scan at the limit."); } -inline void HeapRegion::update_bot_for_block(HeapWord* start, HeapWord* end) { +inline void G1HeapRegion::update_bot_for_block(HeapWord* start, HeapWord* end) { assert(is_in(start), "The start address must be in this region: " HR_FORMAT " start " PTR_FORMAT " end " PTR_FORMAT, HR_FORMAT_PARAMS(this), @@ -262,20 +262,20 @@ inline void HeapRegion::update_bot_for_block(HeapWord* start, HeapWord* end) { _bot->update_for_block(start, end); } -inline HeapWord* HeapRegion::parsable_bottom() const { +inline HeapWord* G1HeapRegion::parsable_bottom() const { assert(!is_init_completed() || SafepointSynchronize::is_at_safepoint(), "only during initialization or safepoint"); return _parsable_bottom; } -inline HeapWord* HeapRegion::parsable_bottom_acquire() const { +inline HeapWord* G1HeapRegion::parsable_bottom_acquire() const { return Atomic::load_acquire(&_parsable_bottom); } -inline void HeapRegion::reset_parsable_bottom() { +inline void G1HeapRegion::reset_parsable_bottom() { Atomic::release_store(&_parsable_bottom, bottom()); } -inline void HeapRegion::note_end_of_marking(HeapWord* top_at_mark_start, size_t marked_bytes) { +inline void G1HeapRegion::note_end_of_marking(HeapWord* top_at_mark_start, size_t marked_bytes) { assert_at_safepoint(); if (top_at_mark_start != bottom()) { @@ -287,23 +287,23 @@ inline void HeapRegion::note_end_of_marking(HeapWord* top_at_mark_start, size_t } } -inline void HeapRegion::note_end_of_scrubbing() { +inline void G1HeapRegion::note_end_of_scrubbing() { reset_parsable_bottom(); } -inline bool HeapRegion::needs_scrubbing() const { +inline bool G1HeapRegion::needs_scrubbing() const { return is_old(); } -inline bool HeapRegion::in_collection_set() const { +inline bool G1HeapRegion::in_collection_set() const { return G1CollectedHeap::heap()->is_in_cset(this); } template -HeapWord* HeapRegion::do_oops_on_memregion_in_humongous(MemRegion mr, +HeapWord* G1HeapRegion::do_oops_on_memregion_in_humongous(MemRegion mr, Closure* cl) { assert(is_humongous(), "precondition"); - HeapRegion* sr = humongous_start_region(); + G1HeapRegion* sr = humongous_start_region(); oop obj = cast_to_oop(sr->bottom()); // If concurrent and klass_or_null is null, then space has been @@ -342,7 +342,7 @@ HeapWord* HeapRegion::do_oops_on_memregion_in_humongous(MemRegion mr, } template -inline HeapWord* HeapRegion::oops_on_memregion_iterate_in_unparsable(MemRegion mr, HeapWord* block_start, Closure* cl) { +inline HeapWord* G1HeapRegion::oops_on_memregion_iterate_in_unparsable(MemRegion mr, HeapWord* block_start, Closure* cl) { HeapWord* const start = mr.start(); HeapWord* const end = mr.end(); @@ -387,7 +387,7 @@ inline HeapWord* HeapRegion::oops_on_memregion_iterate_in_unparsable(MemRegion m // we expect that the amount of GCs executed during scrubbing is very low so such // tests would be unnecessary almost all the time. template -inline HeapWord* HeapRegion::oops_on_memregion_iterate(MemRegion mr, Closure* cl) { +inline HeapWord* G1HeapRegion::oops_on_memregion_iterate(MemRegion mr, Closure* cl) { // Cache the boundaries of the memory region in some const locals HeapWord* const start = mr.start(); HeapWord* const end = mr.end(); @@ -451,7 +451,7 @@ inline HeapWord* HeapRegion::oops_on_memregion_iterate(MemRegion mr, Closure* cl } template -HeapWord* HeapRegion::oops_on_memregion_seq_iterate_careful(MemRegion mr, +HeapWord* G1HeapRegion::oops_on_memregion_seq_iterate_careful(MemRegion mr, Closure* cl) { assert(MemRegion(bottom(), top()).contains(mr), "Card region not in heap region"); @@ -472,26 +472,26 @@ HeapWord* HeapRegion::oops_on_memregion_seq_iterate_careful(MemRegion mr, return oops_on_memregion_iterate(mr, cl); } -inline uint HeapRegion::age_in_surv_rate_group() const { +inline uint G1HeapRegion::age_in_surv_rate_group() const { assert(has_surv_rate_group(), "pre-condition"); assert(has_valid_age_in_surv_rate(), "pre-condition"); return _surv_rate_group->age_in_group(_age_index); } -inline bool HeapRegion::has_valid_age_in_surv_rate() const { +inline bool G1HeapRegion::has_valid_age_in_surv_rate() const { return _surv_rate_group->is_valid_age_index(_age_index); } -inline bool HeapRegion::has_surv_rate_group() const { +inline bool G1HeapRegion::has_surv_rate_group() const { return _surv_rate_group != nullptr; } -inline double HeapRegion::surv_rate_prediction(G1Predictions const& predictor) const { +inline double G1HeapRegion::surv_rate_prediction(G1Predictions const& predictor) const { assert(has_surv_rate_group(), "pre-condition"); return _surv_rate_group->surv_rate_pred(predictor, age_in_surv_rate_group()); } -inline void HeapRegion::install_surv_rate_group(G1SurvRateGroup* surv_rate_group) { +inline void G1HeapRegion::install_surv_rate_group(G1SurvRateGroup* surv_rate_group) { assert(surv_rate_group != nullptr, "pre-condition"); assert(!has_surv_rate_group(), "pre-condition"); assert(is_young(), "pre-condition"); @@ -500,7 +500,7 @@ inline void HeapRegion::install_surv_rate_group(G1SurvRateGroup* surv_rate_group _age_index = surv_rate_group->next_age_index(); } -inline void HeapRegion::uninstall_surv_rate_group() { +inline void G1HeapRegion::uninstall_surv_rate_group() { if (has_surv_rate_group()) { assert(has_valid_age_in_surv_rate(), "pre-condition"); assert(is_young(), "pre-condition"); @@ -512,12 +512,12 @@ inline void HeapRegion::uninstall_surv_rate_group() { } } -inline void HeapRegion::record_surv_words_in_group(size_t words_survived) { +inline void G1HeapRegion::record_surv_words_in_group(size_t words_survived) { uint age = age_in_surv_rate_group(); _surv_rate_group->record_surviving_words(age, words_survived); } -inline void HeapRegion::add_pinned_object_count(size_t value) { +inline void G1HeapRegion::add_pinned_object_count(size_t value) { assert(value != 0, "wasted effort"); assert(!is_free(), "trying to pin free region %u, adding %zu", hrm_index(), value); Atomic::add(&_pinned_object_count, value, memory_order_relaxed); diff --git a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp index c3c7b94e287..7ac688641cd 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionAttr.hpp @@ -121,7 +121,7 @@ struct G1HeapRegionAttr { // processing on it. // // This means that this does NOT completely correspond to the information stored -// in a HeapRegion, but only to what is interesting for the current young collection. +// in a G1HeapRegion, but only to what is interesting for the current young collection. class G1HeapRegionAttrBiasedMappedArray : public G1BiasedMappedArray { protected: G1HeapRegionAttr default_value() const { return G1HeapRegionAttr(G1HeapRegionAttr::NotInCSet); } @@ -180,10 +180,10 @@ class G1HeapRegionAttrBiasedMappedArray : public G1BiasedMappedArrayhrm_index()).is_in_cset(); } + bool is_in_cset(const G1HeapRegion* hr) const { return get_by_index(hr->hrm_index()).is_in_cset(); } G1HeapRegionAttr at(HeapWord* addr) const { return get_by_address(addr); } void clear() { G1BiasedMappedArray::clear(); } - void clear(const HeapRegion* hr) { return set_by_index(hr->hrm_index(), G1HeapRegionAttr(G1HeapRegionAttr::NotInCSet)); } + void clear(const G1HeapRegion* hr) { return set_by_index(hr->hrm_index(), G1HeapRegionAttr(G1HeapRegionAttr::NotInCSet)); } }; #endif // SHARE_GC_G1_G1HEAPREGIONATTR_HPP diff --git a/src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp b/src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp index 5dce9b2aa90..6f01524a14b 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionEventSender.cpp @@ -32,7 +32,7 @@ class DumpEventInfoClosure : public HeapRegionClosure { public: - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { EventG1HeapRegionInformation evt; evt.set_index(r->hrm_index()); evt.set_type(r->get_trace_type()); diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp index 81cba2329c8..2cf6a4088d3 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp @@ -58,7 +58,7 @@ class MasterFreeRegionListChecker : public HeapRegionSetChecker { guarantee(Heap_lock->owned_by_self(), "master free list MT safety protocol outside a safepoint"); } } - bool is_correct_type(HeapRegion* hr) { return hr->is_free(); } + bool is_correct_type(G1HeapRegion* hr) { return hr->is_free(); } const char* get_description() { return "Free Regions"; } }; @@ -85,13 +85,13 @@ void HeapRegionManager::initialize(G1RegionToSpaceMapper* heap_storage, _bot_mapper = bot; _cardtable_mapper = cardtable; - _regions.initialize(heap_storage->reserved(), HeapRegion::GrainBytes); + _regions.initialize(heap_storage->reserved(), G1HeapRegion::GrainBytes); _committed_map.initialize(reserved_length()); } -HeapRegion* HeapRegionManager::allocate_free_region(HeapRegionType type, uint requested_node_index) { - HeapRegion* hr = nullptr; +G1HeapRegion* HeapRegionManager::allocate_free_region(HeapRegionType type, uint requested_node_index) { + G1HeapRegion* hr = nullptr; bool from_head = !type.is_young(); G1NUMA* numa = G1NUMA::numa(); @@ -118,7 +118,7 @@ HeapRegion* HeapRegionManager::allocate_free_region(HeapRegionType type, uint re return hr; } -HeapRegion* HeapRegionManager::allocate_humongous_from_free_list(uint num_regions) { +G1HeapRegion* HeapRegionManager::allocate_humongous_from_free_list(uint num_regions) { uint candidate = find_contiguous_in_free_list(num_regions); if (candidate == G1_NO_HRM_INDEX) { return nullptr; @@ -126,7 +126,7 @@ HeapRegion* HeapRegionManager::allocate_humongous_from_free_list(uint num_region return allocate_free_regions_starting_at(candidate, num_regions); } -HeapRegion* HeapRegionManager::allocate_humongous_allow_expand(uint num_regions) { +G1HeapRegion* HeapRegionManager::allocate_humongous_allow_expand(uint num_regions) { uint candidate = find_contiguous_allow_expand(num_regions); if (candidate == G1_NO_HRM_INDEX) { return nullptr; @@ -135,7 +135,7 @@ HeapRegion* HeapRegionManager::allocate_humongous_allow_expand(uint num_regions) return allocate_free_regions_starting_at(candidate, num_regions); } -HeapRegion* HeapRegionManager::allocate_humongous(uint num_regions) { +G1HeapRegion* HeapRegionManager::allocate_humongous(uint num_regions) { // Special case a single region to avoid expensive search. if (num_regions == 1) { return allocate_free_region(HeapRegionType::Humongous, G1NUMA::AnyNodeIndex); @@ -143,20 +143,20 @@ HeapRegion* HeapRegionManager::allocate_humongous(uint num_regions) { return allocate_humongous_from_free_list(num_regions); } -HeapRegion* HeapRegionManager::expand_and_allocate_humongous(uint num_regions) { +G1HeapRegion* HeapRegionManager::expand_and_allocate_humongous(uint num_regions) { return allocate_humongous_allow_expand(num_regions); } #ifdef ASSERT -bool HeapRegionManager::is_free(HeapRegion* hr) const { +bool HeapRegionManager::is_free(G1HeapRegion* hr) const { return _free_list.contains(hr); } #endif -HeapRegion* HeapRegionManager::new_heap_region(uint hrm_index) { +G1HeapRegion* HeapRegionManager::new_heap_region(uint hrm_index) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); HeapWord* bottom = g1h->bottom_addr_for_region(hrm_index); - MemRegion mr(bottom, bottom + HeapRegion::GrainWords); + MemRegion mr(bottom, bottom + G1HeapRegion::GrainWords); assert(reserved().contains(mr), "invariant"); return g1h->new_heap_region(hrm_index, mr); } @@ -164,7 +164,7 @@ HeapRegion* HeapRegionManager::new_heap_region(uint hrm_index) { void HeapRegionManager::expand(uint start, uint num_regions, WorkerThreads* pretouch_workers) { commit_regions(start, num_regions, pretouch_workers); for (uint i = start; i < start + num_regions; i++) { - HeapRegion* hr = _regions.get_by_index(i); + G1HeapRegion* hr = _regions.get_by_index(i); if (hr == nullptr) { hr = new_heap_region(i); OrderAccess::storestore(); @@ -197,7 +197,7 @@ void HeapRegionManager::uncommit_regions(uint start, uint num_regions) { if (G1HeapRegionPrinter::is_active()) { for (uint i = start; i < end; i++) { // Can't use at() here since region is no longer marked available. - HeapRegion* hr = _regions.get_by_index(i); + G1HeapRegion* hr = _regions.get_by_index(i); assert(hr != nullptr, "Region should still be present"); G1HeapRegionPrinter::uncommit(hr); } @@ -218,7 +218,7 @@ void HeapRegionManager::uncommit_regions(uint start, uint num_regions) { void HeapRegionManager::initialize_regions(uint start, uint num_regions) { for (uint i = start; i < start + num_regions; i++) { assert(is_available(i), "Just made region %u available but is apparently not.", i); - HeapRegion* hr = at(i); + G1HeapRegion* hr = at(i); hr->initialize(); hr->set_node_index(G1NUMA::numa()->index_for_region(hr)); @@ -248,7 +248,7 @@ void HeapRegionManager::deactivate_regions(uint start, uint num_regions) { // Reset NUMA index to and print state change. uint end = start + num_regions; for (uint i = start; i < end; i++) { - HeapRegion* hr = at(i); + G1HeapRegion* hr = at(i); hr->set_node_index(G1NUMA::UnknownNodeIndex); G1HeapRegionPrinter::inactive(hr); } @@ -430,7 +430,7 @@ void HeapRegionManager::assert_contiguous_range(uint start, uint num_regions) { // General sanity check, regions found should either be available and empty // or not available so that we can make them available and use them. for (uint i = start; i < (start + num_regions); i++) { - HeapRegion* hr = _regions.get_by_index(i); + G1HeapRegion* hr = _regions.get_by_index(i); assert(!is_available(i) || hr->is_free(), "Found region sequence starting at " UINT32_FORMAT ", length " UINT32_FORMAT " that is not free at " UINT32_FORMAT ". Hr is " PTR_FORMAT ", type is %s", @@ -486,11 +486,11 @@ uint HeapRegionManager::find_contiguous_allow_expand(uint num_regions) { return find_contiguous_in_range(0, reserved_length(), num_regions); } -HeapRegion* HeapRegionManager::next_region_in_heap(const HeapRegion* r) const { +G1HeapRegion* HeapRegionManager::next_region_in_heap(const G1HeapRegion* r) const { guarantee(r != nullptr, "Start region must be a valid region"); guarantee(is_available(r->hrm_index()), "Trying to iterate starting from region %u which is not in the heap", r->hrm_index()); for (uint i = r->hrm_index() + 1; i < _allocated_heapregions_length; i++) { - HeapRegion* hr = _regions.get_by_index(i); + G1HeapRegion* hr = _regions.get_by_index(i); if (is_available(i)) { return hr; } @@ -505,7 +505,7 @@ void HeapRegionManager::iterate(HeapRegionClosure* blk) const { if (!is_available(i)) { continue; } - guarantee(at(i) != nullptr, "Tried to access region %u that has a null HeapRegion*", i); + guarantee(at(i) != nullptr, "Tried to access region %u that has a null G1HeapRegion*", i); bool res = blk->do_heap_region(at(i)); if (res) { blk->set_incomplete(); @@ -534,7 +534,7 @@ uint HeapRegionManager::find_highest_free(bool* expanded) { // entry which is either free or not yet committed. If not yet // committed, expand at that index. for (uint curr = reserved_length(); curr-- > 0;) { - HeapRegion *hr = _regions.get_by_index(curr); + G1HeapRegion* hr = _regions.get_by_index(curr); if (hr == nullptr || !is_available(curr)) { // Found uncommitted and free region, expand to make it available for use. expand_exact(curr, 1, nullptr); @@ -563,7 +563,7 @@ bool HeapRegionManager::allocate_containing_regions(MemRegion range, size_t* com commits++; expand_exact(curr_index, 1, pretouch_workers); } - HeapRegion* curr_region = _regions.get_by_index(curr_index); + G1HeapRegion* curr_region = _regions.get_by_index(curr_index); if (!curr_region->is_free()) { return false; } @@ -587,7 +587,7 @@ void HeapRegionManager::par_iterate(HeapRegionClosure* blk, HeapRegionClaimer* h if (!is_available(index)) { continue; } - HeapRegion* r = _regions.get_by_index(index); + G1HeapRegion* r = _regions.get_by_index(index); // We'll ignore regions already claimed. if (hrclaimer->is_region_claimed(index)) { continue; @@ -699,7 +699,7 @@ void HeapRegionManager::verify() { continue; } num_committed++; - HeapRegion* hr = _regions.get_by_index(i); + G1HeapRegion* hr = _regions.get_by_index(i); guarantee(hr != nullptr, "invariant: i: %u", i); guarantee(!prev_committed || hr->bottom() == prev_end, "invariant i: %u " HR_FORMAT " prev_end: " PTR_FORMAT, @@ -800,9 +800,9 @@ class G1RebuildFreeListTask : public WorkerTask { return; } - FreeRegionList *free_list = worker_freelist(worker_id); + FreeRegionList* free_list = worker_freelist(worker_id); for (uint i = start; i < end; i++) { - HeapRegion *region = _hrm->at_or_null(i); + G1HeapRegion* region = _hrm->at_or_null(i); if (region != nullptr && region->is_free()) { // Need to clear old links to allow to be added to new freelist. region->unlink_from_list(); diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp index 8ecb5d6d66f..3162cc39a99 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.hpp @@ -32,19 +32,19 @@ #include "memory/allocation.hpp" #include "services/memoryUsage.hpp" -class HeapRegion; +class G1HeapRegion; class HeapRegionClosure; class HeapRegionClaimer; class FreeRegionList; class WorkerThreads; -class G1HeapRegionTable : public G1BiasedMappedArray { +class G1HeapRegionTable : public G1BiasedMappedArray { protected: - virtual HeapRegion* default_value() const { return nullptr; } + virtual G1HeapRegion* default_value() const { return nullptr; } }; // This class keeps track of the actual heap memory, auxiliary data -// and its metadata (i.e., HeapRegion instances) and the list of free regions. +// and its metadata (i.e., G1HeapRegion instances) and the list of free regions. // // This allows maximum flexibility for deciding what to commit or uncommit given // a request from outside. @@ -55,9 +55,9 @@ class G1HeapRegionTable : public G1BiasedMappedArray { // regions that are consecutive in the array should also be adjacent in the // address space (i.e., region(i).end() == region(i+1).bottom(). // -// We create a HeapRegion when we commit the region's address space +// We create a G1HeapRegion when we commit the region's address space // for the first time. When we uncommit the address space of a -// region we retain the HeapRegion to be able to re-use it in the +// region we retain the G1HeapRegion to be able to re-use it in the // future (in case we recommit it). // // We keep track of four lengths: @@ -81,7 +81,7 @@ class HeapRegionManager: public CHeapObj { // can either be active (ready for use) or inactive (ready for uncommit). G1CommittedRegionMap _committed_map; - // Internal only. The highest heap region +1 we allocated a HeapRegion instance for. + // Internal only. The highest heap region +1 we allocated a G1HeapRegion instance for. uint _allocated_heapregions_length; HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); } @@ -137,12 +137,12 @@ class HeapRegionManager: public CHeapObj { void reactivate_regions(uint start, uint num_regions); void uncommit_regions(uint start, uint num_regions); - // Allocate a new HeapRegion for the given index. - HeapRegion* new_heap_region(uint hrm_index); + // Allocate a new G1HeapRegion for the given index. + G1HeapRegion* new_heap_region(uint hrm_index); // Humongous allocation helpers - HeapRegion* allocate_humongous_from_free_list(uint num_regions); - HeapRegion* allocate_humongous_allow_expand(uint num_regions); + G1HeapRegion* allocate_humongous_from_free_list(uint num_regions); + G1HeapRegion* allocate_humongous_allow_expand(uint num_regions); // Expand helper for cases when the regions to expand are well defined. void expand_exact(uint start, uint num_regions, WorkerThreads* pretouch_workers); @@ -153,7 +153,7 @@ class HeapRegionManager: public CHeapObj { #ifdef ASSERT public: - bool is_free(HeapRegion* hr) const; + bool is_free(G1HeapRegion* hr) const; #endif public: // Empty constructor, we'll initialize it with the initialize() method. @@ -165,32 +165,32 @@ class HeapRegionManager: public CHeapObj { G1RegionToSpaceMapper* cardtable); // Return the "dummy" region used for G1AllocRegion. This is currently a hardwired - // new HeapRegion that owns HeapRegion at index 0. Since at the moment we commit + // new G1HeapRegion that owns G1HeapRegion at index 0. Since at the moment we commit // the heap from the lowest address, this region (and its associated data // structures) are available and we do not need to check further. - HeapRegion* get_dummy_region() { return new_heap_region(0); } + G1HeapRegion* get_dummy_region() { return new_heap_region(0); } - // Return the HeapRegion at the given index. Assume that the index + // Return the G1HeapRegion at the given index. Assume that the index // is valid. - inline HeapRegion* at(uint index) const; + inline G1HeapRegion* at(uint index) const; - // Return the HeapRegion at the given index, null if the index + // Return the G1HeapRegion at the given index, null if the index // is for an unavailable region. - inline HeapRegion* at_or_null(uint index) const; + inline G1HeapRegion* at_or_null(uint index) const; // Returns whether the given region is available for allocation. inline bool is_available(uint region) const; // Return the next region (by index) that is part of the same // humongous object that hr is part of. - inline HeapRegion* next_region_in_humongous(HeapRegion* hr) const; + inline G1HeapRegion* next_region_in_humongous(G1HeapRegion* hr) const; // If addr is within the committed space return its corresponding - // HeapRegion, otherwise return null. - inline HeapRegion* addr_to_region(HeapWord* addr) const; + // G1HeapRegion, otherwise return null. + inline G1HeapRegion* addr_to_region(HeapWord* addr) const; // Insert the given region into the free region list. - inline void insert_into_free_list(HeapRegion* hr); + inline void insert_into_free_list(G1HeapRegion* hr); // Rebuild the free region list from scratch. void rebuild_free_list(WorkerThreads* workers); @@ -201,15 +201,15 @@ class HeapRegionManager: public CHeapObj { } // Allocate a free region with specific node index. If fails allocate with next node index. - HeapRegion* allocate_free_region(HeapRegionType type, uint requested_node_index); + G1HeapRegion* allocate_free_region(HeapRegionType type, uint requested_node_index); // Allocate a humongous object from the free list - HeapRegion* allocate_humongous(uint num_regions); + G1HeapRegion* allocate_humongous(uint num_regions); // Allocate a humongous object by expanding the heap - HeapRegion* expand_and_allocate_humongous(uint num_regions); + G1HeapRegion* expand_and_allocate_humongous(uint num_regions); - inline HeapRegion* allocate_free_regions_starting_at(uint first, uint num_regions); + inline G1HeapRegion* allocate_free_regions_starting_at(uint first, uint num_regions); // Remove all regions from the free list. void remove_all_free_regions() { @@ -226,7 +226,7 @@ class HeapRegionManager: public CHeapObj { } size_t total_free_bytes() const { - return num_free_regions() * HeapRegion::GrainBytes; + return num_free_regions() * G1HeapRegion::GrainBytes; } // Return the number of regions available (uncommitted) regions. @@ -247,14 +247,14 @@ class HeapRegionManager: public CHeapObj { // Expand the sequence to reflect that the heap has grown. Either create new // HeapRegions, or re-use existing ones. Returns the number of regions the - // sequence was expanded by. If a HeapRegion allocation fails, the resulting + // sequence was expanded by. If a G1HeapRegion allocation fails, the resulting // number of regions might be smaller than what's desired. uint expand_by(uint num_regions, WorkerThreads* pretouch_workers); // Try to expand on the given node index, returning the index of the new region. uint expand_on_preferred_node(uint node_index); - HeapRegion* next_region_in_heap(const HeapRegion* r) const; + G1HeapRegion* next_region_in_heap(const G1HeapRegion* r) const; // Find the highest free or uncommitted region in the reserved heap, // and if uncommitted, commit it. If none are available, return G1_NO_HRM_INDEX. diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp index 9768ee358ba..0a74a22c52e 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.inline.hpp @@ -35,7 +35,7 @@ inline bool HeapRegionManager::is_available(uint region) const { return _committed_map.active(region); } -inline HeapRegion* HeapRegionManager::addr_to_region(HeapWord* addr) const { +inline G1HeapRegion* HeapRegionManager::addr_to_region(HeapWord* addr) const { assert(addr < heap_end(), "addr: " PTR_FORMAT " end: " PTR_FORMAT, p2i(addr), p2i(heap_end())); assert(addr >= heap_bottom(), @@ -43,25 +43,25 @@ inline HeapRegion* HeapRegionManager::addr_to_region(HeapWord* addr) const { return _regions.get_by_address(addr); } -inline HeapRegion* HeapRegionManager::at(uint index) const { +inline G1HeapRegion* HeapRegionManager::at(uint index) const { assert(is_available(index), "pre-condition"); - HeapRegion* hr = _regions.get_by_index(index); + G1HeapRegion* hr = _regions.get_by_index(index); assert(hr != nullptr, "sanity"); assert(hr->hrm_index() == index, "sanity"); return hr; } -inline HeapRegion* HeapRegionManager::at_or_null(uint index) const { +inline G1HeapRegion* HeapRegionManager::at_or_null(uint index) const { if (!is_available(index)) { return nullptr; } - HeapRegion* hr = _regions.get_by_index(index); - assert(hr != nullptr, "All available regions must have a HeapRegion but index %u has not.", index); + G1HeapRegion* hr = _regions.get_by_index(index); + assert(hr != nullptr, "All available regions must have a G1HeapRegion but index %u has not.", index); assert(hr->hrm_index() == index, "sanity"); return hr; } -inline HeapRegion* HeapRegionManager::next_region_in_humongous(HeapRegion* hr) const { +inline G1HeapRegion* HeapRegionManager::next_region_in_humongous(G1HeapRegion* hr) const { uint index = hr->hrm_index(); assert(is_available(index), "pre-condition"); assert(hr->is_humongous(), "next_region_in_humongous should only be called for a humongous region."); @@ -73,12 +73,12 @@ inline HeapRegion* HeapRegionManager::next_region_in_humongous(HeapRegion* hr) c } } -inline void HeapRegionManager::insert_into_free_list(HeapRegion* hr) { +inline void HeapRegionManager::insert_into_free_list(G1HeapRegion* hr) { _free_list.add_ordered(hr); } -inline HeapRegion* HeapRegionManager::allocate_free_regions_starting_at(uint first, uint num_regions) { - HeapRegion* start = at(first); +inline G1HeapRegion* HeapRegionManager::allocate_free_regions_starting_at(uint first, uint num_regions) { + G1HeapRegion* start = at(first); _free_list.remove_starting_at(start, num_regions); return start; } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp index ed6d171fb6f..bd686f3809d 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionPrinter.hpp @@ -34,7 +34,7 @@ class FreeRegionList; class G1HeapRegionPrinter : public AllStatic { // Print an action event. - static void print(const char* action, HeapRegion* hr) { + static void print(const char* action, G1HeapRegion* hr) { log_trace(gc, region)("G1HR %s(%s) [" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT "]", action, hr->get_type_str(), p2i(hr->bottom()), p2i(hr->top()), p2i(hr->end())); } @@ -47,31 +47,31 @@ class G1HeapRegionPrinter : public AllStatic { // The methods below are convenient wrappers for the print() method. - static void alloc(HeapRegion* hr) { print("ALLOC", hr); } + static void alloc(G1HeapRegion* hr) { print("ALLOC", hr); } - static void retire(HeapRegion* hr) { print("RETIRE", hr); } + static void retire(G1HeapRegion* hr) { print("RETIRE", hr); } - static void reuse(HeapRegion* hr) { print("REUSE", hr); } + static void reuse(G1HeapRegion* hr) { print("REUSE", hr); } - static void cset(HeapRegion* hr) { print("CSET", hr); } + static void cset(G1HeapRegion* hr) { print("CSET", hr); } - static void evac_failure(HeapRegion* hr) { print("EVAC-FAILURE", hr); } + static void evac_failure(G1HeapRegion* hr) { print("EVAC-FAILURE", hr); } - static void mark_reclaim(HeapRegion* hr) { print("MARK-RECLAIM", hr); } + static void mark_reclaim(G1HeapRegion* hr) { print("MARK-RECLAIM", hr); } - static void eager_reclaim(HeapRegion* hr) { print("EAGER-RECLAIM", hr); } + static void eager_reclaim(G1HeapRegion* hr) { print("EAGER-RECLAIM", hr); } - static void evac_reclaim(HeapRegion* hr) { print("EVAC-RECLAIM", hr); } + static void evac_reclaim(G1HeapRegion* hr) { print("EVAC-RECLAIM", hr); } - static void post_compaction(HeapRegion* hr) { print("POST-COMPACTION", hr); } + static void post_compaction(G1HeapRegion* hr) { print("POST-COMPACTION", hr); } - static void commit(HeapRegion* hr) { print("COMMIT", hr); } + static void commit(G1HeapRegion* hr) { print("COMMIT", hr); } - static void active(HeapRegion* hr) { print("ACTIVE", hr); } + static void active(G1HeapRegion* hr) { print("ACTIVE", hr); } - static void inactive(HeapRegion* hr) { print("INACTIVE", hr); } + static void inactive(G1HeapRegion* hr) { print("INACTIVE", hr); } - static void uncommit(HeapRegion* hr) { print("UNCOMMIT", hr); } + static void uncommit(G1HeapRegion* hr) { print("UNCOMMIT", hr); } }; #endif // SHARE_GC_G1_G1HEAPREGIONPRINTER_HPP diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index 17134f0da24..2610fbde298 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -55,7 +55,7 @@ void HeapRegionRemSet::initialize(MemRegion reserved) { _heap_base_address = reserved.start(); } -HeapRegionRemSet::HeapRegionRemSet(HeapRegion* hr, +HeapRegionRemSet::HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config) : _code_roots(), _card_set_mm(config, G1CollectedHeap::heap()->card_set_freelist_pool()), @@ -123,7 +123,7 @@ void HeapRegionRemSet::code_roots_do(NMethodClosure* blk) const { _code_roots.nmethods_do(blk); } -void HeapRegionRemSet::clean_code_roots(HeapRegion* hr) { +void HeapRegionRemSet::clean_code_roots(G1HeapRegion* hr) { _code_roots.clean(hr); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index fa7aee562c6..fb0a64ac0d1 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -49,7 +49,7 @@ class HeapRegionRemSet : public CHeapObj { // The set of cards in the Java heap G1CardSet _card_set; - HeapRegion* _hr; + G1HeapRegion* _hr; // Cached value of heap base address. static HeapWord* _heap_base_address; @@ -57,7 +57,7 @@ class HeapRegionRemSet : public CHeapObj { void clear_fcc(); public: - HeapRegionRemSet(HeapRegion* hr, G1CardSetConfiguration* config); + HeapRegionRemSet(G1HeapRegion* hr, G1CardSetConfiguration* config); bool cardset_is_empty() const { return _card_set.is_empty(); @@ -155,7 +155,7 @@ class HeapRegionRemSet : public CHeapObj { // Applies blk->do_nmethod() to each of the entries in _code_roots void code_roots_do(NMethodClosure* blk) const; // Clean out code roots not having an oop pointing into this region any more. - void clean_code_roots(HeapRegion* hr); + void clean_code_roots(G1HeapRegion* hr); // Returns the number of elements in _code_roots size_t code_roots_list_length() const { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp index 832770ddb4c..eaf475aff34 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp @@ -31,7 +31,7 @@ uint FreeRegionList::_unrealistically_long_length = 0; #ifndef PRODUCT -void HeapRegionSetBase::verify_region(HeapRegion* hr) { +void HeapRegionSetBase::verify_region(G1HeapRegion* hr) { assert(hr->containing_set() == this, "Inconsistent containing set for %u", hr->hrm_index()); assert(!hr->is_young(), "Adding young region %u", hr->hrm_index()); // currently we don't use these sets for young regions assert(_checker == nullptr || _checker->is_correct_type(hr), "Wrong type of region %u (%s) and set %s", @@ -99,11 +99,11 @@ void FreeRegionList::remove_all() { check_mt_safety(); verify_optional(); - HeapRegion* curr = _head; + G1HeapRegion* curr = _head; while (curr != nullptr) { verify_region(curr); - HeapRegion* next = curr->next(); + G1HeapRegion* next = curr->next(); curr->set_next(nullptr); curr->set_prev(nullptr); curr->set_containing_set(nullptr); @@ -134,7 +134,7 @@ void FreeRegionList::add_list_common_start(FreeRegionList* from_list) { #ifdef ASSERT FreeRegionListIterator iter(from_list); while (iter.more_available()) { - HeapRegion* hr = iter.get_next(); + G1HeapRegion* hr = iter.get_next(); // In set_containing_set() we check that we either set the value // from null to non-null or vice versa to catch bugs. So, we have // to null it first before setting it to the value. @@ -189,8 +189,8 @@ void FreeRegionList::add_ordered(FreeRegionList* from_list) { _head = from_list->_head; _tail = from_list->_tail; } else { - HeapRegion* curr_to = _head; - HeapRegion* curr_from = from_list->_head; + G1HeapRegion* curr_to = _head; + G1HeapRegion* curr_from = from_list->_head; while (curr_from != nullptr) { while (curr_to != nullptr && curr_to->hrm_index() < curr_from->hrm_index()) { @@ -203,7 +203,7 @@ void FreeRegionList::add_ordered(FreeRegionList* from_list) { curr_from->set_prev(_tail); curr_from = nullptr; } else { - HeapRegion* next_from = curr_from->next(); + G1HeapRegion* next_from = curr_from->next(); curr_from->set_next(curr_to); curr_from->set_prev(curr_to->prev()); @@ -227,7 +227,7 @@ void FreeRegionList::add_ordered(FreeRegionList* from_list) { } #ifdef ASSERT -void FreeRegionList::verify_region_to_remove(HeapRegion* curr, HeapRegion* next) { +void FreeRegionList::verify_region_to_remove(G1HeapRegion* curr, G1HeapRegion* next) { assert_free_region_list(_head != next, "invariant"); if (next != nullptr) { assert_free_region_list(next->prev() == curr, "invariant"); @@ -235,7 +235,7 @@ void FreeRegionList::verify_region_to_remove(HeapRegion* curr, HeapRegion* next) } else { assert_free_region_list(_tail == curr, "invariant"); } - HeapRegion* prev = curr->prev(); + G1HeapRegion* prev = curr->prev(); if (prev == nullptr) { assert_free_region_list(_head == curr, "invariant"); } else { @@ -244,7 +244,7 @@ void FreeRegionList::verify_region_to_remove(HeapRegion* curr, HeapRegion* next) } #endif -void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) { +void FreeRegionList::remove_starting_at(G1HeapRegion* first, uint num_regions) { check_mt_safety(); assert_free_region_list(num_regions >= 1, "pre-condition"); assert_free_region_list(!is_empty(), "pre-condition"); @@ -254,13 +254,13 @@ void FreeRegionList::remove_starting_at(HeapRegion* first, uint num_regions) { DEBUG_ONLY(uint old_length = length();) // prev points to the node right before first or null when first == _head - HeapRegion* const prev = first->prev(); + G1HeapRegion* const prev = first->prev(); // next points to the node right after first or null when first == _tail, // and after the while loop below, next should point to the next node right // after the removed sublist, or null if the sublist contains _tail. - HeapRegion* next = first->next(); + G1HeapRegion* next = first->next(); - HeapRegion* curr = first; + G1HeapRegion* curr = first; uint count = 0; while (count < num_regions) { verify_region(curr); @@ -329,9 +329,9 @@ void FreeRegionList::clear() { } void FreeRegionList::verify_list() { - HeapRegion* curr = _head; - HeapRegion* prev1 = nullptr; - HeapRegion* prev0 = nullptr; + G1HeapRegion* curr = _head; + G1HeapRegion* prev1 = nullptr; + G1HeapRegion* prev0 = nullptr; uint count = 0; size_t capacity = 0; uint last_index = 0; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp index bfc60992c3d..e401b38aadc 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.hpp @@ -53,8 +53,8 @@ class HeapRegionSetChecker : public CHeapObj { public: // Verify MT safety for this HeapRegionSet. virtual void check_mt_safety() = 0; - // Returns true if the given HeapRegion is of the correct type for this HeapRegionSet. - virtual bool is_correct_type(HeapRegion* hr) = 0; + // Returns true if the given G1HeapRegion is of the correct type for this HeapRegionSet. + virtual bool is_correct_type(G1HeapRegion* hr) = 0; // Return a description of the type of regions this HeapRegionSet contains. virtual const char* get_description() = 0; }; @@ -79,7 +79,7 @@ class HeapRegionSetBase { // verify_region() is used to ensure that the contents of a region // added to / removed from a set are consistent. - void verify_region(HeapRegion* hr) PRODUCT_RETURN; + void verify_region(G1HeapRegion* hr) PRODUCT_RETURN; void check_mt_safety() { if (_checker != nullptr) { @@ -98,15 +98,15 @@ class HeapRegionSetBase { // It updates the fields of the set to reflect hr being added to // the set and tags the region appropriately. - inline void add(HeapRegion* hr); + inline void add(G1HeapRegion* hr); // It updates the fields of the set to reflect hr being removed // from the set and tags the region appropriately. - inline void remove(HeapRegion* hr); + inline void remove(G1HeapRegion* hr); virtual void verify(); void verify_start(); - void verify_next_region(HeapRegion* hr); + void verify_next_region(G1HeapRegion* hr); void verify_end(); void verify_optional() { DEBUG_ONLY(verify();) } @@ -163,19 +163,19 @@ class FreeRegionList : public HeapRegionSetBase { void add(NodeInfo* info); }; - HeapRegion* _head; - HeapRegion* _tail; + G1HeapRegion* _head; + G1HeapRegion* _tail; // _last is used to keep track of where we added an element the last // time. It helps to improve performance when adding several ordered items in a row. - HeapRegion* _last; + G1HeapRegion* _last; NodeInfo* _node_info; static uint _unrealistically_long_length; - inline HeapRegion* remove_from_head_impl(); - inline HeapRegion* remove_from_tail_impl(); + inline G1HeapRegion* remove_from_head_impl(); + inline G1HeapRegion* remove_from_tail_impl(); inline void increase_length(uint node_index); inline void decrease_length(uint node_index); @@ -184,7 +184,7 @@ class FreeRegionList : public HeapRegionSetBase { void add_list_common_start(FreeRegionList* from_list); void add_list_common_end(FreeRegionList* from_list); - void verify_region_to_remove(HeapRegion* curr, HeapRegion* next) NOT_DEBUG_RETURN; + void verify_region_to_remove(G1HeapRegion* curr, G1HeapRegion* next) NOT_DEBUG_RETURN; protected: // See the comment for HeapRegionSetBase::clear() virtual void clear(); @@ -196,7 +196,7 @@ class FreeRegionList : public HeapRegionSetBase { void verify_list(); #ifdef ASSERT - bool contains(HeapRegion* hr) const { + bool contains(G1HeapRegion* hr) const { return hr->containing_set() == this; } #endif @@ -206,14 +206,14 @@ class FreeRegionList : public HeapRegionSetBase { // Add hr to the list. The region should not be a member of another set. // Assumes that the list is ordered and will preserve that order. The order // is determined by hrm_index. - inline void add_ordered(HeapRegion* hr); + inline void add_ordered(G1HeapRegion* hr); // Same restrictions as above, but adds the region last in the list. - inline void add_to_tail(HeapRegion* region_to_add); + inline void add_to_tail(G1HeapRegion* region_to_add); // Removes from head or tail based on the given argument. - HeapRegion* remove_region(bool from_head); + G1HeapRegion* remove_region(bool from_head); - HeapRegion* remove_region_with_node_index(bool from_head, + G1HeapRegion* remove_region_with_node_index(bool from_head, uint requested_node_index); // Merge two ordered lists. The result is also ordered. The order is @@ -231,7 +231,7 @@ class FreeRegionList : public HeapRegionSetBase { // Remove all (contiguous) regions from first to first + num_regions -1 from // this list. // Num_regions must be >= 1. - void remove_starting_at(HeapRegion* first, uint num_regions); + void remove_starting_at(G1HeapRegion* first, uint num_regions); virtual void verify(); @@ -245,21 +245,21 @@ class FreeRegionList : public HeapRegionSetBase { class FreeRegionListIterator : public StackObj { private: FreeRegionList* _list; - HeapRegion* _curr; + G1HeapRegion* _curr; public: bool more_available() { return _curr != nullptr; } - HeapRegion* get_next() { + G1HeapRegion* get_next() { assert(more_available(), "get_next() should be called when more regions are available"); // If we are going to introduce a count in the iterator we should // do the "cycle" check. - HeapRegion* hr = _curr; + G1HeapRegion* hr = _curr; _list->verify_region(hr); _curr = hr->next(); return hr; diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp index fbd19466d9f..f0a38a41754 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.inline.hpp @@ -29,7 +29,7 @@ #include "gc/g1/g1NUMA.hpp" -inline void HeapRegionSetBase::add(HeapRegion* hr) { +inline void HeapRegionSetBase::add(G1HeapRegion* hr) { check_mt_safety(); assert_heap_region_set(hr->containing_set() == nullptr, "should not already have a containing set"); assert_heap_region_set(hr->next() == nullptr, "should not already be linked"); @@ -40,7 +40,7 @@ inline void HeapRegionSetBase::add(HeapRegion* hr) { verify_region(hr); } -inline void HeapRegionSetBase::remove(HeapRegion* hr) { +inline void HeapRegionSetBase::remove(G1HeapRegion* hr) { check_mt_safety(); verify_region(hr); assert_heap_region_set(hr->next() == nullptr, "should already be unlinked"); @@ -51,7 +51,7 @@ inline void HeapRegionSetBase::remove(HeapRegion* hr) { _length--; } -inline void FreeRegionList::add_to_tail(HeapRegion* region_to_add) { +inline void FreeRegionList::add_to_tail(G1HeapRegion* region_to_add) { assert_free_region_list((length() == 0 && _head == nullptr && _tail == nullptr && _last == nullptr) || (length() > 0 && _head != nullptr && _tail != nullptr && _tail->hrm_index() < region_to_add->hrm_index()), "invariant"); @@ -71,7 +71,7 @@ inline void FreeRegionList::add_to_tail(HeapRegion* region_to_add) { increase_length(region_to_add->node_index()); } -inline void FreeRegionList::add_ordered(HeapRegion* hr) { +inline void FreeRegionList::add_ordered(G1HeapRegion* hr) { assert_free_region_list((length() == 0 && _head == nullptr && _tail == nullptr && _last == nullptr) || (length() > 0 && _head != nullptr && _tail != nullptr), "invariant"); @@ -80,7 +80,7 @@ inline void FreeRegionList::add_ordered(HeapRegion* hr) { // Now link the region if (_head != nullptr) { - HeapRegion* curr; + G1HeapRegion* curr; if (_last != nullptr && _last->hrm_index() < hr->hrm_index()) { curr = _last; @@ -120,8 +120,8 @@ inline void FreeRegionList::add_ordered(HeapRegion* hr) { increase_length(hr->node_index()); } -inline HeapRegion* FreeRegionList::remove_from_head_impl() { - HeapRegion* result = _head; +inline G1HeapRegion* FreeRegionList::remove_from_head_impl() { + G1HeapRegion* result = _head; _head = result->next(); if (_head == nullptr) { _tail = nullptr; @@ -132,8 +132,8 @@ inline HeapRegion* FreeRegionList::remove_from_head_impl() { return result; } -inline HeapRegion* FreeRegionList::remove_from_tail_impl() { - HeapRegion* result = _tail; +inline G1HeapRegion* FreeRegionList::remove_from_tail_impl() { + G1HeapRegion* result = _tail; _tail = result->prev(); if (_tail == nullptr) { @@ -145,7 +145,7 @@ inline HeapRegion* FreeRegionList::remove_from_tail_impl() { return result; } -inline HeapRegion* FreeRegionList::remove_region(bool from_head) { +inline G1HeapRegion* FreeRegionList::remove_region(bool from_head) { check_mt_safety(); verify_optional(); @@ -154,7 +154,7 @@ inline HeapRegion* FreeRegionList::remove_region(bool from_head) { } assert_free_region_list(length() > 0 && _head != nullptr && _tail != nullptr, "invariant"); - HeapRegion* hr; + G1HeapRegion* hr; if (from_head) { hr = remove_from_head_impl(); @@ -174,12 +174,12 @@ inline HeapRegion* FreeRegionList::remove_region(bool from_head) { return hr; } -inline HeapRegion* FreeRegionList::remove_region_with_node_index(bool from_head, +inline G1HeapRegion* FreeRegionList::remove_region_with_node_index(bool from_head, uint requested_node_index) { assert(UseNUMA, "Invariant"); const uint max_search_depth = G1NUMA::numa()->max_search_depth(); - HeapRegion* cur; + G1HeapRegion* cur; // Find the region to use, searching from _head or _tail as requested. size_t cur_depth = 0; @@ -207,8 +207,8 @@ inline HeapRegion* FreeRegionList::remove_region_with_node_index(bool from_head, } // Splice the region out of the list. - HeapRegion* prev = cur->prev(); - HeapRegion* next = cur->next(); + G1HeapRegion* prev = cur->prev(); + G1HeapRegion* next = cur->next(); if (prev == nullptr) { _head = next; } else { diff --git a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp index d340ed646b4..a7b08a6a5c9 100644 --- a/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1HeapSizingPolicy.cpp @@ -123,7 +123,7 @@ size_t G1HeapSizingPolicy::young_collection_expansion_amount() { bool filled_history_buffer = _pauses_since_start == _num_prev_pauses_for_heuristics; if ((_ratio_over_threshold_count == MinOverThresholdForGrowth) || (filled_history_buffer && (long_term_pause_time_ratio > threshold))) { - size_t min_expand_bytes = HeapRegion::GrainBytes; + size_t min_expand_bytes = G1HeapRegion::GrainBytes; size_t reserved_bytes = _g1h->max_capacity(); size_t committed_bytes = _g1h->capacity(); size_t uncommitted_bytes = reserved_bytes - committed_bytes; @@ -224,7 +224,7 @@ size_t G1HeapSizingPolicy::full_collection_resize_amount(bool& expand) { // GC where eden is empty. During Remark there can be an // arbitrary number of eden regions which would skew the // results. - _g1h->eden_regions_count() * HeapRegion::GrainBytes; + _g1h->eden_regions_count() * G1HeapRegion::GrainBytes; size_t minimum_desired_capacity = target_heap_capacity(used_after_gc, MinHeapFreeRatio); size_t maximum_desired_capacity = target_heap_capacity(used_after_gc, MaxHeapFreeRatio); diff --git a/src/hotspot/share/gc/g1/g1HeapTransition.cpp b/src/hotspot/share/gc/g1/g1HeapTransition.cpp index 4f759b4a606..8804d37cc71 100644 --- a/src/hotspot/share/gc/g1/g1HeapTransition.cpp +++ b/src/hotspot/share/gc/g1/g1HeapTransition.cpp @@ -82,7 +82,7 @@ struct G1HeapTransition::DetailedUsage : public StackObj { class G1HeapTransition::DetailedUsageClosure: public HeapRegionClosure { public: DetailedUsage _usage; - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { if (r->is_old()) { _usage._old_used += r->used(); _usage._old_region_count++; @@ -157,17 +157,17 @@ void G1HeapTransition::print() { log_regions("Survivor", _before._survivor_length, after._survivor_length, survivor_capacity_length_before_gc, _before._survivor_length_per_node, after._survivor_length_per_node); log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K", - usage._survivor_used / K, ((after._survivor_length * HeapRegion::GrainBytes) - usage._survivor_used) / K); + usage._survivor_used / K, ((after._survivor_length * G1HeapRegion::GrainBytes) - usage._survivor_used) / K); log_info(gc, heap)("Old regions: " SIZE_FORMAT "->" SIZE_FORMAT, _before._old_length, after._old_length); log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K", - usage._old_used / K, ((after._old_length * HeapRegion::GrainBytes) - usage._old_used) / K); + usage._old_used / K, ((after._old_length * G1HeapRegion::GrainBytes) - usage._old_used) / K); log_info(gc, heap)("Humongous regions: " SIZE_FORMAT "->" SIZE_FORMAT, _before._humongous_length, after._humongous_length); log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K", - usage._humongous_used / K, ((after._humongous_length * HeapRegion::GrainBytes) - usage._humongous_used) / K); + usage._humongous_used / K, ((after._humongous_length * G1HeapRegion::GrainBytes) - usage._humongous_used) / K); MetaspaceUtils::print_metaspace_change(_before._meta_sizes); } diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index 199edded0b8..9201fc98c8a 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -110,7 +110,7 @@ class G1VerifyCodeRootOopClosure: public OopClosure { oop obj = CompressedOops::decode_not_null(heap_oop); // Now fetch the region containing the object - HeapRegion* hr = _g1h->heap_region_containing(obj); + G1HeapRegion* hr = _g1h->heap_region_containing(obj); HeapRegionRemSet* hrrs = hr->rem_set(); // Verify that the code root list for this region // contains the nmethod @@ -198,11 +198,11 @@ class VerifyObjsInRegionClosure: public ObjectClosure { private: G1CollectedHeap* _g1h; size_t _live_bytes; - HeapRegion *_hr; + G1HeapRegion* _hr; VerifyOption _vo; public: - VerifyObjsInRegionClosure(HeapRegion *hr, VerifyOption vo) + VerifyObjsInRegionClosure(G1HeapRegion* hr, VerifyOption vo) : _live_bytes(0), _hr(hr), _vo(vo) { _g1h = G1CollectedHeap::heap(); } @@ -245,7 +245,7 @@ class VerifyRegionClosure: public HeapRegionClosure { return _failures; } - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { guarantee(!r->has_index_in_opt_cset(), "Region %u still has opt collection set index %u", r->hrm_index(), r->index_in_opt_cset()); guarantee(!r->is_young() || r->rem_set()->is_complete(), "Remembered set for Young region %u must be complete, is %s", r->hrm_index(), r->rem_set()->get_state_str()); // Humongous and old regions regions might be of any state, so can't check here. @@ -394,7 +394,7 @@ class VerifyRegionListsClosure : public HeapRegionClosure { _old_set(old_set), _humongous_set(humongous_set), _hrm(hrm), _old_count(), _humongous_count(), _free_count(){ } - bool do_heap_region(HeapRegion* hr) { + bool do_heap_region(G1HeapRegion* hr) { if (hr->is_young()) { // TODO } else if (hr->is_humongous()) { @@ -452,7 +452,7 @@ class G1VerifyRegionMarkingStateClosure : public HeapRegionClosure { }; public: - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { if (r->is_free()) { return false; } @@ -541,7 +541,7 @@ void G1HeapVerifier::verify_bitmap_clear(bool from_tams) { public: G1VerifyBitmapClear(bool from_tams) : _from_tams(from_tams) { } - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); G1CMBitMap* bitmap = cm->mark_bitmap(); @@ -562,7 +562,7 @@ class G1VerifyCardTableCleanup: public HeapRegionClosure { public: G1VerifyCardTableCleanup(G1HeapVerifier* verifier) : _verifier(verifier) { } - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { if (r->is_survivor()) { _verifier->verify_dirty_region(r); } else { @@ -579,14 +579,14 @@ void G1HeapVerifier::verify_card_table_cleanup() { } } -void G1HeapVerifier::verify_not_dirty_region(HeapRegion* hr) { +void G1HeapVerifier::verify_not_dirty_region(G1HeapRegion* hr) { // All of the region should be clean. G1CardTable* ct = _g1h->card_table(); MemRegion mr(hr->bottom(), hr->end()); ct->verify_not_dirty_region(mr); } -void G1HeapVerifier::verify_dirty_region(HeapRegion* hr) { +void G1HeapVerifier::verify_dirty_region(G1HeapRegion* hr) { // We cannot guarantee that [bottom(),end()] is dirty. Threads // dirty allocated blocks as they allocate them. The thread that // retires each region and replaces it with a new one will do a @@ -608,7 +608,7 @@ class G1VerifyDirtyYoungListClosure : public HeapRegionClosure { G1HeapVerifier* _verifier; public: G1VerifyDirtyYoungListClosure(G1HeapVerifier* verifier) : HeapRegionClosure(), _verifier(verifier) { } - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { _verifier->verify_dirty_region(r); return false; } @@ -626,7 +626,7 @@ class G1CheckRegionAttrTableClosure : public HeapRegionClosure { public: G1CheckRegionAttrTableClosure() : HeapRegionClosure(), _failures(false) { } - virtual bool do_heap_region(HeapRegion* hr) { + virtual bool do_heap_region(G1HeapRegion* hr) { uint i = hr->hrm_index(); G1HeapRegionAttr region_attr = (G1HeapRegionAttr) G1CollectedHeap::heap()->_region_attr.get_by_index(i); if (hr->is_humongous()) { diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.hpp b/src/hotspot/share/gc/g1/g1HeapVerifier.hpp index 221ae957648..39246237ba3 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.hpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.hpp @@ -80,8 +80,8 @@ class G1HeapVerifier : public CHeapObj { void verify_card_table_cleanup() PRODUCT_RETURN; - void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN; - void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN; + void verify_not_dirty_region(G1HeapRegion* hr) PRODUCT_RETURN; + void verify_dirty_region(G1HeapRegion* hr) PRODUCT_RETURN; void verify_dirty_young_regions() PRODUCT_RETURN; }; diff --git a/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp b/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp index 4e0a7dcfc3d..febb27fb43c 100644 --- a/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp +++ b/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp @@ -253,8 +253,8 @@ void G1MonitoringSupport::recalculate_sizes() { uint eden_list_max_length = young_list_target_length - survivor_list_length; // First calculate the committed sizes that can be calculated independently. - _survivor_space_committed = survivor_list_length * HeapRegion::GrainBytes; - _old_gen_committed = HeapRegion::align_up_to_region_byte_size(_old_gen_used); + _survivor_space_committed = survivor_list_length * G1HeapRegion::GrainBytes; + _old_gen_committed = G1HeapRegion::align_up_to_region_byte_size(_old_gen_used); // Next, start with the overall committed size. _overall_committed = _g1h->capacity(); @@ -266,7 +266,7 @@ void G1MonitoringSupport::recalculate_sizes() { committed -= _survivor_space_committed + _old_gen_committed; // Next, calculate and remove the committed size for the eden. - _eden_space_committed = (size_t) eden_list_max_length * HeapRegion::GrainBytes; + _eden_space_committed = (size_t) eden_list_max_length * G1HeapRegion::GrainBytes; // Somewhat defensive: be robust in case there are inaccuracies in // the calculations _eden_space_committed = MIN2(_eden_space_committed, committed); diff --git a/src/hotspot/share/gc/g1/g1NMethodClosure.cpp b/src/hotspot/share/gc/g1/g1NMethodClosure.cpp index 56f1f52e981..1574ded4aa1 100644 --- a/src/hotspot/share/gc/g1/g1NMethodClosure.cpp +++ b/src/hotspot/share/gc/g1/g1NMethodClosure.cpp @@ -40,7 +40,7 @@ void G1NMethodClosure::HeapRegionGatheringOopClosure::do_oop_work(T* p) { T oop_or_narrowoop = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(oop_or_narrowoop)) { oop o = CompressedOops::decode_not_null(oop_or_narrowoop); - HeapRegion* hr = _g1h->heap_region_containing(o); + G1HeapRegion* hr = _g1h->heap_region_containing(o); assert(!_g1h->is_in_cset(o) || hr->rem_set()->code_roots_list_contains(_nm), "if o still in collection set then evacuation failed and nm must already be in the remset"); hr->add_code_root(_nm); } diff --git a/src/hotspot/share/gc/g1/g1NUMA.cpp b/src/hotspot/share/gc/g1/g1NUMA.cpp index 07c39a26989..fd80bd52ce1 100644 --- a/src/hotspot/share/gc/g1/g1NUMA.cpp +++ b/src/hotspot/share/gc/g1/g1NUMA.cpp @@ -173,7 +173,7 @@ uint G1NUMA::index_of_address(HeapWord *address) const { } } -uint G1NUMA::index_for_region(HeapRegion* hr) const { +uint G1NUMA::index_for_region(G1HeapRegion* hr) const { if (!is_enabled()) { return 0; } @@ -194,15 +194,15 @@ uint G1NUMA::index_for_region(HeapRegion* hr) const { // nodes. Which node to request for a given address is given by the // region size and the page size. Below are two examples on 4 NUMA nodes system: // 1. G1HeapRegionSize(_region_size) is larger than or equal to page size. -// * Page #: |-0--||-1--||-2--||-3--||-4--||-5--||-6--||-7--||-8--||-9--||-10-||-11-||-12-||-13-||-14-||-15-| -// * HeapRegion #: |----#0----||----#1----||----#2----||----#3----||----#4----||----#5----||----#6----||----#7----| -// * NUMA node #: |----#0----||----#1----||----#2----||----#3----||----#0----||----#1----||----#2----||----#3----| +// * Page #: |-0--||-1--||-2--||-3--||-4--||-5--||-6--||-7--||-8--||-9--||-10-||-11-||-12-||-13-||-14-||-15-| +// * G1HeapRegion #: |----#0----||----#1----||----#2----||----#3----||----#4----||----#5----||----#6----||----#7----| +// * NUMA node #: |----#0----||----#1----||----#2----||----#3----||----#0----||----#1----||----#2----||----#3----| // 2. G1HeapRegionSize(_region_size) is smaller than page size. // Memory will be touched one page at a time because G1RegionToSpaceMapper commits // pages one by one. -// * Page #: |-----0----||-----1----||-----2----||-----3----||-----4----||-----5----||-----6----||-----7----| -// * HeapRegion #: |-#0-||-#1-||-#2-||-#3-||-#4-||-#5-||-#6-||-#7-||-#8-||-#9-||#10-||#11-||#12-||#13-||#14-||#15-| -// * NUMA node #: |----#0----||----#1----||----#2----||----#3----||----#0----||----#1----||----#2----||----#3----| +// * Page #: |-----0----||-----1----||-----2----||-----3----||-----4----||-----5----||-----6----||-----7----| +// * G1HeapRegion #: |-#0-||-#1-||-#2-||-#3-||-#4-||-#5-||-#6-||-#7-||-#8-||-#9-||#10-||#11-||#12-||#13-||#14-||#15-| +// * NUMA node #: |----#0----||----#1----||----#2----||----#3----||----#0----||----#1----||----#2----||----#3----| void G1NUMA::request_memory_on_node(void* aligned_address, size_t size_in_bytes, uint region_index) { if (!is_enabled()) { return; @@ -288,7 +288,7 @@ G1NodeIndexCheckClosure::~G1NodeIndexCheckClosure() { FREE_C_HEAP_ARRAY(uint, _total); } -bool G1NodeIndexCheckClosure::do_heap_region(HeapRegion* hr) { +bool G1NodeIndexCheckClosure::do_heap_region(G1HeapRegion* hr) { // Preferred node index will only have valid node index. uint preferred_node_index = _numa->preferred_node_index_for_index(hr->hrm_index()); // Active node index may have UnknownNodeIndex. diff --git a/src/hotspot/share/gc/g1/g1NUMA.hpp b/src/hotspot/share/gc/g1/g1NUMA.hpp index cbefab411df..e9726fcad1b 100644 --- a/src/hotspot/share/gc/g1/g1NUMA.hpp +++ b/src/hotspot/share/gc/g1/g1NUMA.hpp @@ -46,7 +46,7 @@ class G1NUMA: public CHeapObj { // Total number of node ids. uint _num_active_node_ids; - // HeapRegion size + // G1HeapRegion size size_t _region_size; // Necessary when touching memory. size_t _page_size; @@ -94,9 +94,9 @@ class G1NUMA: public CHeapObj { // Returns node index of current calling thread. uint index_of_current_thread() const; - // Returns the preferred index for the given HeapRegion index. + // Returns the preferred index for the given G1HeapRegion index. // This assumes that HeapRegions are evenly spit, so we can decide preferred index - // with the given HeapRegion index. + // with the given G1HeapRegion index. // Result is less than num_active_nodes(). uint preferred_node_index_for_index(uint region_index) const; @@ -107,7 +107,7 @@ class G1NUMA: public CHeapObj { // If AlwaysPreTouch is enabled, return actual node index via system call. // If disabled, return preferred node index of the given heap region. - uint index_for_region(HeapRegion* hr) const; + uint index_for_region(G1HeapRegion* hr) const; // Requests the given memory area to be located at the given node index. void request_memory_on_node(void* aligned_address, size_t size_in_bytes, uint region_index); @@ -143,7 +143,7 @@ class G1NodeIndexCheckClosure : public HeapRegionClosure { G1NodeIndexCheckClosure(const char* desc, G1NUMA* numa, LogStream* ls); ~G1NodeIndexCheckClosure(); - bool do_heap_region(HeapRegion* hr); + bool do_heap_region(G1HeapRegion* hr); }; #endif // SHARE_VM_GC_G1_NUMA_HPP diff --git a/src/hotspot/share/gc/g1/g1OopClosures.hpp b/src/hotspot/share/gc/g1/g1OopClosures.hpp index ef32e5f33bb..965df8ea82a 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp @@ -30,7 +30,6 @@ #include "memory/iterator.hpp" #include "oops/markWord.hpp" -class HeapRegion; class G1CollectedHeap; class G1RemSet; class G1ConcurrentMark; diff --git a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp index 50b3ab203d7..1d4a1d5ab86 100644 --- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp @@ -88,7 +88,7 @@ inline void G1ScanEvacuatedObjClosure::do_oop_work(T* p) { const G1HeapRegionAttr region_attr = _g1h->region_attr(obj); if (region_attr.is_in_cset()) { prefetch_and_push(p, obj); - } else if (!HeapRegion::is_in_same_region(p, obj)) { + } else if (!G1HeapRegion::is_in_same_region(p, obj)) { handle_non_cset_obj_common(region_attr, p, obj); assert(_skip_card_enqueue != Uninitialized, "Scan location has not been initialized."); if (_skip_card_enqueue == True) { @@ -135,7 +135,7 @@ inline void G1ConcurrentRefineOopClosure::do_oop_work(T* p) { check_obj_during_refinement(p, obj); - if (HeapRegion::is_in_same_region(p, obj)) { + if (G1HeapRegion::is_in_same_region(p, obj)) { // Normally this closure should only be called with cross-region references. // But since Java threads are manipulating the references concurrently and we // reload the values things may have changed. @@ -174,7 +174,7 @@ inline void G1ScanCardClosure::do_oop_work(T* p) { // that this is a cross-region reference too. prefetch_and_push(p, obj); _heap_roots_found++; - } else if (!HeapRegion::is_in_same_region(p, obj)) { + } else if (!G1HeapRegion::is_in_same_region(p, obj)) { handle_non_cset_obj_common(region_attr, p, obj); _par_scan_state->enqueue_card_if_tracked(region_attr, p, obj); } @@ -261,11 +261,11 @@ template void G1RebuildRemSetClosure::do_oop_work(T* p) { return; } - if (HeapRegion::is_in_same_region(p, obj)) { + if (G1HeapRegion::is_in_same_region(p, obj)) { return; } - HeapRegion* to = _g1h->heap_region_containing(obj); + G1HeapRegion* to = _g1h->heap_region_containing(obj); HeapRegionRemSet* rem_set = to->rem_set(); if (rem_set->is_tracked()) { rem_set->add_reference(p, _worker_id); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index bc09a660730..e4ac20ca7ea 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -277,7 +277,7 @@ void G1ParScanThreadState::start_partial_objarray(G1HeapRegionAttr dest_attr, } // Skip the card enqueue iff the object (to_array) is in survivor region. - // However, HeapRegion::is_survivor() is too expensive here. + // However, G1HeapRegion::is_survivor() is too expensive here. // Instead, we use dest_attr.is_young() because the two values are always // equal: successfully allocated young regions must be survivor regions. assert(dest_attr.is_young() == _g1h->heap_region_containing(to_array)->is_survivor(), "must be"); @@ -444,7 +444,7 @@ void G1ParScanThreadState::undo_allocation(G1HeapRegionAttr dest_attr, void G1ParScanThreadState::update_bot_after_copying(oop obj, size_t word_sz) { HeapWord* obj_start = cast_from_oop(obj); - HeapRegion* region = _g1h->heap_region_containing(obj_start); + G1HeapRegion* region = _g1h->heap_region_containing(obj_start); region->update_bot_for_block(obj_start, obj_start + word_sz); } @@ -469,7 +469,7 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio uint age = 0; G1HeapRegionAttr dest_attr = next_region_attr(region_attr, old_mark, age); - HeapRegion* const from_region = _g1h->heap_region_containing(old); + G1HeapRegion* const from_region = _g1h->heap_region_containing(old); uint node_index = from_region->node_index(); HeapWord* obj_ptr = _plab_allocator->plab_allocate(dest_attr, word_sz, node_index); @@ -552,7 +552,7 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio } // Skip the card enqueue iff the object (obj) is in survivor region. - // However, HeapRegion::is_survivor() is too expensive here. + // However, G1HeapRegion::is_survivor() is too expensive here. // Instead, we use dest_attr.is_young() because the two values are always // equal: successfully allocated young regions must be survivor regions. assert(dest_attr.is_young() == _g1h->heap_region_containing(obj)->is_survivor(), "must be"); @@ -623,7 +623,7 @@ void G1ParScanThreadStateSet::flush_stats() { _flushed = true; } -void G1ParScanThreadStateSet::record_unused_optional_region(HeapRegion* hr) { +void G1ParScanThreadStateSet::record_unused_optional_region(G1HeapRegion* hr) { for (uint worker_index = 0; worker_index < _num_workers; ++worker_index) { G1ParScanThreadState* pss = _states[worker_index]; assert(pss != nullptr, "must be initialized"); @@ -640,7 +640,7 @@ oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markWord m, siz oop forward_ptr = old->forward_to_atomic(old, m, memory_order_relaxed); if (forward_ptr == nullptr) { // Forward-to-self succeeded. We are the "owner" of the object. - HeapRegion* r = _g1h->heap_region_containing(old); + G1HeapRegion* r = _g1h->heap_region_containing(old); if (_evac_failure_regions->record(_worker_id, r->hrm_index(), cause_pinned)) { G1HeapRegionPrinter::evac_failure(r); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index 3f8f8e22a99..24ca682e141 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -46,7 +46,7 @@ class G1EvacFailureRegions; class G1EvacuationRootClosures; class G1OopStarChunkedList; class G1PLABAllocator; -class HeapRegion; +class G1HeapRegion; class PreservedMarks; class PreservedMarksSet; class outputStream; @@ -238,7 +238,7 @@ class G1ParScanThreadState : public CHeapObj { template inline void remember_reference_into_optional_region(T* p); - inline G1OopStarChunkedList* oops_into_optional_region(const HeapRegion* hr); + inline G1OopStarChunkedList* oops_into_optional_region(const G1HeapRegion* hr); }; class G1ParScanThreadStateSet : public StackObj { @@ -265,7 +265,7 @@ class G1ParScanThreadStateSet : public StackObj { PreservedMarksSet* preserved_marks_set() { return &_preserved_marks_set; } void flush_stats(); - void record_unused_optional_region(HeapRegion* hr); + void record_unused_optional_region(G1HeapRegion* hr); G1ParScanThreadState* state_for_worker(uint worker_id); uint num_workers() const { return _num_workers; } diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp index 7f666c0f497..a164fa34929 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp @@ -89,7 +89,7 @@ inline void G1ParScanThreadState::remember_reference_into_optional_region(T* p) verify_task(p); } -G1OopStarChunkedList* G1ParScanThreadState::oops_into_optional_region(const HeapRegion* hr) { +G1OopStarChunkedList* G1ParScanThreadState::oops_into_optional_region(const G1HeapRegion* hr) { assert(hr->index_in_opt_cset() < _max_num_optional_regions, "Trying to access optional region idx %u beyond " SIZE_FORMAT " " HR_FORMAT, hr->index_in_opt_cset(), _max_num_optional_regions, HR_FORMAT_PARAMS(hr)); @@ -109,7 +109,7 @@ template bool G1ParScanThreadState::enqueue_if_new(T* p) { } template void G1ParScanThreadState::enqueue_card_into_evac_fail_region(T* p, oop obj) { - assert(!HeapRegion::is_in_same_region(p, obj), "Should have filtered out cross-region references already."); + assert(!G1HeapRegion::is_in_same_region(p, obj), "Should have filtered out cross-region references already."); assert(!_g1h->heap_region_containing(p)->is_survivor(), "Should have filtered out from-newly allocated survivor references already."); assert(_g1h->heap_region_containing(obj)->in_collection_set(), "Only for enqeueing reference into collection set region"); @@ -120,7 +120,7 @@ template void G1ParScanThreadState::enqueue_card_into_evac_fail_region template void G1ParScanThreadState::write_ref_field_post(T* p, oop obj) { assert(obj != nullptr, "Must be"); - if (HeapRegion::is_in_same_region(p, obj)) { + if (G1HeapRegion::is_in_same_region(p, obj)) { return; } G1HeapRegionAttr from_attr = _g1h->region_attr(p); @@ -144,14 +144,14 @@ template void G1ParScanThreadState::write_ref_field_post(T* p, oop obj } template void G1ParScanThreadState::enqueue_card_if_tracked(G1HeapRegionAttr region_attr, T* p, oop o) { - assert(!HeapRegion::is_in_same_region(p, o), "Should have filtered out cross-region references already."); + assert(!G1HeapRegion::is_in_same_region(p, o), "Should have filtered out cross-region references already."); assert(!_g1h->heap_region_containing(p)->is_survivor(), "Should have filtered out from-newly allocated survivor references already."); // We relabel all regions that failed evacuation as old gen without remembered, // and so pre-filter them out in the caller. assert(!_g1h->heap_region_containing(o)->in_collection_set(), "Should not try to enqueue reference into collection set region"); #ifdef ASSERT - HeapRegion* const hr_obj = _g1h->heap_region_containing(o); + G1HeapRegion* const hr_obj = _g1h->heap_region_containing(o); assert(region_attr.remset_is_tracked() == hr_obj->rem_set()->is_tracked(), "State flag indicating remset tracking disagrees (%s) with actual remembered set (%s) for region %u", BOOL_TO_STR(region_attr.remset_is_tracked()), diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index b27ddd0a9bb..7d0acd3a326 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -142,7 +142,7 @@ class G1YoungLengthPredictor { return false; } - const size_t free_bytes = (_base_free_regions - young_length) * HeapRegion::GrainBytes; + const size_t free_bytes = (_base_free_regions - young_length) * G1HeapRegion::GrainBytes; // When copying, we will likely need more bytes free than is live in the region. // Add some safety margin to factor in the confidence of our guess, and the @@ -173,7 +173,7 @@ void G1Policy::record_new_heap_size(uint new_number_of_regions) { _young_gen_sizer.heap_size_changed(new_number_of_regions); - _ihop_control->update_target_occupancy(new_number_of_regions * HeapRegion::GrainBytes); + _ihop_control->update_target_occupancy(new_number_of_regions * G1HeapRegion::GrainBytes); } uint G1Policy::calculate_desired_eden_length_by_mmu() const { @@ -507,9 +507,9 @@ uint G1Policy::calculate_desired_eden_length_before_mixed(double base_time_ms, } double G1Policy::predict_survivor_regions_evac_time() const { - const GrowableArray* survivor_regions = _g1h->survivor()->regions(); + const GrowableArray* survivor_regions = _g1h->survivor()->regions(); double survivor_regions_evac_time = predict_young_region_other_time_ms(_g1h->survivor()->length()); - for (GrowableArrayIterator it = survivor_regions->begin(); + for (GrowableArrayIterator it = survivor_regions->begin(); it != survivor_regions->end(); ++it) { survivor_regions_evac_time += predict_region_copy_time_ms(*it, _g1h->collector_state()->in_young_only_phase()); @@ -529,7 +529,7 @@ double G1Policy::predict_retained_regions_evac_time() const { list.length()); for (G1CollectionSetCandidateInfo* ci : list) { - HeapRegion* r = ci->_r; + G1HeapRegion* r = ci->_r; // We optimistically assume that any of these marking candidate regions will // be reclaimable the next gc, so just consider them as normal. if (r->has_pinned_objects()) { @@ -599,7 +599,7 @@ void G1Policy::record_full_collection_end() { _survivor_surv_rate_group->reset(); update_young_length_bounds(); - _old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * HeapRegion::GrainBytes); + _old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * G1HeapRegion::GrainBytes); record_pause(G1GCPauseType::FullGC, _full_collection_start_sec, end_sec); } @@ -663,12 +663,12 @@ bool G1Policy::should_retain_evac_failed_region(uint index) const { size_t live_bytes = _g1h->region_at(index)->live_bytes(); #ifdef ASSERT - HeapRegion* r = _g1h->region_at(index); + G1HeapRegion* r = _g1h->region_at(index); assert(live_bytes != 0, "live bytes not set for %u used %zu garbage %zu cm-live %zu pinned %d", index, r->used(), r->garbage_bytes(), live_bytes, r->has_pinned_objects()); #endif - size_t threshold = G1RetainRegionLiveThresholdPercent * HeapRegion::GrainBytes / 100; + size_t threshold = G1RetainRegionLiveThresholdPercent * G1HeapRegion::GrainBytes / 100; return live_bytes < threshold; } @@ -954,7 +954,7 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar if (_g1h->gc_cause() != GCCause::_g1_periodic_collection) { update_young_length_bounds(); - _old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * HeapRegion::GrainBytes); + _old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * G1HeapRegion::GrainBytes); update_ihop_prediction(app_time_ms / 1000.0, G1GCPauseTypeHelper::is_young_only_pause(this_pause)); @@ -1040,7 +1040,7 @@ void G1Policy::update_ihop_prediction(double mutator_time_s, // restrained by the heap reserve. Using the actual length would make the // prediction too small and the limit the young gen every time we get to the // predicted target occupancy. - size_t young_gen_size = young_list_desired_length() * HeapRegion::GrainBytes; + size_t young_gen_size = young_list_desired_length() * G1HeapRegion::GrainBytes; _ihop_control->update_allocation_info(mutator_time_s, young_gen_size); report = true; } @@ -1093,7 +1093,7 @@ double G1Policy::predict_base_time_ms(size_t pending_cards) const { return predict_base_time_ms(pending_cards, card_rs_length, code_root_rs_length); } -size_t G1Policy::predict_bytes_to_copy(HeapRegion* hr) const { +size_t G1Policy::predict_bytes_to_copy(G1HeapRegion* hr) const { size_t bytes_to_copy; if (!hr->is_young()) { bytes_to_copy = hr->live_bytes(); @@ -1111,19 +1111,19 @@ double G1Policy::predict_eden_copy_time_ms(uint count, size_t* bytes_to_copy) co if (count == 0) { return 0.0; } - size_t const expected_bytes = _eden_surv_rate_group->accum_surv_rate_pred(count - 1) * HeapRegion::GrainBytes; + size_t const expected_bytes = _eden_surv_rate_group->accum_surv_rate_pred(count - 1) * G1HeapRegion::GrainBytes; if (bytes_to_copy != nullptr) { *bytes_to_copy = expected_bytes; } return _analytics->predict_object_copy_time_ms(expected_bytes, collector_state()->in_young_only_phase()); } -double G1Policy::predict_region_copy_time_ms(HeapRegion* hr, bool for_young_only_phase) const { +double G1Policy::predict_region_copy_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const { size_t const bytes_to_copy = predict_bytes_to_copy(hr); return _analytics->predict_object_copy_time_ms(bytes_to_copy, for_young_only_phase); } -double G1Policy::predict_region_merge_scan_time(HeapRegion* hr, bool for_young_only_phase) const { +double G1Policy::predict_region_merge_scan_time(G1HeapRegion* hr, bool for_young_only_phase) const { size_t card_rs_length = hr->rem_set()->occupied(); size_t scan_card_num = _analytics->predict_scan_card_num(card_rs_length, for_young_only_phase); @@ -1132,14 +1132,14 @@ double G1Policy::predict_region_merge_scan_time(HeapRegion* hr, bool for_young_o _analytics->predict_card_scan_time_ms(scan_card_num, for_young_only_phase); } -double G1Policy::predict_region_code_root_scan_time(HeapRegion* hr, bool for_young_only_phase) const { +double G1Policy::predict_region_code_root_scan_time(G1HeapRegion* hr, bool for_young_only_phase) const { size_t code_root_length = hr->rem_set()->code_roots_list_length(); return _analytics->predict_code_root_scan_time_ms(code_root_length, for_young_only_phase); } -double G1Policy::predict_region_non_copy_time_ms(HeapRegion* hr, +double G1Policy::predict_region_non_copy_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const { double region_elapsed_time_ms = predict_region_merge_scan_time(hr, for_young_only_phase) + @@ -1154,7 +1154,7 @@ double G1Policy::predict_region_non_copy_time_ms(HeapRegion* hr, return region_elapsed_time_ms; } -double G1Policy::predict_region_total_time_ms(HeapRegion* hr, bool for_young_only_phase) const { +double G1Policy::predict_region_total_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const { return predict_region_non_copy_time_ms(hr, for_young_only_phase) + predict_region_copy_time_ms(hr, for_young_only_phase); @@ -1175,12 +1175,12 @@ size_t G1Policy::estimate_used_young_bytes_locked() const { uint used = _g1h->young_regions_count(); uint alloc = allocator->num_nodes(); uint full = used - MIN2(used, alloc); - size_t bytes_used = full * HeapRegion::GrainBytes; + size_t bytes_used = full * G1HeapRegion::GrainBytes; return bytes_used + allocator->used_in_alloc_regions(); } size_t G1Policy::desired_survivor_size(uint max_regions) const { - size_t const survivor_capacity = HeapRegion::GrainWords * max_regions; + size_t const survivor_capacity = G1HeapRegion::GrainWords * max_regions; return (size_t)((((double)survivor_capacity) * TargetSurvivorRatio) / 100); } @@ -1337,7 +1337,7 @@ void G1Policy::record_concurrent_mark_cleanup_end(bool has_rebuilt_remembered_se void G1Policy::abandon_collection_set_candidates() { // Clear remembered sets of remaining candidate regions and the actual candidate // set. - for (HeapRegion* r : *candidates()) { + for (G1HeapRegion* r : *candidates()) { r->rem_set()->clear(true /* only_cardset */); } _collection_set->abandon_all_candidates(); @@ -1502,7 +1502,7 @@ double G1Policy::select_candidates_from_marking(G1CollectionCandidateList* marki print_finish_message("Maximum number of regions reached", true); break; } - HeapRegion* hr = (*iter)->_r; + 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 @@ -1597,7 +1597,7 @@ void G1Policy::select_candidates_from_retained(G1CollectionCandidateList* retain min_regions, retained_list->length(), time_remaining_ms, optional_time_remaining_ms); for (G1CollectionSetCandidateInfo* ci : *retained_list) { - HeapRegion* r = ci->_r; + 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. @@ -1655,7 +1655,7 @@ void G1Policy::calculate_optional_collection_set_regions(G1CollectionCandidateRe double total_prediction_ms = 0.0; - for (HeapRegion* r : *optional_regions) { + for (G1HeapRegion* r : *optional_regions) { double prediction_ms = predict_region_total_time_ms(r, false); if (prediction_ms > time_remaining_ms) { @@ -1678,10 +1678,10 @@ void G1Policy::calculate_optional_collection_set_regions(G1CollectionCandidateRe void G1Policy::transfer_survivors_to_cset(const G1SurvivorRegions* survivors) { start_adding_survivor_regions(); - for (GrowableArrayIterator it = survivors->regions()->begin(); + for (GrowableArrayIterator it = survivors->regions()->begin(); it != survivors->regions()->end(); ++it) { - HeapRegion* curr = *it; + G1HeapRegion* curr = *it; set_region_survivor(curr); // The region is a non-empty survivor so let's add it to diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 43759dc4767..9de27e76d96 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -44,7 +44,7 @@ // * choice of collection set. // * when to collect. -class HeapRegion; +class G1HeapRegion; class G1CollectionSet; class G1CollectionCandidateList; class G1CollectionSetCandidates; @@ -122,12 +122,12 @@ class G1Policy: public CHeapObj { G1OldGenAllocationTracker* old_gen_alloc_tracker() { return &_old_gen_alloc_tracker; } - void set_region_eden(HeapRegion* hr) { + void set_region_eden(G1HeapRegion* hr) { hr->set_eden(); hr->install_surv_rate_group(_eden_surv_rate_group); } - void set_region_survivor(HeapRegion* hr) { + void set_region_survivor(G1HeapRegion* hr) { assert(hr->is_survivor(), "pre-condition"); hr->install_surv_rate_group(_survivor_surv_rate_group); } @@ -145,14 +145,14 @@ class G1Policy: public CHeapObj { double predict_base_time_ms(size_t pending_cards, size_t card_rs_length, size_t code_root_length) const; // Copy time for a region is copying live data. - double predict_region_copy_time_ms(HeapRegion* hr, bool for_young_only_phase) const; + double predict_region_copy_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const; // Merge-scan time for a region is handling card-based remembered sets of that region // (as a single unit). - double predict_region_merge_scan_time(HeapRegion* hr, bool for_young_only_phase) const; + double predict_region_merge_scan_time(G1HeapRegion* hr, bool for_young_only_phase) const; // Code root scan time prediction for the given region. - double predict_region_code_root_scan_time(HeapRegion* hr, bool for_young_only_phase) const; + double predict_region_code_root_scan_time(G1HeapRegion* hr, bool for_young_only_phase) const; // Non-copy time for a region is handling remembered sets and other time. - double predict_region_non_copy_time_ms(HeapRegion* hr, bool for_young_only_phase) const; + double predict_region_non_copy_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const; public: @@ -163,7 +163,7 @@ class G1Policy: public CHeapObj { double predict_eden_copy_time_ms(uint count, size_t* bytes_to_copy = nullptr) const; // Total time for a region is handling remembered sets (as a single unit), copying its live data // and other time. - double predict_region_total_time_ms(HeapRegion* hr, bool for_young_only_phase) const; + double predict_region_total_time_ms(G1HeapRegion* hr, bool for_young_only_phase) const; void cset_regions_freed() { bool update = should_update_surv_rate_group_predictors(); @@ -245,7 +245,7 @@ class G1Policy: public CHeapObj { // Limit the given desired young length to available free regions. uint calculate_young_target_length(uint desired_young_length) const; - size_t predict_bytes_to_copy(HeapRegion* hr) const; + size_t predict_bytes_to_copy(G1HeapRegion* hr) const; double predict_survivor_regions_evac_time() const; double predict_retained_regions_evac_time() const; @@ -400,7 +400,7 @@ class G1Policy: public CHeapObj { void record_concurrent_refinement_stats(size_t pending_cards, size_t thread_buffer_cards); - bool should_retain_evac_failed_region(HeapRegion* r) const { + bool should_retain_evac_failed_region(G1HeapRegion* r) const { return should_retain_evac_failed_region(r->hrm_index()); } bool should_retain_evac_failed_region(uint index) const; diff --git a/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp b/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp index 88a4b9611dc..4a81b529e7b 100644 --- a/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp +++ b/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp @@ -36,7 +36,7 @@ G1RegionsOnNodes::~G1RegionsOnNodes() { FREE_C_HEAP_ARRAY(uint, _count_per_node); } -uint G1RegionsOnNodes::add(HeapRegion* hr) { +uint G1RegionsOnNodes::add(G1HeapRegion* hr) { uint node_index = hr->node_index(); // Update only if the node index is valid. diff --git a/src/hotspot/share/gc/g1/g1RegionsOnNodes.hpp b/src/hotspot/share/gc/g1/g1RegionsOnNodes.hpp index 27f96e4977e..2ab4950a25c 100644 --- a/src/hotspot/share/gc/g1/g1RegionsOnNodes.hpp +++ b/src/hotspot/share/gc/g1/g1RegionsOnNodes.hpp @@ -28,7 +28,7 @@ #include "memory/allocation.hpp" class G1NUMA; -class HeapRegion; +class G1HeapRegion; // Contains per node index region count class G1RegionsOnNodes : public StackObj { @@ -41,7 +41,7 @@ class G1RegionsOnNodes : public StackObj { ~G1RegionsOnNodes(); // Increase _count_per_node for the node of given heap region and returns node index. - uint add(HeapRegion* hr); + uint add(G1HeapRegion* hr); void clear(); diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 63f48a15e8d..39c9c2c7a30 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -92,7 +92,7 @@ class G1RemSetScanState : public CHeapObj { size_t _max_reserved_regions; // Card table iteration claim for each heap region, from 0 (completely unscanned) - // to (>=) HeapRegion::CardsPerRegion (completely scanned). + // to (>=) G1HeapRegion::CardsPerRegion (completely scanned). uint volatile* _card_table_scan_state; uint _scan_chunks_per_region; // Number of chunks per region. @@ -223,7 +223,7 @@ class G1RemSetScanState : public CHeapObj { return AlmostNoWork; } - double num_cards = num_regions << HeapRegion::LogCardsPerRegion; + double num_cards = num_regions << G1HeapRegion::LogCardsPerRegion; return ceil(num_cards / num_cards_per_worker); } @@ -235,14 +235,14 @@ class G1RemSetScanState : public CHeapObj { } void do_work(uint worker_id) override { - const uint num_regions_per_worker = num_cards_per_worker / (uint)HeapRegion::CardsPerRegion; + const uint num_regions_per_worker = num_cards_per_worker / (uint)G1HeapRegion::CardsPerRegion; while (_cur_dirty_regions < _regions->size()) { uint next = Atomic::fetch_then_add(&_cur_dirty_regions, num_regions_per_worker); uint max = MIN2(next + num_regions_per_worker, _regions->size()); for (uint i = next; i < max; i++) { - HeapRegion* r = _g1h->region_at(_regions->at(i)); + G1HeapRegion* r = _g1h->region_at(_regions->at(i)); r->clear_cardtable(); } } @@ -276,7 +276,7 @@ class G1RemSetScanState : public CHeapObj { _num_total_scan_chunks = max_reserved_regions * _scan_chunks_per_region; _region_scan_chunks = NEW_C_HEAP_ARRAY(bool, _num_total_scan_chunks, mtGC); - _scan_chunks_shift = (uint8_t)log2i(HeapRegion::CardsPerRegion / _scan_chunks_per_region); + _scan_chunks_shift = (uint8_t)log2i(G1HeapRegion::CardsPerRegion / _scan_chunks_per_region); _scan_top = NEW_C_HEAP_ARRAY(HeapWord*, max_reserved_regions, mtGC); } @@ -317,7 +317,7 @@ class G1RemSetScanState : public CHeapObj { // - are located in free regions // as we do not clean up remembered sets before merging heap roots. bool contains_cards_to_process(uint const region_idx) const { - HeapRegion* hr = G1CollectedHeap::heap()->region_at_or_null(region_idx); + G1HeapRegion* hr = G1CollectedHeap::heap()->region_at_or_null(region_idx); return (hr != nullptr && !hr->in_collection_set() && hr->is_old_or_humongous()); } @@ -328,11 +328,11 @@ class G1RemSetScanState : public CHeapObj { result++; } } - return result * (HeapRegion::CardsPerRegion / _scan_chunks_per_region); + return result * (G1HeapRegion::CardsPerRegion / _scan_chunks_per_region); } size_t num_cards_in_dirty_regions() const { - return _next_dirty_regions->size() * HeapRegion::CardsPerRegion; + return _next_dirty_regions->size() * G1HeapRegion::CardsPerRegion; } void set_chunk_range_dirty(size_t const region_card_idx, size_t const card_length) { @@ -392,7 +392,7 @@ class G1RemSetScanState : public CHeapObj { bool has_cards_to_scan(uint region) { assert(region < _max_reserved_regions, "Tried to access invalid region %u", region); - return _card_table_scan_state[region] < HeapRegion::CardsPerRegion; + return _card_table_scan_state[region] < G1HeapRegion::CardsPerRegion; } uint claim_cards_to_scan(uint region, uint increment) { @@ -402,7 +402,7 @@ class G1RemSetScanState : public CHeapObj { void add_dirty_region(uint const region) { #ifdef ASSERT - HeapRegion* hr = G1CollectedHeap::heap()->region_at(region); + G1HeapRegion* hr = G1CollectedHeap::heap()->region_at(region); assert(!hr->in_collection_set() && hr->is_old_or_humongous(), "Region %u is not suitable for scanning, is %sin collection set or %s", hr->hrm_index(), hr->in_collection_set() ? "" : "not ", hr->get_short_type_str()); @@ -412,7 +412,7 @@ class G1RemSetScanState : public CHeapObj { void add_all_dirty_region(uint region) { #ifdef ASSERT - HeapRegion* hr = G1CollectedHeap::heap()->region_at(region); + G1HeapRegion* hr = G1CollectedHeap::heap()->region_at(region); assert(hr->in_collection_set(), "Only add collection set regions to all dirty regions directly but %u is %s", hr->hrm_index(), hr->get_short_type_str()); @@ -461,13 +461,13 @@ class G1CardTableChunkClaimer { _scan_state(scan_state), _region_idx(region_idx), _cur_claim(0) { - guarantee(size() <= HeapRegion::CardsPerRegion, "Should not claim more space than possible."); + guarantee(size() <= G1HeapRegion::CardsPerRegion, "Should not claim more space than possible."); } bool has_next() { while (true) { _cur_claim = _scan_state->claim_cards_to_scan(_region_idx, size()); - if (_cur_claim >= HeapRegion::CardsPerRegion) { + if (_cur_claim >= G1HeapRegion::CardsPerRegion) { return false; } if (_scan_state->chunk_needs_scan(_region_idx, _cur_claim)) { @@ -509,7 +509,7 @@ class G1ScanHRForRegionClosure : public HeapRegionClosure { CardValue _scanned_card_value; HeapWord* scan_memregion(uint region_idx_for_card, MemRegion mr) { - HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); + G1HeapRegion* const card_region = _g1h->region_at(region_idx_for_card); G1ScanCardClosure card_cl(_g1h, _pss, _heap_roots_found); HeapWord* const scanned_to = card_region->oops_on_memregion_seq_iterate_careful(mr, &card_cl); @@ -639,7 +639,7 @@ class G1ScanHRForRegionClosure : public HeapRegionClosure { } }; - void scan_heap_roots(HeapRegion* r) { + void scan_heap_roots(G1HeapRegion* r) { uint const region_idx = r->hrm_index(); ResourceMark rm; @@ -655,7 +655,7 @@ class G1ScanHRForRegionClosure : public HeapRegionClosure { while (claim.has_next()) { _chunks_claimed++; - size_t const region_card_base_idx = ((size_t)region_idx << HeapRegion::LogCardsPerRegion) + claim.value(); + size_t const region_card_base_idx = ((size_t)region_idx << G1HeapRegion::LogCardsPerRegion) + claim.value(); CardValue* const start_card = _ct->byte_for_index(region_card_base_idx); CardValue* const end_card = start_card + claim.size(); @@ -690,7 +690,7 @@ class G1ScanHRForRegionClosure : public HeapRegionClosure { : G1CardTable::clean_card_val()) { } - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { assert(!r->in_collection_set() && r->is_old_or_humongous(), "Should only be called on old gen non-collection set regions but region %u is not.", r->hrm_index()); @@ -776,7 +776,7 @@ class G1ScanCollectionSetRegionClosure : public HeapRegionClosure { Tickspan _rem_set_opt_root_scan_time; Tickspan _rem_set_opt_trim_partially_time; - void scan_opt_rem_set_roots(HeapRegion* r) { + void scan_opt_rem_set_roots(G1HeapRegion* r) { G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r); G1ScanCardClosure scan_cl(G1CollectedHeap::heap(), _pss, _opt_roots_scanned); @@ -805,7 +805,7 @@ class G1ScanCollectionSetRegionClosure : public HeapRegionClosure { _rem_set_opt_root_scan_time(), _rem_set_opt_trim_partially_time() { } - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { // The individual references for the optional remembered set are per-worker, so we // always need to scan them. if (r->has_index_in_opt_cset()) { @@ -880,7 +880,7 @@ void G1RemSet::assert_scan_top_is_null(uint hrm_index) { } #endif -void G1RemSet::prepare_region_for_scan(HeapRegion* r) { +void G1RemSet::prepare_region_for_scan(G1HeapRegion* r) { uint hrm_index = r->hrm_index(); r->prepare_remset_for_scan(); @@ -1044,7 +1044,7 @@ class G1MergeHeapRootsTask : public WorkerTask { bool start_iterate(uint const tag, uint const region_idx) { assert(tag < G1GCPhaseTimes::MergeRSCards, "invalid tag %u", tag); if (remember_if_interesting(region_idx)) { - _region_base_idx = (size_t)region_idx << HeapRegion::LogCardsPerRegion; + _region_base_idx = (size_t)region_idx << G1HeapRegion::LogCardsPerRegion; _stats.inc_card_set_merged(tag); return true; } @@ -1071,7 +1071,7 @@ class G1MergeHeapRootsTask : public WorkerTask { // pass) or the "dirty" list will be merged with the "all" list later otherwise. // (And there is no problem either way if the region does not contain dirty // cards). - void merge_card_set_for_region(HeapRegion* r) { + void merge_card_set_for_region(G1HeapRegion* r) { assert(r->in_collection_set() || r->is_starts_humongous(), "must be"); HeapRegionRemSet* rem_set = r->rem_set(); @@ -1080,7 +1080,7 @@ class G1MergeHeapRootsTask : public WorkerTask { } } - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { assert(r->in_collection_set(), "must be"); _scan_state->add_all_dirty_region(r->hrm_index()); @@ -1101,12 +1101,12 @@ class G1MergeHeapRootsTask : public WorkerTask { class G1ClearBitmapClosure : public HeapRegionClosure { G1CollectedHeap* _g1h; - void assert_bitmap_clear(HeapRegion* hr, const G1CMBitMap* bitmap) { + void assert_bitmap_clear(G1HeapRegion* hr, const G1CMBitMap* bitmap) { assert(bitmap->get_next_marked_addr(hr->bottom(), hr->end()) == hr->end(), "Bitmap should have no mark for region %u (%s)", hr->hrm_index(), hr->get_short_type_str()); } - bool should_clear_region(HeapRegion* hr) const { + bool should_clear_region(G1HeapRegion* hr) const { // The bitmap for young regions must obviously be clear as we never mark through them; // old regions that are currently being marked through are only in the collection set // after the concurrent cycle completed, so their bitmaps must also be clear except when @@ -1126,7 +1126,7 @@ class G1MergeHeapRootsTask : public WorkerTask { public: G1ClearBitmapClosure(G1CollectedHeap* g1h) : _g1h(g1h) { } - bool do_heap_region(HeapRegion* hr) { + bool do_heap_region(G1HeapRegion* hr) { assert(_g1h->is_in_cset(hr), "Should only be used iterating the collection set"); // Evacuation failure uses the bitmap to record evacuation failed objects, @@ -1152,7 +1152,7 @@ class G1MergeHeapRootsTask : public WorkerTask { _closure1(cl1), _closure2(cl2) { } - bool do_heap_region(HeapRegion* hr) { + bool do_heap_region(G1HeapRegion* hr) { return _closure1->do_heap_region(hr) || _closure2->do_heap_region(hr); } @@ -1173,7 +1173,7 @@ class G1MergeHeapRootsTask : public WorkerTask { return false; } - HeapRegion* r = g1h->region_at(region_index); + G1HeapRegion* r = g1h->region_at(region_index); assert(r->rem_set()->is_complete(), "humongous candidates must have complete remset"); @@ -1413,7 +1413,7 @@ void G1RemSet::print_merge_heap_roots_stats() { G1CollectedHeap* g1h = G1CollectedHeap::heap(); size_t total_old_region_cards = - (g1h->num_regions() - (g1h->num_free_regions() - g1h->collection_set()->cur_length())) * HeapRegion::CardsPerRegion; + (g1h->num_regions() - (g1h->num_free_regions() - g1h->collection_set()->cur_length())) * G1HeapRegion::CardsPerRegion; ls.print_cr("Visited cards " SIZE_FORMAT " Total dirty " SIZE_FORMAT " (%.2lf%%) Total old " SIZE_FORMAT " (%.2lf%%)", num_visited_cards, @@ -1496,7 +1496,7 @@ bool G1RemSet::clean_card_before_refine(CardValue** const card_ptr_addr) { // Find the start address represented by the card. HeapWord* start = _ct->addr_for(card_ptr); // And find the region containing it. - HeapRegion* r = _g1h->heap_region_containing_or_null(start); + G1HeapRegion* r = _g1h->heap_region_containing_or_null(start); // If this is a (stale) card into an uncommitted region, exit. if (r == nullptr) { @@ -1570,7 +1570,7 @@ void G1RemSet::refine_card_concurrently(CardValue* const card_ptr, // Construct the MemRegion representing the card. HeapWord* start = _ct->addr_for(card_ptr); // And find the region containing it. - HeapRegion* r = _g1h->heap_region_containing(start); + G1HeapRegion* r = _g1h->heap_region_containing(start); // This reload of the top is safe even though it happens after the full // fence, because top is stable for old and unfiltered humongous // regions, so it must return the same value as the previous load when diff --git a/src/hotspot/share/gc/g1/g1RemSet.hpp b/src/hotspot/share/gc/g1/g1RemSet.hpp index 260fc728923..65eabc312a6 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.hpp +++ b/src/hotspot/share/gc/g1/g1RemSet.hpp @@ -108,7 +108,7 @@ class G1RemSet: public CHeapObj { void exclude_region_from_scan(uint region_idx); // Creates a snapshot of the current _top values at the start of collection to // filter out card marks that we do not want to scan. - void prepare_region_for_scan(HeapRegion* region); + void prepare_region_for_scan(G1HeapRegion* region); // Do work for regions in the current increment of the collection set, scanning // non-card based (heap) roots. diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index 0cd1823a8ee..b8a0c709276 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -190,23 +190,23 @@ class HRRSStatsIter: public HeapRegionClosure { RegionTypeCounter _all; size_t _max_rs_mem_sz; - HeapRegion* _max_rs_mem_sz_region; + G1HeapRegion* _max_rs_mem_sz_region; size_t total_rs_unused_mem_sz() const { return _all.rs_unused_mem_size(); } size_t total_rs_mem_sz() const { return _all.rs_mem_size(); } size_t total_cards_occupied() const { return _all.cards_occupied(); } size_t max_rs_mem_sz() const { return _max_rs_mem_sz; } - HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; } + G1HeapRegion* max_rs_mem_sz_region() const { return _max_rs_mem_sz_region; } size_t _max_code_root_mem_sz; - HeapRegion* _max_code_root_mem_sz_region; + G1HeapRegion* _max_code_root_mem_sz_region; size_t total_code_root_mem_sz() const { return _all.code_root_mem_size(); } size_t total_code_root_elems() const { return _all.code_root_elems(); } size_t max_code_root_mem_sz() const { return _max_code_root_mem_sz; } - HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; } + G1HeapRegion* max_code_root_mem_sz_region() const { return _max_code_root_mem_sz_region; } public: HRRSStatsIter() : _young("Young"), _humongous("Humongous"), @@ -215,7 +215,7 @@ class HRRSStatsIter: public HeapRegionClosure { _max_code_root_mem_sz(0), _max_code_root_mem_sz_region(nullptr) {} - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { HeapRegionRemSet* hrrs = r->rem_set(); // HeapRegionRemSet::mem_size() includes the diff --git a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp index d11c1804ea5..6a97deacfab 100644 --- a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.cpp @@ -30,7 +30,7 @@ #include "gc/g1/g1RemSetTrackingPolicy.hpp" #include "runtime/safepoint.hpp" -bool G1RemSetTrackingPolicy::needs_scan_for_rebuild(HeapRegion* r) const { +bool G1RemSetTrackingPolicy::needs_scan_for_rebuild(G1HeapRegion* r) const { // All non-free and non-young regions need to be scanned for references; // At every gc we gather references to other regions in young. // Free regions trivially do not need scanning because they do not contain live @@ -38,7 +38,7 @@ bool G1RemSetTrackingPolicy::needs_scan_for_rebuild(HeapRegion* r) const { return !(r->is_young() || r->is_free()); } -void G1RemSetTrackingPolicy::update_at_allocate(HeapRegion* r) { +void G1RemSetTrackingPolicy::update_at_allocate(G1HeapRegion* r) { assert(r->is_young() || r->is_humongous() || r->is_old(), "Region %u with unexpected heap region type %s", r->hrm_index(), r->get_type_str()); if (r->is_old()) { @@ -51,11 +51,11 @@ void G1RemSetTrackingPolicy::update_at_allocate(HeapRegion* r) { r->rem_set()->set_state_complete(); } -void G1RemSetTrackingPolicy::update_at_free(HeapRegion* r) { +void G1RemSetTrackingPolicy::update_at_free(G1HeapRegion* r) { /* nothing to do */ } -bool G1RemSetTrackingPolicy::update_humongous_before_rebuild(HeapRegion* r) { +bool G1RemSetTrackingPolicy::update_humongous_before_rebuild(G1HeapRegion* r) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(r->is_starts_humongous(), "Region %u should be Humongous", r->hrm_index()); @@ -66,7 +66,7 @@ bool G1RemSetTrackingPolicy::update_humongous_before_rebuild(HeapRegion* r) { // support eager-reclaim. However, their remset state can be reset after // Full-GC. Try to re-enable remset-tracking for them if possible. if (cast_to_oop(r->bottom())->is_typeArray() && !r->rem_set()->is_tracked()) { - auto on_humongous_region = [] (HeapRegion* r) { + auto on_humongous_region = [] (G1HeapRegion* r) { r->rem_set()->set_state_updating(); }; G1CollectedHeap::heap()->humongous_obj_regions_iterate(r, on_humongous_region); @@ -76,7 +76,7 @@ bool G1RemSetTrackingPolicy::update_humongous_before_rebuild(HeapRegion* r) { return selected_for_rebuild; } -bool G1RemSetTrackingPolicy::update_old_before_rebuild(HeapRegion* r) { +bool G1RemSetTrackingPolicy::update_old_before_rebuild(G1HeapRegion* r) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(r->is_old(), "Region %u should be Old", r->hrm_index()); @@ -93,7 +93,7 @@ bool G1RemSetTrackingPolicy::update_old_before_rebuild(HeapRegion* r) { return selected_for_rebuild; } -void G1RemSetTrackingPolicy::update_after_rebuild(HeapRegion* r) { +void G1RemSetTrackingPolicy::update_after_rebuild(G1HeapRegion* r) { assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); if (r->is_old_or_humongous()) { @@ -107,7 +107,7 @@ void G1RemSetTrackingPolicy::update_after_rebuild(HeapRegion* r) { if (r->is_starts_humongous() && !g1h->is_potential_eager_reclaim_candidate(r)) { // Handle HC regions with the HS region. g1h->humongous_obj_regions_iterate(r, - [&] (HeapRegion* r) { + [&] (G1HeapRegion* r) { assert(!r->is_continues_humongous() || r->rem_set()->is_empty(), "Continues humongous region %u remset should be empty", r->hrm_index()); r->rem_set()->clear(true /* only_cardset */); diff --git a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.hpp b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.hpp index abe06d4b190..7560b726080 100644 --- a/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.hpp +++ b/src/hotspot/share/gc/g1/g1RemSetTrackingPolicy.hpp @@ -36,22 +36,22 @@ class G1RemSetTrackingPolicy : public CHeapObj { public: // Do we need to scan the given region to get all outgoing references for remembered // set rebuild? - bool needs_scan_for_rebuild(HeapRegion* r) const; + bool needs_scan_for_rebuild(G1HeapRegion* r) const; // Update remembered set tracking state at allocation of the region. May be // called at any time. The caller makes sure that the changes to the remembered // set state are visible to other threads. - void update_at_allocate(HeapRegion* r); + void update_at_allocate(G1HeapRegion* r); // Update remembered set tracking state for humongous regions before we are going to // rebuild remembered sets. Called at safepoint in the remark pause. - bool update_humongous_before_rebuild(HeapRegion* r); + bool update_humongous_before_rebuild(G1HeapRegion* r); // Update remembered set tracking state for old regions before we are going // to rebuild remembered sets. Called at safepoint in the remark pause. - bool update_old_before_rebuild(HeapRegion* r); + bool update_old_before_rebuild(G1HeapRegion* r); // Update remembered set tracking state after rebuild is complete, i.e. the cleanup // pause. Called at safepoint. - void update_after_rebuild(HeapRegion* r); + void update_after_rebuild(G1HeapRegion* r); // Update remembered set tracking state when the region is freed. - void update_at_free(HeapRegion* r); + void update_at_free(G1HeapRegion* r); }; #endif // SHARE_GC_G1_G1REMSETTRACKINGPOLICY_HPP diff --git a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp index 48773a6634e..15fc42d80fd 100644 --- a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp +++ b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp @@ -85,7 +85,7 @@ void G1SurvRateGroup::stop_adding_regions() { void G1SurvRateGroup::record_surviving_words(uint age, size_t surv_words) { assert(is_valid_age(age), "age is %u not between 0 and %u", age, _num_added_regions); - double surv_rate = (double)surv_words / HeapRegion::GrainWords; + double surv_rate = (double)surv_words / G1HeapRegion::GrainWords; _surv_rate_predictors[age]->add(surv_rate); } diff --git a/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp b/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp index fa86f02075d..b08563bb7e5 100644 --- a/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp +++ b/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp @@ -29,11 +29,11 @@ #include "utilities/debug.hpp" G1SurvivorRegions::G1SurvivorRegions() : - _regions(new (mtGC) GrowableArray(8, mtGC)), + _regions(new (mtGC) GrowableArray(8, mtGC)), _used_bytes(0), _regions_on_node() {} -uint G1SurvivorRegions::add(HeapRegion* hr) { +uint G1SurvivorRegions::add(G1HeapRegion* hr) { assert(hr->is_survivor(), "should be flagged as survivor region"); _regions->append(hr); return _regions_on_node.add(hr); @@ -48,10 +48,10 @@ uint G1SurvivorRegions::regions_on_node(uint node_index) const { } void G1SurvivorRegions::convert_to_eden() { - for (GrowableArrayIterator it = _regions->begin(); + for (GrowableArrayIterator it = _regions->begin(); it != _regions->end(); ++it) { - HeapRegion* hr = *it; + G1HeapRegion* hr = *it; hr->set_eden_pre_gc(); } clear(); diff --git a/src/hotspot/share/gc/g1/g1SurvivorRegions.hpp b/src/hotspot/share/gc/g1/g1SurvivorRegions.hpp index 2648e71ea03..daedbd35d7a 100644 --- a/src/hotspot/share/gc/g1/g1SurvivorRegions.hpp +++ b/src/hotspot/share/gc/g1/g1SurvivorRegions.hpp @@ -30,18 +30,18 @@ template class GrowableArray; -class HeapRegion; +class G1HeapRegion; class G1SurvivorRegions { private: - GrowableArray* _regions; + GrowableArray* _regions; volatile size_t _used_bytes; G1RegionsOnNodes _regions_on_node; public: G1SurvivorRegions(); - uint add(HeapRegion* hr); + uint add(G1HeapRegion* hr); void convert_to_eden(); @@ -50,7 +50,7 @@ class G1SurvivorRegions { uint length() const; uint regions_on_node(uint node_index) const; - const GrowableArray* regions() const { + const GrowableArray* regions() const { return _regions; } diff --git a/src/hotspot/share/gc/g1/g1UncommitRegionTask.cpp b/src/hotspot/share/gc/g1/g1UncommitRegionTask.cpp index 0fbaa5a4a8d..8d194063789 100644 --- a/src/hotspot/share/gc/g1/g1UncommitRegionTask.cpp +++ b/src/hotspot/share/gc/g1/g1UncommitRegionTask.cpp @@ -83,16 +83,16 @@ void G1UncommitRegionTask::report_execution(Tickspan time, uint regions) { _summary_duration += time; log_trace(gc, heap)("Concurrent Uncommit: " SIZE_FORMAT "%s, %u regions, %1.3fms", - byte_size_in_proper_unit(regions * HeapRegion::GrainBytes), - proper_unit_for_byte_size(regions * HeapRegion::GrainBytes), + byte_size_in_proper_unit(regions * G1HeapRegion::GrainBytes), + proper_unit_for_byte_size(regions * G1HeapRegion::GrainBytes), regions, time.seconds() * 1000); } void G1UncommitRegionTask::report_summary() { log_debug(gc, heap)("Concurrent Uncommit Summary: " SIZE_FORMAT "%s, %u regions, %1.3fms", - byte_size_in_proper_unit(_summary_region_count * HeapRegion::GrainBytes), - proper_unit_for_byte_size(_summary_region_count * HeapRegion::GrainBytes), + byte_size_in_proper_unit(_summary_region_count * G1HeapRegion::GrainBytes), + proper_unit_for_byte_size(_summary_region_count * G1HeapRegion::GrainBytes), _summary_region_count, _summary_duration.seconds() * 1000); } diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index 720cf3a3629..d0d49fa6d40 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -261,7 +261,7 @@ void G1YoungCollector::wait_for_root_region_scanning() { class G1PrintCollectionSetClosure : public HeapRegionClosure { public: - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { G1HeapRegionPrinter::cset(r); return false; } @@ -294,7 +294,7 @@ class G1PrepareEvacuationTask : public WorkerTask { G1MonotonicArenaMemoryStats _card_set_stats; - void sample_card_set_size(HeapRegion* hr) { + void sample_card_set_size(G1HeapRegion* hr) { // Sample card set sizes for young gen and humongous before GC: this makes // the policy to give back memory to the OS keep the most recent amount of // memory for these regions. @@ -303,7 +303,7 @@ class G1PrepareEvacuationTask : public WorkerTask { } } - bool humongous_region_is_candidate(HeapRegion* region) const { + bool humongous_region_is_candidate(G1HeapRegion* region) const { assert(region->is_starts_humongous(), "Must start a humongous object"); oop obj = cast_to_oop(region->bottom()); @@ -375,7 +375,7 @@ class G1PrepareEvacuationTask : public WorkerTask { _parent_task->add_humongous_total(_worker_humongous_total); } - virtual bool do_heap_region(HeapRegion* hr) { + virtual bool do_heap_region(G1HeapRegion* hr) { // First prepare the region for scanning _g1h->rem_set()->prepare_region_for_scan(hr); @@ -968,7 +968,7 @@ void G1YoungCollector::enqueue_candidates_as_root_regions() { assert(collector_state()->in_concurrent_start_gc(), "must be"); G1CollectionSetCandidates* candidates = collection_set()->candidates(); - for (HeapRegion* r : *candidates) { + for (G1HeapRegion* r : *candidates) { _g1h->concurrent_mark()->add_root_region(r); } } diff --git a/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp b/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp index 9bbb6bddb31..066f4353d4c 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCAllocationFailureInjector.cpp @@ -39,7 +39,7 @@ class SelectAllocationFailureRegionClosure : public HeapRegionClosure { _allocation_failure_regions(allocation_failure_regions), _allocation_failure_regions_num(cset_length * G1GCAllocationFailureALotCSetPercent / 100) { } - bool do_heap_region(HeapRegion* r) override { + bool do_heap_region(G1HeapRegion* r) override { assert(r->in_collection_set(), "must be"); if (_allocation_failure_regions_num > 0) { _allocation_failure_regions.set_bit(r->hrm_index()); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index ac1a758a709..90c85250c05 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -107,7 +107,7 @@ class G1PostEvacuateCollectionSetCleanupTask1::SampleCollectionSetCandidatesTask G1MonotonicArenaMemoryStats _total; G1CollectionSetCandidates* candidates = g1h->collection_set()->candidates(); - for (HeapRegion* r : *candidates) { + for (G1HeapRegion* r : *candidates) { _total.add(r->rem_set()->card_set_memory_stats()); } g1h->set_collection_set_candidates_stats(_total); @@ -176,7 +176,7 @@ class G1PostEvacuateCollectionSetCleanupTask1::RestoreEvacFailureRegionsTask : p // Fill the memory area from start to end with filler objects, and update the BOT // accordingly. Since we clear and use the bitmap for marking objects that failed // evacuation, there is no other work to be done there. - static size_t zap_dead_objects(HeapRegion* hr, HeapWord* start, HeapWord* end) { + static size_t zap_dead_objects(G1HeapRegion* hr, HeapWord* start, HeapWord* end) { assert(start <= end, "precondition"); if (start == end) { return 0; @@ -186,7 +186,7 @@ class G1PostEvacuateCollectionSetCleanupTask1::RestoreEvacFailureRegionsTask : p return pointer_delta(end, start); } - static void update_garbage_words_in_hr(HeapRegion* hr, size_t garbage_words) { + static void update_garbage_words_in_hr(G1HeapRegion* hr, size_t garbage_words) { if (garbage_words != 0) { hr->note_self_forward_chunk_done(garbage_words * HeapWordSize); } @@ -205,7 +205,7 @@ class G1PostEvacuateCollectionSetCleanupTask1::RestoreEvacFailureRegionsTask : p G1CMBitMap* bitmap = _cm->mark_bitmap(); const uint region_idx = _evac_failure_regions->get_region_idx(chunk_idx / _num_chunks_per_region); - HeapRegion* hr = _g1h->region_at(region_idx); + G1HeapRegion* hr = _g1h->region_at(region_idx); HeapWord* hr_bottom = hr->bottom(); HeapWord* hr_top = hr->top(); @@ -286,7 +286,7 @@ class G1PostEvacuateCollectionSetCleanupTask1::RestoreEvacFailureRegionsTask : p _num_evac_fail_regions = _evac_failure_regions->num_regions_evac_failed(); _num_chunks_per_region = G1CollectedHeap::get_chunks_per_region(); - _chunk_size = static_cast(HeapRegion::GrainWords / _num_chunks_per_region); + _chunk_size = static_cast(G1HeapRegion::GrainWords / _num_chunks_per_region); log_debug(gc, ergo)("Initializing removing self forwards with %u chunks per region", _num_chunks_per_region); @@ -387,7 +387,7 @@ class G1FreeHumongousRegionClosure : public HeapRegionIndexClosure { return false; } - HeapRegion* r = _g1h->region_at(region_index); + G1HeapRegion* r = _g1h->region_at(region_index); oop obj = cast_to_oop(r->bottom()); guarantee(obj->is_typeArray(), @@ -408,7 +408,7 @@ class G1FreeHumongousRegionClosure : public HeapRegionIndexClosure { BOOL_TO_STR(cm->is_marked_in_bitmap(obj))); _humongous_objects_reclaimed++; - auto free_humongous_region = [&] (HeapRegion* r) { + auto free_humongous_region = [&] (G1HeapRegion* r) { _freed_bytes += r->used(); r->set_containing_set(nullptr); _humongous_regions_reclaimed++; @@ -504,11 +504,11 @@ class RedirtyLoggedCardTableEntryClosure : public G1CardTableEntryClosure { G1CardTable* _g1_ct; G1EvacFailureRegions* _evac_failure_regions; - HeapRegion* region_for_card(CardValue* card_ptr) const { + G1HeapRegion* region_for_card(CardValue* card_ptr) const { return _g1h->heap_region_containing(_g1_ct->addr_for(card_ptr)); } - bool will_become_free(HeapRegion* hr) const { + bool will_become_free(G1HeapRegion* hr) const { // A region will be freed by during the FreeCollectionSet phase if the region is in the // collection set and has not had an evacuation failure. return _g1h->is_in_cset(hr) && !_evac_failure_regions->contains(hr->hrm_index()); @@ -523,7 +523,7 @@ class RedirtyLoggedCardTableEntryClosure : public G1CardTableEntryClosure { _evac_failure_regions(evac_failure_regions) { } void do_card_ptr(CardValue* card_ptr, uint worker_id) { - HeapRegion* hr = region_for_card(card_ptr); + G1HeapRegion* hr = region_for_card(card_ptr); // Should only dirty cards in regions that won't be freed. if (!will_become_free(hr)) { @@ -542,7 +542,7 @@ class G1PostEvacuateCollectionSetCleanupTask2::ProcessEvacuationFailedRegionsTas class ProcessEvacuationFailedRegionsClosure : public HeapRegionClosure { public: - bool do_heap_region(HeapRegion* r) override { + bool do_heap_region(G1HeapRegion* r) override { G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1ConcurrentMark* cm = g1h->concurrent_mark(); @@ -677,10 +677,10 @@ class FreeCSetStats { policy->cset_regions_freed(); } - void account_failed_region(HeapRegion* r) { + void account_failed_region(G1HeapRegion* r) { size_t used_words = r->live_bytes() / HeapWordSize; _failure_used_words += used_words; - _failure_waste_words += HeapRegion::GrainWords - used_words; + _failure_waste_words += G1HeapRegion::GrainWords - used_words; _after_used_bytes += r->used(); // When moving a young gen region to old gen, we "allocate" that whole @@ -689,18 +689,18 @@ class FreeCSetStats { // additional allocation: both the objects still in the region and the // ones already moved are accounted for elsewhere. if (r->is_young()) { - _bytes_allocated_in_old_since_last_gc += HeapRegion::GrainBytes; + _bytes_allocated_in_old_since_last_gc += G1HeapRegion::GrainBytes; } } - void account_evacuated_region(HeapRegion* r) { + void account_evacuated_region(G1HeapRegion* r) { size_t used = r->used(); assert(used > 0, "region %u %s zero used", r->hrm_index(), r->get_short_type_str()); _before_used_bytes += used; _regions_freed += 1; } - void account_card_rs_length(HeapRegion* r) { + void account_card_rs_length(G1HeapRegion* r) { _card_rs_length += r->rem_set()->occupied(); } }; @@ -712,7 +712,7 @@ class FreeCSetClosure : public HeapRegionClosure { EventGCPhaseParallel _event; public: - JFREventForRegion(HeapRegion* region, uint worker_id) : _event() { + JFREventForRegion(G1HeapRegion* region, uint worker_id) : _event() { _event.set_gcId(GCId::current()); _event.set_gcWorkerId(worker_id); if (region->is_young()) { @@ -748,14 +748,14 @@ class FreeCSetClosure : public HeapRegionClosure { G1EvacFailureRegions* _evac_failure_regions; uint _num_retained_regions; - void assert_tracks_surviving_words(HeapRegion* r) { + void assert_tracks_surviving_words(G1HeapRegion* r) { assert(r->young_index_in_cset() != 0 && (uint)r->young_index_in_cset() <= _g1h->collection_set()->young_region_length(), "Young index %u is wrong for region %u of type %s with %u young regions", r->young_index_in_cset(), r->hrm_index(), r->get_type_str(), _g1h->collection_set()->young_region_length()); } - void handle_evacuated_region(HeapRegion* r) { + void handle_evacuated_region(G1HeapRegion* r) { assert(!r->is_empty(), "Region %u is an empty region in the collection set.", r->hrm_index()); stats()->account_evacuated_region(r); @@ -764,7 +764,7 @@ class FreeCSetClosure : public HeapRegionClosure { _g1h->free_region(r, nullptr); } - void handle_failed_region(HeapRegion* r) { + void handle_failed_region(G1HeapRegion* r) { // Do some allocation statistics accounting. Regions that failed evacuation // are always made old, so there is no need to update anything in the young // gen statistics, but we need to update old gen statistics. @@ -794,7 +794,7 @@ class FreeCSetClosure : public HeapRegionClosure { _g1h->old_set_add(r); } - Tickspan& timer_for_region(HeapRegion* r) { + Tickspan& timer_for_region(G1HeapRegion* r) { return r->is_young() ? _young_time : _non_young_time; } @@ -817,7 +817,7 @@ class FreeCSetClosure : public HeapRegionClosure { _evac_failure_regions(evac_failure_regions), _num_retained_regions(0) { } - virtual bool do_heap_region(HeapRegion* r) { + virtual bool do_heap_region(G1HeapRegion* r) { assert(r->in_collection_set(), "Invariant: %u missing from CSet", r->hrm_index()); JFREventForRegion event(r, _worker_id); TimerForRegion timer(timer_for_region(r)); diff --git a/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp b/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp index 30b9c6cb7a1..f4daf30eb56 100644 --- a/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp @@ -52,11 +52,11 @@ G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), } if (FLAG_IS_CMDLINE(NewSize)) { - _min_desired_young_length = MAX2((uint) (NewSize / HeapRegion::GrainBytes), + _min_desired_young_length = MAX2((uint) (NewSize / G1HeapRegion::GrainBytes), 1U); if (FLAG_IS_CMDLINE(MaxNewSize)) { _max_desired_young_length = - MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes), + MAX2((uint) (MaxNewSize / G1HeapRegion::GrainBytes), 1U); _sizer_kind = SizerMaxAndNewSize; _use_adaptive_sizing = _min_desired_young_length != _max_desired_young_length; @@ -65,7 +65,7 @@ G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), } } else if (FLAG_IS_CMDLINE(MaxNewSize)) { _max_desired_young_length = - MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes), + MAX2((uint) (MaxNewSize / G1HeapRegion::GrainBytes), 1U); _sizer_kind = SizerMaxNewSizeOnly; } @@ -119,7 +119,7 @@ void G1YoungGenSizer::adjust_max_new_size(uint number_of_heap_regions) { uint result = _max_desired_young_length; recalculate_min_max_young_length(number_of_heap_regions, &temp, &result); - size_t max_young_size = result * HeapRegion::GrainBytes; + size_t max_young_size = result * G1HeapRegion::GrainBytes; if (max_young_size != MaxNewSize) { FLAG_SET_ERGO(MaxNewSize, max_young_size); } diff --git a/src/hotspot/share/gc/g1/vmStructs_g1.hpp b/src/hotspot/share/gc/g1/vmStructs_g1.hpp index 62d91fe3100..ec0db2d9782 100644 --- a/src/hotspot/share/gc/g1/vmStructs_g1.hpp +++ b/src/hotspot/share/gc/g1/vmStructs_g1.hpp @@ -34,14 +34,14 @@ volatile_nonstatic_field, \ static_field) \ \ - static_field(HeapRegion, GrainBytes, size_t) \ - static_field(HeapRegion, LogOfHRGrainBytes, uint) \ + static_field(G1HeapRegion, GrainBytes, size_t) \ + static_field(G1HeapRegion, LogOfHRGrainBytes, uint) \ \ - nonstatic_field(HeapRegion, _type, HeapRegionType) \ - nonstatic_field(HeapRegion, _bottom, HeapWord* const) \ - nonstatic_field(HeapRegion, _top, HeapWord* volatile) \ - nonstatic_field(HeapRegion, _end, HeapWord* const) \ - volatile_nonstatic_field(HeapRegion, _pinned_object_count, size_t) \ + nonstatic_field(G1HeapRegion, _type, HeapRegionType) \ + nonstatic_field(G1HeapRegion, _bottom, HeapWord* const) \ + nonstatic_field(G1HeapRegion, _top, HeapWord* volatile) \ + nonstatic_field(G1HeapRegion, _end, HeapWord* const) \ + volatile_nonstatic_field(G1HeapRegion, _pinned_object_count, size_t) \ \ nonstatic_field(HeapRegionType, _tag, HeapRegionType::Tag volatile) \ \ @@ -93,7 +93,7 @@ \ declare_type(G1CollectedHeap, CollectedHeap) \ \ - declare_toplevel_type(HeapRegion) \ + declare_toplevel_type(G1HeapRegion) \ declare_toplevel_type(HeapRegionManager) \ declare_toplevel_type(HeapRegionSetBase) \ declare_toplevel_type(G1MonitoringSupport) \ @@ -103,7 +103,7 @@ declare_toplevel_type(G1DirtyCardQueue) \ \ declare_toplevel_type(G1CollectedHeap*) \ - declare_toplevel_type(HeapRegion*) \ + declare_toplevel_type(G1HeapRegion*) \ declare_toplevel_type(G1MonitoringSupport*) \ \ declare_integer_type(HeapRegionType::Tag volatile) diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index c72ca3870b5..f0ecc5af7d2 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -838,7 +838,7 @@ #if INCLUDE_G1GC #define VM_STRUCTS_JVMCI_G1GC(nonstatic_field, static_field) \ - static_field(HeapRegion, LogOfHRGrainBytes, uint) + static_field(G1HeapRegion, LogOfHRGrainBytes, uint) #define VM_INT_CONSTANTS_JVMCI_G1GC(declare_constant, declare_constant_with_value, declare_preprocessor_constant) \ declare_constant_with_value("G1CardTable::g1_young_gen", G1CardTable::g1_young_card_val()) \ diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 54fb62180bf..9a4c0756889 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -403,7 +403,7 @@ WB_ENTRY(jboolean, WB_isObjectInOldGen(JNIEnv* env, jobject o, jobject obj)) #if INCLUDE_G1GC if (UseG1GC) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - const HeapRegion* hr = g1h->heap_region_containing(p); + const G1HeapRegion* hr = g1h->heap_region_containing(p); return hr->is_old_or_humongous(); } #endif @@ -478,7 +478,7 @@ WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj)) if (UseG1GC) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); oop result = JNIHandles::resolve(obj); - const HeapRegion* hr = g1h->heap_region_containing(result); + const G1HeapRegion* hr = g1h->heap_region_containing(result); return hr->is_humongous(); } THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1IsHumongous: G1 GC is not enabled"); @@ -487,7 +487,7 @@ WB_END WB_ENTRY(jboolean, WB_G1BelongsToHumongousRegion(JNIEnv* env, jobject o, jlong addr)) if (UseG1GC) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - const HeapRegion* hr = g1h->heap_region_containing((void*) addr); + const G1HeapRegion* hr = g1h->heap_region_containing((void*) addr); return hr->is_humongous(); } THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1BelongsToHumongousRegion: G1 GC is not enabled"); @@ -496,7 +496,7 @@ WB_END WB_ENTRY(jboolean, WB_G1BelongsToFreeRegion(JNIEnv* env, jobject o, jlong addr)) if (UseG1GC) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - const HeapRegion* hr = g1h->heap_region_containing((void*) addr); + const G1HeapRegion* hr = g1h->heap_region_containing((void*) addr); return hr->is_free(); } THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1BelongsToFreeRegion: G1 GC is not enabled"); @@ -539,7 +539,7 @@ WB_END WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o)) if (UseG1GC) { - return (jint)HeapRegion::GrainBytes; + return (jint)G1HeapRegion::GrainBytes; } THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1RegionSize: G1 GC is not enabled"); WB_END @@ -626,11 +626,11 @@ class OldRegionsLivenessClosure: public HeapRegionClosure { size_t total_memory() { return _total_memory; } size_t total_memory_to_free() { return _total_memory_to_free; } - bool do_heap_region(HeapRegion* r) { + bool do_heap_region(G1HeapRegion* r) { if (r->is_old()) { size_t live = r->live_bytes(); size_t size = r->used(); - size_t reg_size = HeapRegion::GrainBytes; + size_t reg_size = G1HeapRegion::GrainBytes; if (size > 0 && ((int)(live * 100 / size) < _liveness)) { _total_memory += size; ++_total_count; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java index 6ef7d3d077b..870621421c8 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java @@ -1088,7 +1088,7 @@ public void addAnnotation(Address addr, OopHandle handle) { } } else if (collHeap instanceof G1CollectedHeap) { G1CollectedHeap heap = (G1CollectedHeap)collHeap; - HeapRegion region = heap.hrm().getByAddress(handle); + G1HeapRegion region = heap.hrm().getByAddress(handle); if (region == null) { // intentionally skip diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java index e04b2381da9..16e91d0a0cd 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java @@ -110,22 +110,22 @@ public HeapRegionSetBase humongousSet() { return VMObjectFactory.newObject(HeapRegionSetBase.class, humongousSetAddr); } - private Iterator heapRegionIterator() { + private Iterator heapRegionIterator() { return hrm().heapRegionIterator(); } public void heapRegionIterate(HeapRegionClosure hrcl) { - Iterator iter = heapRegionIterator(); + Iterator iter = heapRegionIterator(); while (iter.hasNext()) { - HeapRegion hr = iter.next(); + G1HeapRegion hr = iter.next(); hrcl.doHeapRegion(hr); } } - public HeapRegion heapRegionForAddress(Address addr) { - Iterator iter = heapRegionIterator(); + public G1HeapRegion heapRegionForAddress(Address addr) { + Iterator iter = heapRegionIterator(); while (iter.hasNext()) { - HeapRegion hr = iter.next(); + G1HeapRegion hr = iter.next(); if (hr.isInRegion(addr)) { return hr; } @@ -139,9 +139,9 @@ public CollectedHeapName kind() { @Override public void liveRegionsIterate(LiveRegionsClosure closure) { - Iterator iter = heapRegionIterator(); + Iterator iter = heapRegionIterator(); while (iter.hasNext()) { - HeapRegion hr = iter.next(); + G1HeapRegion hr = iter.next(); closure.doLiveRegions(hr); } } @@ -152,7 +152,7 @@ public void printOn(PrintStream tty) { tty.print("garbage-first heap"); tty.print(" [" + mr.start() + ", " + mr.end() + "]"); - tty.println(" region size " + (HeapRegion.grainBytes() / 1024) + "K"); + tty.println(" region size " + (G1HeapRegion.grainBytes() / 1024) + "K"); HeapSummary sum = new HeapSummary(); sum.printG1HeapSummary(tty, this); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegion.java similarity index 93% rename from src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegion.java index 3abc3f75cd8..ef270ba5671 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegion.java @@ -41,10 +41,10 @@ import sun.jvm.hotspot.types.Type; import sun.jvm.hotspot.types.TypeDataBase; -// Mirror class for HeapRegion. Currently we don't actually include +// Mirror class for G1HeapRegion. Currently we don't actually include // any of its fields but only iterate over it. -public class HeapRegion extends ContiguousSpace implements LiveRegionsProvider { +public class G1HeapRegion extends ContiguousSpace implements LiveRegionsProvider { private static AddressField bottomField; private static AddressField topField; private static AddressField endField; @@ -66,7 +66,7 @@ public void update(Observable o, Object data) { } private static synchronized void initialize(TypeDataBase db) { - Type type = db.lookupType("HeapRegion"); + Type type = db.lookupType("G1HeapRegion"); bottomField = type.getAddressField("_bottom"); topField = type.getAddressField("_top"); @@ -77,14 +77,14 @@ private static synchronized void initialize(TypeDataBase db) { typeFieldOffset = type.getField("_type").getOffset(); - pointerSize = db.lookupType("HeapRegion*").getSize(); + pointerSize = db.lookupType("G1HeapRegion*").getSize(); } public static long grainBytes() { return grainBytesField.getValue(); } - public HeapRegion(Address addr) { + public G1HeapRegion(Address addr) { super(addr); Address typeAddr = (addr instanceof OopHandle) ? addr.addOffsetToAsOopHandle(typeFieldOffset) : addr.addOffsetTo(typeFieldOffset); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java index dc6960f2114..864c9319966 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1HeapRegionTable.java @@ -38,14 +38,14 @@ import sun.jvm.hotspot.types.Type; import sun.jvm.hotspot.types.TypeDataBase; -// Mirror class for G1HeapRegionTable. It's essentially an index -> HeapRegion map. +// Mirror class for G1HeapRegionTable. It's essentially an index -> G1HeapRegion map. public class G1HeapRegionTable extends VMObject { - // HeapRegion** _base; + // G1HeapRegion** _base; private static AddressField baseField; // uint _length; private static CIntegerField lengthField; - // HeapRegion** _biased_base + // G1HeapRegion** _biased_base private static AddressField biasedBaseField; // size_t _bias private static CIntegerField biasField; @@ -70,12 +70,12 @@ private static synchronized void initialize(TypeDataBase db) { shiftByField = type.getCIntegerField("_shift_by"); } - private HeapRegion at(long index) { + private G1HeapRegion at(long index) { Address arrayAddr = baseField.getValue(addr); // Offset of &_base[index] long offset = index * VM.getVM().getAddressSize(); Address regionAddr = arrayAddr.getAddressAt(offset); - return VMObjectFactory.newObject(HeapRegion.class, regionAddr); + return VMObjectFactory.newObject(G1HeapRegion.class, regionAddr); } public long length() { @@ -90,13 +90,13 @@ public long shiftBy() { return shiftByField.getValue(addr); } - private class HeapRegionIterator implements Iterator { + private class G1HeapRegionIterator implements Iterator { private long index; private long length; - private HeapRegion next; + private G1HeapRegion next; - public HeapRegion positionToNext() { - HeapRegion result = next; + public G1HeapRegion positionToNext() { + G1HeapRegion result = next; while (index < length && at(index) == null) { index++; } @@ -113,31 +113,31 @@ public HeapRegion positionToNext() { public boolean hasNext() { return next != null; } @Override - public HeapRegion next() { return positionToNext(); } + public G1HeapRegion next() { return positionToNext(); } @Override public void remove() { /* not supported */ } - HeapRegionIterator(long totalLength) { + G1HeapRegionIterator(long totalLength) { index = 0; length = totalLength; positionToNext(); } } - public Iterator heapRegionIterator(long committedLength) { - return new HeapRegionIterator(committedLength); + public Iterator heapRegionIterator(long committedLength) { + return new G1HeapRegionIterator(committedLength); } public G1HeapRegionTable(Address addr) { super(addr); } - public HeapRegion getByAddress(Address target) { + public G1HeapRegion getByAddress(Address target) { Address arrayAddr = biasedBaseField.getValue(addr); long biasedIndex = target.asLongValue() >>> shiftBy(); - long offset = biasedIndex * HeapRegion.getPointerSize(); + long offset = biasedIndex * G1HeapRegion.getPointerSize(); Address regionAddr = arrayAddr.getAddressAt(offset); - return VMObjectFactory.newObject(HeapRegion.class, regionAddr); + return VMObjectFactory.newObject(G1HeapRegion.class, regionAddr); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1MonitoringSupport.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1MonitoringSupport.java index d630db07012..23bbad2c3df 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1MonitoringSupport.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1MonitoringSupport.java @@ -78,7 +78,7 @@ public long edenSpaceUsed() { } public long edenSpaceRegionNum() { - return edenSpaceUsed() / HeapRegion.grainBytes(); + return edenSpaceUsed() / G1HeapRegion.grainBytes(); } public long survivorSpaceCommitted() { @@ -90,7 +90,7 @@ public long survivorSpaceUsed() { } public long survivorSpaceRegionNum() { - return survivorSpaceUsed() / HeapRegion.grainBytes(); + return survivorSpaceUsed() / G1HeapRegion.grainBytes(); } public long oldGenCommitted() { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionClosure.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionClosure.java index fe9bb7dc3c8..d63679d3099 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionClosure.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionClosure.java @@ -25,5 +25,5 @@ package sun.jvm.hotspot.gc.g1; public interface HeapRegionClosure { - public void doHeapRegion(HeapRegion hr); + public void doHeapRegion(G1HeapRegion hr); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java index 4af2c0322f8..d79723c2c80 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionManager.java @@ -63,14 +63,14 @@ private G1HeapRegionTable regions() { } public long capacity() { - return length() * HeapRegion.grainBytes(); + return length() * G1HeapRegion.grainBytes(); } public long length() { return regions().length(); } - public Iterator heapRegionIterator() { + public Iterator heapRegionIterator() { return regions().heapRegionIterator(length()); } @@ -78,7 +78,7 @@ public HeapRegionManager(Address addr) { super(addr); } - public HeapRegion getByAddress(Address addr) { + public G1HeapRegion getByAddress(Address addr) { return regions().getByAddress(addr); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/PrintRegionClosure.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/PrintRegionClosure.java index f47fe6fcea3..fb777f35167 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/PrintRegionClosure.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/PrintRegionClosure.java @@ -25,7 +25,7 @@ package sun.jvm.hotspot.gc.g1; import java.io.PrintStream; -import sun.jvm.hotspot.gc.g1.HeapRegion; +import sun.jvm.hotspot.gc.g1.G1HeapRegion; public class PrintRegionClosure implements HeapRegionClosure { private PrintStream tty; @@ -34,7 +34,7 @@ public PrintRegionClosure(PrintStream tty) { this.tty = tty; } - public void doHeapRegion(HeapRegion hr) { + public void doHeapRegion(G1HeapRegion hr) { hr.printOn(tty); } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java index e3eee4b7237..41788757e0c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java @@ -87,7 +87,7 @@ public void run() { printValMB("CompressedClassSpaceSize = ", getFlagValue("CompressedClassSpaceSize", flagMap)); printValMB("MaxMetaspaceSize = ", getFlagValue("MaxMetaspaceSize", flagMap)); if (heap instanceof G1CollectedHeap) { - printValMB("G1HeapRegionSize = ", HeapRegion.grainBytes()); + printValMB("G1HeapRegionSize = ", G1HeapRegion.grainBytes()); } System.out.println(); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java index d4368ee8b96..1fea467abeb 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerFinder.java @@ -123,8 +123,8 @@ public static PointerLocation find(Address a) { loc.hr = g1.heapRegionForAddress(a); // We don't assert that loc.hr is not null like we do for the SerialHeap. This is // because heap.isIn(a) can return true if the address is anywhere in G1's mapped - // memory, even if that area of memory is not in use by a G1 HeapRegion. So there - // may in fact be no HeapRegion for the address even though it is in the heap. + // memory, even if that area of memory is not in use by a G1HeapRegion. So there + // may in fact be no G1HeapRegion for the address even though it is in the heap. // Leaving loc.hr == null in this case will result in PointerFinder saying that // the address is "In unknown section of Java the heap", which is what we want. } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java index 39937d834c6..393ad76a011 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java @@ -59,7 +59,7 @@ public class PointerLocation { CollectedHeap heap; Generation gen; // Serial heap generation - HeapRegion hr; // G1 heap region + G1HeapRegion hr; // G1 heap region // If UseTLAB was enabled and the pointer was found in a // currently-active TLAB, these will be set @@ -128,7 +128,7 @@ public Generation getGeneration() { return gen; // SerialHeap generation } - public HeapRegion getHeapRegion() { + public G1HeapRegion getG1HeapRegion() { return hr; // G1 heap region } @@ -302,11 +302,11 @@ public void printOn(PrintStream tty, boolean printAddress, boolean verbose) { getGeneration().printOn(tty); // does not include "\n" } tty.println(); - } else if (getHeapRegion() != null) { + } else if (getG1HeapRegion() != null) { // Address is in the G1 heap if (verbose) { tty.print("In G1 heap "); - getHeapRegion().printOn(tty); // includes "\n" + getG1HeapRegion().printOn(tty); // includes "\n" } else { tty.println("In G1 heap region"); } diff --git a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp index 4639f1c9694..60ebf3c7208 100644 --- a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp +++ b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp @@ -42,11 +42,11 @@ TEST_OTHER_VM(FreeRegionList, length) { FreeRegionList l("test"); const uint num_regions_in_test = 5; - // Create a fake heap. It does not need to be valid, as the HeapRegion constructor + // Create a fake heap. It does not need to be valid, as the G1HeapRegion constructor // does not access it. - MemRegion heap(nullptr, num_regions_in_test * HeapRegion::GrainWords); + MemRegion heap(nullptr, num_regions_in_test * G1HeapRegion::GrainWords); - // Allocate a fake BOT because the HeapRegion constructor initializes + // Allocate a fake BOT because the G1HeapRegion constructor initializes // the BOT. size_t bot_size = G1BlockOffsetTable::compute_size(heap.word_size()); HeapWord* bot_data = NEW_C_HEAP_ARRAY(HeapWord, bot_size, mtGC); @@ -55,26 +55,26 @@ TEST_OTHER_VM(FreeRegionList, length) { G1RegionToSpaceMapper::create_mapper(bot_rs, bot_rs.size(), os::vm_page_size(), - HeapRegion::GrainBytes, + G1HeapRegion::GrainBytes, CardTable::card_size(), mtGC); G1BlockOffsetTable bot(heap, bot_storage); bot_storage->commit_regions(0, num_regions_in_test); // Set up memory regions for the heap regions. - MemRegion mr0(heap.start(), HeapRegion::GrainWords); - MemRegion mr1(mr0.end(), HeapRegion::GrainWords); - MemRegion mr2(mr1.end(), HeapRegion::GrainWords); - MemRegion mr3(mr2.end(), HeapRegion::GrainWords); - MemRegion mr4(mr3.end(), HeapRegion::GrainWords); + MemRegion mr0(heap.start(), G1HeapRegion::GrainWords); + MemRegion mr1(mr0.end(), G1HeapRegion::GrainWords); + MemRegion mr2(mr1.end(), G1HeapRegion::GrainWords); + MemRegion mr3(mr2.end(), G1HeapRegion::GrainWords); + MemRegion mr4(mr3.end(), G1HeapRegion::GrainWords); G1CardSetConfiguration config; - HeapRegion hr0(0, &bot, mr0, &config); - HeapRegion hr1(1, &bot, mr1, &config); - HeapRegion hr2(2, &bot, mr2, &config); - HeapRegion hr3(3, &bot, mr3, &config); - HeapRegion hr4(4, &bot, mr4, &config); + G1HeapRegion hr0(0, &bot, mr0, &config); + G1HeapRegion hr1(1, &bot, mr1, &config); + G1HeapRegion hr2(2, &bot, mr2, &config); + G1HeapRegion hr3(3, &bot, mr3, &config); + G1HeapRegion hr4(4, &bot, mr4, &config); l.add_ordered(&hr1); l.add_ordered(&hr0); diff --git a/test/hotspot/gtest/gc/g1/test_heapRegion.cpp b/test/hotspot/gtest/gc/g1/test_heapRegion.cpp index c274e1c8494..c8d30226176 100644 --- a/test/hotspot/gtest/gc/g1/test_heapRegion.cpp +++ b/test/hotspot/gtest/gc/g1/test_heapRegion.cpp @@ -72,7 +72,7 @@ void VM_HeapRegionApplyToMarkedObjectsTest::doit() { G1CollectedHeap* heap = G1CollectedHeap::heap(); // Using region 0 for testing. - HeapRegion* region = heap->heap_region_containing(heap->bottom_addr_for_region(0)); + G1HeapRegion* region = heap->heap_region_containing(heap->bottom_addr_for_region(0)); // Mark some "oops" in the bitmap. G1CMBitMap* bitmap = heap->concurrent_mark()->mark_bitmap(); @@ -88,7 +88,7 @@ void VM_HeapRegionApplyToMarkedObjectsTest::doit() { // When top is equal to bottom the closure should not be // applied to any object because apply_to_marked_objects - // will stop at HeapRegion::scan_limit which is equal to top. + // will stop at G1HeapRegion::scan_limit which is equal to top. region->set_top(region->bottom()); region->apply_to_marked_objects(bitmap, &cl); EXPECT_EQ(0, cl.count()); @@ -122,7 +122,7 @@ void VM_HeapRegionApplyToMarkedObjectsTest::doit() { region->set_top(old_top); } -TEST_OTHER_VM(HeapRegion, apply_to_marked_object) { +TEST_OTHER_VM(G1HeapRegion, apply_to_marked_object) { if (!UseG1GC) { return; } diff --git a/test/hotspot/jtreg/gc/g1/TestHumongousAllocNearlyFullRegion.java b/test/hotspot/jtreg/gc/g1/TestHumongousAllocNearlyFullRegion.java index d6d8b5578cc..0c25a6d03ae 100644 --- a/test/hotspot/jtreg/gc/g1/TestHumongousAllocNearlyFullRegion.java +++ b/test/hotspot/jtreg/gc/g1/TestHumongousAllocNearlyFullRegion.java @@ -29,7 +29,7 @@ * @test TestHumongousAllocNearlyFullRegion * @bug 8143587 * @summary G1: humongous object allocations should work even when there is - * not enough space in the heapRegion to fit a filler object. + * not enough space in the G1HeapRegion to fit a filler object. * @requires vm.gc.G1 * @modules java.base/jdk.internal.misc * @library /test/lib @@ -62,7 +62,7 @@ public static void main(String[] args) throws Exception { static class HumongousObjectAllocator { public static void main(String [] args) { for (int i = 0; i < heapSize; i++) { - // 131069 is the number of longs it takes to fill a heapRegion except + // 131069 is the number of longs it takes to fill a G1HeapRegion except // for 8 bytes on 64 bit. blackHole(new long[131069]); } diff --git a/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java b/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java index 832281c8257..407248c7f28 100644 --- a/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java +++ b/test/hotspot/jtreg/gc/g1/numa/TestG1NUMATouchRegions.java @@ -109,7 +109,7 @@ static long heapPageSize(OutputAnalyzer output) { // 1. -UseLargePages: default page, page size < G1HeapRegionSize // +UseLargePages: large page size <= G1HeapRegionSize // - // Each 'int' represents a numa id of single HeapRegion (bottom page). + // Each 'int' represents a numa id of single G1HeapRegion (bottom page). // e.g. 1MB heap region, 2MB page size and 2 NUMA nodes system // Check the first set(2 regions) // 0| ...omitted..| 0 diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsHumongous.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsHumongous.java index b863f609caf..01cebb29f91 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsHumongous.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsHumongous.java @@ -84,10 +84,10 @@ public static void test(String[] args) throws Exception { "-Xlog:gc+region+cds", "-Xlog:gc+region=trace")); TestCommon.checkDump(dumpOutput, "extra interned string ignored; size too large"); - // Extra strings that are humongous are not kelp alive, so they should be GC'ed + // Extra strings that are humongous are not kept alive, so they should be GC'ed // before dumping the string table. That means the heap should contain no // humongous regions. - dumpOutput.shouldNotMatch("gc,region,cds. HeapRegion 0x[0-9a-f]* HUM"); + dumpOutput.shouldNotMatch("gc,region,cds. G1HeapRegion 0x[0-9a-f]* HUM"); OutputAnalyzer execOutput = TestCommon.exec(appJar, TestCommon.concat(vmOptionsPrefix, "HelloString")); diff --git a/test/hotspot/jtreg/serviceability/sa/TestG1HeapRegion.java b/test/hotspot/jtreg/serviceability/sa/TestG1HeapRegion.java index 5c344b408dc..c4e13858a7d 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestG1HeapRegion.java +++ b/test/hotspot/jtreg/serviceability/sa/TestG1HeapRegion.java @@ -25,7 +25,7 @@ import java.util.List; import sun.jvm.hotspot.gc.g1.G1CollectedHeap; -import sun.jvm.hotspot.gc.g1.HeapRegion; +import sun.jvm.hotspot.gc.g1.G1HeapRegion; import sun.jvm.hotspot.HotSpotAgent; import sun.jvm.hotspot.runtime.VM; @@ -59,11 +59,11 @@ private static void checkHeapRegion(String pid) throws Exception { try { agent.attach(Integer.parseInt(pid)); G1CollectedHeap heap = (G1CollectedHeap)VM.getVM().getUniverse().heap(); - HeapRegion hr = heap.hrm().heapRegionIterator().next(); - HeapRegion hrTop = heap.hrm().getByAddress(hr.top()); + G1HeapRegion hr = heap.hrm().heapRegionIterator().next(); + G1HeapRegion hrTop = heap.hrm().getByAddress(hr.top()); Asserts.assertEquals(hr.top(), hrTop.top(), - "Address of HeapRegion does not match."); + "Address of G1HeapRegion does not match."); } finally { agent.detach(); } diff --git a/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java b/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java index 84744c70cdf..61d81c0fd46 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java +++ b/test/hotspot/jtreg/serviceability/sa/TestObjectAlignment.java @@ -55,7 +55,7 @@ private static void checkAlignment(String pid, int expectedAlign) throws Excepti agent.attach(Integer.parseInt(pid)); int actualAlign = VM.getVM().getObjectAlignmentInBytes(); Asserts.assertEquals(expectedAlign, actualAlign, - "Address of HeapRegion does not match."); + "Address of G1HeapRegion does not match."); } finally { agent.detach(); } From 97ee2ffb89257a37a178b70c8fee96a1d831deb6 Mon Sep 17 00:00:00 2001 From: Phil Race Date: Sat, 25 May 2024 23:17:57 +0000 Subject: [PATCH 44/99] 8332416: Add more font selection options to Font2DTest Reviewed-by: tr, honkar --- src/demo/share/jfc/Font2DTest/Font2DTest.java | 514 ++++++++++++++++-- src/demo/share/jfc/Font2DTest/FontPanel.java | 5 +- 2 files changed, 467 insertions(+), 52 deletions(-) diff --git a/src/demo/share/jfc/Font2DTest/Font2DTest.java b/src/demo/share/jfc/Font2DTest/Font2DTest.java index e237ee680ce..e474e638105 100644 --- a/src/demo/share/jfc/Font2DTest/Font2DTest.java +++ b/src/demo/share/jfc/Font2DTest/Font2DTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -67,22 +67,20 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.lang.reflect.InvocationTargetException; import java.util.StringTokenizer; +import java.util.ArrayList; import java.util.BitSet; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; import javax.swing.*; import javax.swing.event.*; +import javax.swing.plaf.nimbus.NimbusLookAndFeel; import static java.nio.charset.StandardCharsets.UTF_16; -/** - * Font2DTest.java - * - * @author Shinsuke Fukuda - * @author Ankit Patel [Conversion to Swing - 01/07/30] - */ - -/// Main Font2DTest Class - public final class Font2DTest extends JPanel implements ActionListener, ItemListener, ChangeListener { @@ -95,6 +93,12 @@ public final class Font2DTest extends JPanel /// Other menus to set parameters for text drawing private final ChoiceV2 fontMenu; + private JPanel fontMenuPanel; + private JPanel stylePanel; + private LabelV2 fontMenuLabel = null; + private LabelV2 styleLabel = null; + private ChoiceV2 fontNameMenu; + private ChoiceV2 fontSubFamilyMenu; private final JTextField sizeField; private final ChoiceV2 styleMenu; private final ChoiceV2 textMenu; @@ -111,6 +115,9 @@ public final class Font2DTest extends JPanel private CheckboxMenuItemV2 displayGridCBMI; private CheckboxMenuItemV2 force16ColsCBMI; private CheckboxMenuItemV2 showFontInfoCBMI; + private JRadioButtonMenuItem familyAndStyleRBMI; + private JRadioButtonMenuItem familyAndSubFamilyRBMI; + private JRadioButtonMenuItem fontNameRBMI; /// JDialog boxes private JDialog userTextDialog; @@ -126,6 +133,7 @@ public final class Font2DTest extends JPanel /// Status bar private final LabelV2 statusBar; + private String currentFontName = Font.DIALOG; private int[] fontStyles = {Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLD | Font.ITALIC}; /// Text filename @@ -133,6 +141,7 @@ public final class Font2DTest extends JPanel // Enabled or disabled status of canDisplay check private static boolean canDisplayCheck = true; + private static final Locale l = Locale.getDefault(); /// Initialize GUI variables and its layouts public Font2DTest( JFrame f) { @@ -143,6 +152,8 @@ public Font2DTest( JFrame f) { statusBar = new LabelV2(""); fontMenu = new ChoiceV2( this, canDisplayCheck ); + fontNameMenu = new ChoiceV2( this, false ); + fontSubFamilyMenu = new ChoiceV2( this, false ); sizeField = new JTextField( "12", 3 ); sizeField.addActionListener( this ); styleMenu = new ChoiceV2( this ); @@ -175,6 +186,46 @@ public Font2DTest( JFrame f) { } } + private void addFontMenuToGBL(String labelText, + JComponent menuContainer, + GridBagLayout gbl, + GridBagConstraints gbc, + int leftInset, + Container target) { + + fontMenuLabel = new LabelV2(labelText); + fontMenuLabel.setLabelFor(menuContainer); + GridBagConstraints gbcLabel = (GridBagConstraints) gbc.clone(); + gbcLabel.insets = new Insets(2, leftInset, 2, 0); + gbcLabel.gridwidth = 1; + gbcLabel.weightx = 0; + gbcLabel.anchor = GridBagConstraints.EAST; + gbl.setConstraints(fontMenuLabel, gbcLabel); + target.add(fontMenuLabel); + gbl.setConstraints(menuContainer, gbc); + target.add( menuContainer ); + } + + private void addStyleMenuToGBL(String labelText, + JComponent menuContainer, + GridBagLayout gbl, + GridBagConstraints gbc, + int leftInset, + Container target) { + + styleLabel = new LabelV2(labelText); + styleLabel.setLabelFor(menuContainer); + GridBagConstraints gbcLabel = (GridBagConstraints) gbc.clone(); + gbcLabel.insets = new Insets(2, leftInset, 2, 0); + gbcLabel.gridwidth = 1; + gbcLabel.weightx = 0; + gbcLabel.anchor = GridBagConstraints.EAST; + gbl.setConstraints(styleLabel, gbcLabel); + target.add(styleLabel); + gbl.setConstraints(menuContainer, gbc); + target.add(menuContainer); + } + /// Set up the main interface panel private void setupPanel() { GridBagLayout gbl = new GridBagLayout(); @@ -184,43 +235,49 @@ private void setupPanel() { gbc.insets = new Insets( 2, 0, 2, 2 ); this.setLayout( gbl ); - addLabeledComponentToGBL( "Font: ", fontMenu, gbl, gbc, this ); - addLabeledComponentToGBL( "Size: ", sizeField, gbl, gbc, this ); + fontMenuPanel = new JPanel(); + fontMenuPanel.setLayout(new GridLayout()); + fontMenuPanel.add(fontMenu); + addFontMenuToGBL(FAMILY_LABEL_TEXT, fontMenuPanel, gbl, gbc, 2, this ); + + stylePanel = new JPanel(); + stylePanel.setLayout(new GridLayout()); + stylePanel.add(styleMenu); + addStyleMenuToGBL(STYLE_LABEL_TEXT, stylePanel, gbl, gbc, 40, this ); + gbc.gridwidth = GridBagConstraints.REMAINDER; addLabeledComponentToGBL( "Font Transform:", - transformMenu, gbl, gbc, this ); + transformMenu, gbl, gbc, 20, this ); gbc.gridwidth = 1; - addLabeledComponentToGBL( "Range: ", rm, gbl, gbc, this ); - addLabeledComponentToGBL( "Style: ", styleMenu, gbl, gbc, this ); + addLabeledComponentToGBL( "Range: ", rm, gbl, gbc, 2, this ); + addLabeledComponentToGBL( "Size: ", sizeField, gbl, gbc, 40, this ); gbc.gridwidth = GridBagConstraints.REMAINDER; addLabeledComponentToGBL( "Graphics Transform: ", - transformMenuG2, gbl, gbc, this ); + transformMenuG2, gbl, gbc, 20, this ); gbc.gridwidth = 1; gbc.anchor = GridBagConstraints.WEST; - addLabeledComponentToGBL( "Method: ", methodsMenu, gbl, gbc, this ); - addLabeledComponentToGBL("", null, gbl, gbc, this); + addLabeledComponentToGBL( "Method: ", methodsMenu, gbl, gbc, 2, this ); + addLabeledComponentToGBL("", null, gbl, gbc, 40, this); gbc.anchor = GridBagConstraints.EAST; + gbc.gridwidth = GridBagConstraints.REMAINDER; - addLabeledComponentToGBL( "Text to use:", textMenu, gbl, gbc, this ); + addLabeledComponentToGBL( "Text to use:", textMenu, gbl, gbc, 20, this ); - gbc.weightx=1; gbc.gridwidth = 1; - gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.WEST; addLabeledComponentToGBL("LCD contrast: ", - contrastSlider, gbl, gbc, this); + contrastSlider, gbl, gbc, 2, this); gbc.gridwidth = 1; - gbc.fill = GridBagConstraints.NONE; addLabeledComponentToGBL("Antialiasing: ", - antiAliasMenu, gbl, gbc, this); + antiAliasMenu, gbl, gbc, 40, this); gbc.anchor = GridBagConstraints.EAST; gbc.gridwidth = GridBagConstraints.REMAINDER; addLabeledComponentToGBL("Fractional metrics: ", - fracMetricsMenu, gbl, gbc, this); + fracMetricsMenu, gbl, gbc, 20, this); gbc.weightx = 1; gbc.weighty = 1; @@ -241,16 +298,23 @@ private void addLabeledComponentToGBL( String name, JComponent c, GridBagLayout gbl, GridBagConstraints gbc, + int leftInset, Container target ) { LabelV2 l = new LabelV2( name ); + l.setLabelFor(c); GridBagConstraints gbcLabel = (GridBagConstraints) gbc.clone(); - gbcLabel.insets = new Insets( 2, 2, 2, 0 ); + if (gbcLabel.gridwidth == GridBagConstraints.REMAINDER) { + gbcLabel.gridwidth = GridBagConstraints.RELATIVE; + } + + gbcLabel.insets = new Insets( 2, leftInset, 2, 0 ); gbcLabel.gridwidth = 1; gbcLabel.weightx = 0; if ( c == null ) c = new JLabel( "" ); + gbcLabel.anchor = GridBagConstraints.EAST; gbl.setConstraints( l, gbcLabel ); target.add( l ); gbl.setConstraints( c, gbc ); @@ -277,6 +341,21 @@ private void setupMenu() { optionMenu.add( displayGridCBMI ); optionMenu.add( force16ColsCBMI ); optionMenu.add( showFontInfoCBMI ); + optionMenu.addSeparator(); + familyAndStyleRBMI = new JRadioButtonMenuItem("Select font using Family Name and Style"); + familyAndStyleRBMI.addActionListener(this); + familyAndSubFamilyRBMI = new JRadioButtonMenuItem("Select font using Family Name and SubFamily"); + familyAndSubFamilyRBMI.addActionListener(this); + fontNameRBMI = new JRadioButtonMenuItem("Select font using Full Name"); + fontNameRBMI.addActionListener(this); + ButtonGroup bg = new ButtonGroup(); + bg.add(familyAndStyleRBMI); + bg.add(familyAndSubFamilyRBMI); + bg.add(fontNameRBMI); + familyAndStyleRBMI.setSelected(true); + optionMenu.add(familyAndStyleRBMI); + optionMenu.add(familyAndSubFamilyRBMI); + optionMenu.add(fontNameRBMI); JMenuBar mb = parent.getJMenuBar(); if ( mb == null ) @@ -286,12 +365,17 @@ private void setupMenu() { parent.setJMenuBar( mb ); - String[] fontList = - GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); + String[] fontList = getAllFamilyNames(); + for (int i = 0; i < fontList.length; i++ ) { + fontMenu.addItem( fontList[i] ); + } + fontMenu.setSelectedItem("Dialog"); - for ( int i = 0; i < fontList.length; i++ ) - fontMenu.addItem( fontList[i] ); - fontMenu.setSelectedItem( "Dialog" ); + fontList = getAllFontNames(); + for (int i = 0; i < fontList.length; i++ ) { + fontNameMenu.addItem( fontList[i] ); + } + fontNameMenu.setSelectedItem("Dialog"); styleMenu.addItem( "Plain" ); styleMenu.addItem( "Bold" ); @@ -647,6 +731,10 @@ private void writeCurrentOptions( String fileName ) { displayGridCBMI.getState() + "\n" + force16ColsCBMI.getState() + "\n" + showFontInfoCBMI.getState() + "\n" + + fontSelectionType + "\n" + + (String)fontMenu.getSelectedItem() + "\n" + + (String)fontNameMenu.getSelectedItem() + "\n" + + (String)fontSubFamilyMenu.getSelectedItem() + "\n" + rm.getSelectedItem() + "\n" + range[0] + "\n" + range[1] + "\n" + curOptions + tFileName); byte[] toBeWritten = completeOptions.getBytes(UTF_16); @@ -724,6 +812,10 @@ private void loadOptions( String fileName ) { boolean displayGridOpt = Boolean.parseBoolean( perLine.nextToken() ); boolean force16ColsOpt = Boolean.parseBoolean( perLine.nextToken() ); boolean showFontInfoOpt = Boolean.parseBoolean( perLine.nextToken() ); + int fontSelType = Integer.parseInt( perLine.nextToken() ); + String fmItem = perLine.nextToken(); + String fnmItem = perLine.nextToken(); + String fsmItem = perLine.nextToken(); String rangeNameOpt = perLine.nextToken(); int rangeStartOpt = Integer.parseInt( perLine.nextToken() ); int rangeEndOpt = Integer.parseInt( perLine.nextToken() ); @@ -756,7 +848,11 @@ private void loadOptions( String fileName ) { force16ColsCBMI.setState( force16ColsOpt ); showFontInfoCBMI.setState( showFontInfoOpt ); rm.setSelectedRange( rangeNameOpt, rangeStartOpt, rangeEndOpt ); - fontMenu.setSelectedItem( fontNameOpt ); + currentFontName = fontNameOpt; + setFontSelectionType(fontSelType); + fontMenu.setSelectedItem( fmItem ); + fontNameMenu.setSelectedItem( fnmItem ); + fontSubFamilyMenu.setSelectedItem( fsmItem ); sizeField.setText( String.valueOf( fontSizeOpt )); styleMenu.setSelectedIndex( fontStyleOpt ); transformMenu.setSelectedIndex( fontTransformOpt ); @@ -819,6 +915,110 @@ public void windowClosing( WindowEvent e ) { } } + static final int FAMILY_AND_STYLE = 1; + static final int FONT_NAME = 2; + static final int FAMILY_AND_SUBFAMILY = 3; + static int fontSelectionType = FAMILY_AND_STYLE; + + static final String FAMILY_LABEL_TEXT = "Font Family:"; + static final String NAME_LABEL_TEXT = "Font Name:"; + static final String STYLE_LABEL_TEXT = "Style:"; + static final String SUBFAMILY_LABEL_TEXT = "Subfamily:"; + + void setUseFamilyAndStyle() { + if (fontSelectionType == FAMILY_AND_STYLE) { + return; + } + fontMenuLabel.setText(FAMILY_LABEL_TEXT); + fontMenuPanel.removeAll(); + fontMenuPanel.add(fontMenu); + if (fontSelectionType == FAMILY_AND_SUBFAMILY) { + styleLabel.setText(STYLE_LABEL_TEXT); + stylePanel.removeAll(); + stylePanel.add(styleMenu); + } + fontSelectionType = FAMILY_AND_STYLE; + if (!familyAndStyleRBMI.isSelected()) { + familyAndStyleRBMI.setSelected(true); + } + styleMenu.setSelectedIndex(0); + currentFontName = (String)fontMenu.getSelectedItem(); + fp.setFontParams(currentFontName, + Float.parseFloat(sizeField.getText()), + 0, // want to reset style to PLAIN + transformMenu.getSelectedIndex()); + revalidate(); + repaint(); + } + + void setUseFontName() { + if (fontSelectionType == FONT_NAME) { + return; + } + fontMenuLabel.setText(NAME_LABEL_TEXT); + fontMenuPanel.removeAll(); + fontMenuPanel.add(fontNameMenu); + if (fontSelectionType == FAMILY_AND_SUBFAMILY) { + styleLabel.setText(STYLE_LABEL_TEXT); + stylePanel.removeAll(); + stylePanel.add(styleMenu); + } + fontSelectionType = FONT_NAME; + if (!fontNameRBMI.isSelected()) { + fontNameRBMI.setSelected(true); + } + styleMenu.setSelectedIndex(0); + currentFontName = (String)fontNameMenu.getSelectedItem(); + fp.setFontParams(currentFontName, + Float.parseFloat(sizeField.getText()), + 0, // want to reset style to PLAIN + transformMenu.getSelectedIndex()); + revalidate(); + repaint(); + } + + void setUseFamilyAndSubFamily() { + if (fontSelectionType == FAMILY_AND_SUBFAMILY) { + return; + } + fontMenuLabel.setText(FAMILY_LABEL_TEXT); + fontMenuPanel.removeAll(); + fontMenuPanel.add(fontMenu); + styleLabel.setText(SUBFAMILY_LABEL_TEXT); + stylePanel.removeAll(); + styleMenu.setSelectedIndex(0); + String family = (String)fontMenu.getSelectedItem(); + updateSubFamilyMenu(family); + stylePanel.add(fontSubFamilyMenu); + fontSelectionType = FAMILY_AND_SUBFAMILY; + if (!familyAndSubFamilyRBMI.isSelected()) { + familyAndSubFamilyRBMI.setSelected(true); + } + String subname = (String)fontSubFamilyMenu.getSelectedItem(); + Font font = FontFamily.getFont(family, subname); + currentFontName = (font != null) ? font.getFontName(l) : family; + fp.setFontParams(currentFontName, + Float.parseFloat(sizeField.getText()), + 0, // want to reset style to PLAIN + transformMenu.getSelectedIndex()); + revalidate(); + repaint(); + } + + void setFontSelectionType(int fsType) { + switch (fsType) { + case FAMILY_AND_STYLE : + setUseFamilyAndStyle(); + break; + case FONT_NAME : + setUseFontName(); + break; + case FAMILY_AND_SUBFAMILY : + setUseFamilyAndSubFamily(); + break; + } + } + /// Interface functions... /// ActionListener interface function @@ -830,7 +1030,14 @@ public void actionPerformed( ActionEvent e ) { JMenuItem mi = (JMenuItem) source; String itemName = mi.getText(); - if ( itemName.equals( "Save Selected Options..." )) { + if (source == familyAndStyleRBMI) { + setUseFamilyAndStyle(); + } else if (source == familyAndSubFamilyRBMI) { + setUseFamilyAndSubFamily(); + } else if (source == fontNameRBMI) { + setUseFontName(); + } + else if ( itemName.equals( "Save Selected Options..." )) { String fileName = promptFile( true, "options.txt" ); if ( fileName != null ) writeCurrentOptions( fileName ); @@ -872,11 +1079,12 @@ else if ( source instanceof JTextField ) { } catch (Exception se) { sizeField.setText("12"); } - if ( tf == sizeField ) - fp.setFontParams( fontMenu.getSelectedItem(), + if ( tf == sizeField ) { + fp.setFontParams(currentFontName, sz, styleMenu.getSelectedIndex(), transformMenu.getSelectedIndex() ); + } } else if ( source instanceof JButton ) { @@ -901,7 +1109,41 @@ else if ( source instanceof JComboBox ) { /// RangeMenu handles actions by itself and then calls fireRangeChanged, /// so it is not listed or handled here - if ( c == fontMenu || c == styleMenu || c == transformMenu ) { + if ( c == fontMenu || c == fontNameMenu || c == fontSubFamilyMenu || + c == styleMenu || c == transformMenu ) + { + if (c == fontNameMenu) { + currentFontName = (String)fontNameMenu.getSelectedItem(); + } + else if ((c == fontMenu) && (fontSelectionType == FAMILY_AND_STYLE)) { + currentFontName = (String)fontMenu.getSelectedItem(); + } + else if ((c == fontMenu) && (fontSelectionType == FAMILY_AND_SUBFAMILY)) { + String family = (String)fontMenu.getSelectedItem(); + updateSubFamilyMenu(family); + String subname = (String)fontSubFamilyMenu.getSelectedItem(); + Font font = FontFamily.getFont(family, subname); + if (font == null) return; + currentFontName = font.getFontName(l); + } + else if (c == fontSubFamilyMenu) { + /* + * When switching families, all items are removed from the sub family list. + * This triggers a synchronous recursive ActionEvent on the EDT, which should + * be ignored here, the code removes them adds the new items and will then + * use the new default selected item. + * If we do not return, we'll not find a match and can get an NPE. + * This feels unsatisfactory, but it works. + */ + if (fontSubFamilyMenu.getItemCount() == 0) { + return; + } + String family = (String)fontMenu.getSelectedItem(); + String subname = (String)fontSubFamilyMenu.getSelectedItem(); + Font font = FontFamily.getFont(family, subname); + if (font == null) return; + currentFontName = font.getFontName(l); + } float sz = 12f; try { sz = Float.parseFloat(sizeField.getText()); @@ -912,7 +1154,7 @@ else if ( source instanceof JComboBox ) { } catch (Exception se) { sizeField.setText("12"); } - fp.setFontParams(fontMenu.getSelectedItem(), + fp.setFontParams(currentFontName, sz, styleMenu.getSelectedIndex(), transformMenu.getSelectedIndex()); @@ -1008,11 +1250,177 @@ private static void printUsage() { System.exit(0); } + static class FontFamily { + + static Map familyMap = new HashMap<>(); + private static Locale l = Locale.getDefault(); + private List fonts = new ArrayList<>(); + private List subFamilyNames = new ArrayList<>(); + private Map nameToFontMap = new HashMap<>(); + private String familyName; + + private FontFamily(String name) { + this.familyName = name; + } + + String stripFamily(String family, String fullName) { + if (family.equals(fullName)) { + return ""; + } + char[] familyChars = family.toCharArray(); + char[] fullChars = fullName.toCharArray(); + int familyIndex = 0; + int fullIndex = 0; + // there's probably a clever regexp way to do this + // iterate over the chars in the family , if they are the same + // keep going, if there's a '-' or ' ', skip it. In the font name, + // do the same. If you reach the end of the family without some + // other diff, return what's left of the fullName. + while (familyIndex < familyChars.length && fullIndex < fullChars.length) { + //while (familyIndex < familyChars.length) { + if (fullIndex == fullChars.length) { + System.err.println("WEIRD FONT " + family + " " + fullName); + break; + } + if (familyChars[familyIndex] == fullChars[fullIndex]) { + familyIndex++; fullIndex++; + } + else if (familyChars[familyIndex] == ' ' && fullChars[fullIndex] == '-') { + familyIndex++; fullIndex++; + } + else if (familyChars[familyIndex] == '-' && fullChars[fullIndex] == ' ') { + familyIndex++; fullIndex++; + } + else if (familyChars[familyIndex] == ' ' || familyChars[familyIndex] == '-') { + familyIndex++; + } + else if (fullChars[fullIndex] == ' ' || fullChars[fullIndex] == '-') { + fullIndex++; + } else { + break; + } + } + if (fullIndex == fullChars.length) { + return fullName; + } else { + return fullName.substring(fullIndex); + } + } + + /* + * Getting the string to display here can be an art. + * If the family is "Arial Black", then for a regular font, the + * full name may be "Arial Black", or "Arial-Black", as reported on macOS. + * For this case for the specific font might want to display the + * full name, or synthesise "Regular". But to do that we have to + * recognise that ' ' to '-' mapping. + * For "Arial Black Italic" (Arial-Black-Italic) we want to be able to + * trim so we display just "Italic". + * Then we need to be able to map the text selection back to the + * right font. + */ + void add(Font f) { + String fontName = f.getFontName(l); + int flen = familyName.length(); + int nlen = fontName.length(); + String sfn; + + if (fontName.equals(familyName)) { + sfn = "Regular"; + } + else { + sfn = stripFamily(familyName, fontName); + sfn = sfn.replace('-', ' '); + } + + fonts.add(f); + subFamilyNames.add(sfn); + nameToFontMap.put(sfn, f); + } + + String[] getSubFamilyNames() { + return subFamilyNames.stream().sorted().toArray(String[]::new); + } + + + Font getFontForSubFamilyName(String name) { + return nameToFontMap.get(name); + } + + static FontFamily getFontFamily(String name) { + return familyMap.get(name); + } + + static FontFamily createFontFamily(String name) { + FontFamily f = familyMap.get(name); + if (f == null) { + f = new FontFamily(name); + familyMap.put(name, f); + } + return f; + } + + /* + * familyName must be a name of an existing FontFamily + * name, must be a valid "subFamilyName" within that FontFamily + * as returned by getSubFamilyNames() + */ + static Font getFont(String familyName, String subFamilyName) { + FontFamily family = getFontFamily(familyName); + return family.getFontForSubFamilyName(subFamilyName); + } + } + + static String[] familyNames; + static Font[] allFonts; + static List allFontNames; + static Map familyMap = new HashMap<>(); + + private static void buildFontInfo() { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + familyNames = ge.getAvailableFontFamilyNames(); + allFonts = ge.getAllFonts(); + allFontNames = new ArrayList(); + Locale l = Locale.getDefault(); + for (Font f : allFonts) { + allFontNames.add(f.getFontName(l)); + String family = f.getFamily(l); + FontFamily ff = FontFamily.getFontFamily(family); + if (ff == null) { + ff = FontFamily.createFontFamily(family); + } + ff.add(f); + } + } + + String getFontNameFor(String family, String subFamily) { + return family + " " + subFamily; + } + + void updateSubFamilyMenu(String name) { + FontFamily family = FontFamily.getFontFamily(name); + fontSubFamilyMenu.removeAllItems(); + + String [] sfNames = family.getSubFamilyNames(); + for (int i=0; i 0) { - if(argv[0].equalsIgnoreCase("-disablecandisplaycheck") || + if (argv.length > 0) { + if (argv[0].equalsIgnoreCase("-disablecandisplaycheck") || argv[0].equalsIgnoreCase("-dcdc")) { canDisplayCheck = false; } @@ -1021,17 +1429,23 @@ public static void main(String[] argv) { } } - UIManager.put("swing.boldMetal", Boolean.FALSE); - final JFrame f = new JFrame( "Font2DTest" ); - final Font2DTest f2dt = new Font2DTest( f); - f.addWindowListener( new WindowAdapter() { - public void windowOpening( WindowEvent e ) { f2dt.repaint(); } - public void windowClosing( WindowEvent e ) { System.exit(0); } - }); - - f.getContentPane().add( f2dt ); - f.pack(); - f.setVisible(true); + buildFontInfo(); + try { + UIManager.setLookAndFeel(new NimbusLookAndFeel()); + SwingUtilities.invokeAndWait(() -> { + final JFrame f = new JFrame( "Font2DTest" ); + final Font2DTest f2dt = new Font2DTest( f); + f.addWindowListener( new WindowAdapter() { + public void windowOpening( WindowEvent e ) { f2dt.repaint(); } + public void windowClosing( WindowEvent e ) { System.exit(0); } + }); + + f.getContentPane().add( f2dt ); + f.pack(); + f.setVisible(true); + }); + } catch (UnsupportedLookAndFeelException|InterruptedException|InvocationTargetException e) { + } } /// Inner class definitions... diff --git a/src/demo/share/jfc/Font2DTest/FontPanel.java b/src/demo/share/jfc/Font2DTest/FontPanel.java index d52f572e090..70b1390fd76 100644 --- a/src/demo/share/jfc/Font2DTest/FontPanel.java +++ b/src/demo/share/jfc/Font2DTest/FontPanel.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. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -740,7 +740,8 @@ private void resetScrollbar( int oldValue ) { verticalBar.setValues( oldValue, numCharDown, 0, totalNumRows ); } if ( totalNumRows <= numCharDown && drawStart == 0) { - verticalBar.setEnabled( false ); + // the disabled scroll bar looks odd with Nimbus L&F. + verticalBar.setEnabled( true ); } else { verticalBar.setEnabled( true ); From 08d51003d142e89b9d2f66187a4ea50e12b94fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Mon, 27 May 2024 05:23:26 +0000 Subject: [PATCH 45/99] 8332724: x86 MacroAssembler may over-align code Reviewed-by: dlong, kvn --- src/hotspot/cpu/x86/assembler_x86.cpp | 2 +- src/hotspot/cpu/x86/assembler_x86.hpp | 2 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 10 +++++----- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index ee9e2064941..b02cca92cd4 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -3918,7 +3918,7 @@ void Assembler::negl(Address dst) { emit_operand(as_Register(3), dst, 0); } -void Assembler::nop(int i) { +void Assembler::nop(uint i) { #ifdef ASSERT assert(i > 0, " "); // The fancy nops aren't currently recognized by debuggers making it a diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 32a81519f82..41a63924828 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1800,7 +1800,7 @@ class Assembler : public AbstractAssembler { void negq(Address dst); #endif - void nop(int i = 1); + void nop(uint i = 1); void notl(Register dst); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index d20f34e27b8..01372f0c53a 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1150,20 +1150,20 @@ void MacroAssembler::addpd(XMMRegister dst, AddressLiteral src, Register rscratc // Stub code is generated once and never copied. // NMethods can't use this because they get copied and we can't force alignment > 32 bytes. void MacroAssembler::align64() { - align(64, (unsigned long long) pc()); + align(64, (uint)(uintptr_t)pc()); } void MacroAssembler::align32() { - align(32, (unsigned long long) pc()); + align(32, (uint)(uintptr_t)pc()); } -void MacroAssembler::align(int modulus) { +void MacroAssembler::align(uint modulus) { // 8273459: Ensure alignment is possible with current segment alignment - assert(modulus <= CodeEntryAlignment, "Alignment must be <= CodeEntryAlignment"); + assert(modulus <= (uintx)CodeEntryAlignment, "Alignment must be <= CodeEntryAlignment"); align(modulus, offset()); } -void MacroAssembler::align(int modulus, int target) { +void MacroAssembler::align(uint modulus, uint target) { if (target % modulus != 0) { nop(modulus - (target % modulus)); } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index c69c8c0d447..b9f14da3db6 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -213,8 +213,8 @@ class MacroAssembler: public Assembler { // Alignment void align32(); void align64(); - void align(int modulus); - void align(int modulus, int target); + void align(uint modulus); + void align(uint modulus, uint target); void post_call_nop(); // A 5 byte nop that is safe for patching (see patch_verified_entry) From 4e8deb396e38c69de22b6348dca637d814d73aef Mon Sep 17 00:00:00 2001 From: SendaoYan Date: Mon, 27 May 2024 06:32:21 +0000 Subject: [PATCH 46/99] 8332922: Test java/io/IO/IO.java fails when /usr/bin/expect not exist Reviewed-by: djelinski --- test/jdk/java/io/IO/IO.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/io/IO/IO.java b/test/jdk/java/io/IO/IO.java index 9b35fe1ab81..1a9a25c90c7 100644 --- a/test/jdk/java/io/IO/IO.java +++ b/test/jdk/java/io/IO/IO.java @@ -29,7 +29,7 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; -import jtreg.SkippedException; +import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.condition.EnabledOnOs; @@ -60,7 +60,7 @@ public class OSSpecificTests { public static void prepareTTY() { expect = Paths.get("/usr/bin/expect"); // os-specific path if (!Files.exists(expect) || !Files.isExecutable(expect)) { - throw new SkippedException("'" + expect + "' not found"); + Assumptions.abort("'" + expect + "' not found"); } } From 16dba04e8dfa871f8056480a42a9baeb24a2fb24 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 27 May 2024 06:35:39 +0000 Subject: [PATCH 47/99] 8332589: ubsan: unix/native/libjava/ProcessImpl_md.c:562:5: runtime error: null pointer passed as argument 2, which is declared to never be null Reviewed-by: rriggs, mdoerr --- .../unix/native/libjava/ProcessImpl_md.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/java.base/unix/native/libjava/ProcessImpl_md.c b/src/java.base/unix/native/libjava/ProcessImpl_md.c index 558882f61e1..506b33aae96 100644 --- a/src/java.base/unix/native/libjava/ProcessImpl_md.c +++ b/src/java.base/unix/native/libjava/ProcessImpl_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 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 @@ -559,8 +559,17 @@ spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) } offset = copystrings(buf, 0, &c->argv[0]); offset = copystrings(buf, offset, &c->envv[0]); - memcpy(buf+offset, c->pdir, sp.dirlen); - offset += sp.dirlen; + if (c->pdir != NULL) { + if (sp.dirlen > 0) { + memcpy(buf+offset, c->pdir, sp.dirlen); + offset += sp.dirlen; + } + } else { + if (sp.dirlen > 0) { + free(buf); + return -1; + } + } offset = copystrings(buf, offset, parentPathv); assert(offset == bufsize); From a083364520ab75cb5596f103b2fa51d7f7a8a706 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 27 May 2024 07:11:18 +0000 Subject: [PATCH 48/99] 8321292: SerialGC: NewSize vs InitialHeapSize check has an off-by-one error Reviewed-by: ayang, iwalulya --- src/hotspot/share/gc/shared/genArguments.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/shared/genArguments.cpp b/src/hotspot/share/gc/shared/genArguments.cpp index 3c1d1ac6ec1..3eac2e39f38 100644 --- a/src/hotspot/share/gc/shared/genArguments.cpp +++ b/src/hotspot/share/gc/shared/genArguments.cpp @@ -101,8 +101,11 @@ void GenArguments::initialize_heap_flags_and_sizes() { // Make sure NewSize allows an old generation to fit even if set on the command line if (FLAG_IS_CMDLINE(NewSize) && NewSize >= InitialHeapSize) { - log_warning(gc, ergo)("NewSize was set larger than initial heap size, will use initial heap size."); - FLAG_SET_ERGO(NewSize, bound_minus_alignment(NewSize, InitialHeapSize, GenAlignment)); + size_t revised_new_size = bound_minus_alignment(NewSize, InitialHeapSize, GenAlignment); + log_warning(gc, ergo)("NewSize (%zuk) is equal to or greater than initial heap size (%zuk). A new " + "NewSize of %zuk will be used to accomodate an old generation.", + NewSize/K, InitialHeapSize/K, revised_new_size/K); + FLAG_SET_ERGO(NewSize, revised_new_size); } // Now take the actual NewSize into account. We will silently increase NewSize From 61db2f5b90cd40ce104cb55bf9fd52d6e141161d Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 27 May 2024 07:11:39 +0000 Subject: [PATCH 49/99] 8079167: Fix documentation for G1SATBBufferEnqueueingThresholdPercent == 0 Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1_globals.hpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1_globals.hpp b/src/hotspot/share/gc/g1/g1_globals.hpp index 677d86f5a0c..af1ac1f70c6 100644 --- a/src/hotspot/share/gc/g1/g1_globals.hpp +++ b/src/hotspot/share/gc/g1/g1_globals.hpp @@ -149,12 +149,11 @@ "Number of completed buffers that triggers log processing.") \ range(0, max_jint) \ \ - product(uint, G1SATBBufferEnqueueingThresholdPercent, 60, \ + product(uint, G1SATBBufferEnqueueingThresholdPercent, 60, \ "Before enqueueing them, each mutator thread tries to do some " \ "filtering on the SATB buffers it generates. If post-filtering " \ "the percentage of retained entries is over this threshold " \ - "the buffer will be enqueued for processing. A value of 0 " \ - "specifies that mutator threads should not do such filtering.") \ + "the buffer will be enqueued for processing.") \ range(0, 100) \ \ product(uint, G1ExpandByPercentOfAvailable, 20, EXPERIMENTAL, \ From a3a367ef5d6c462ebca40104d05c11219e84a64f Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 27 May 2024 08:06:24 +0000 Subject: [PATCH 50/99] 8332871: Parallel: Remove public bits APIs in ParMarkBitMap Reviewed-by: tschatzl --- .../share/gc/parallel/parMarkBitMap.hpp | 19 +++++++------------ .../gc/parallel/parMarkBitMap.inline.hpp | 12 +++++------- .../share/gc/parallel/psParallelCompact.cpp | 7 ++----- 3 files changed, 14 insertions(+), 24 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp index 63c4d4e7185..cedf7aca77c 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp @@ -31,8 +31,7 @@ class PSVirtualSpace; -class ParMarkBitMap: public CHeapObj -{ +class ParMarkBitMap: public CHeapObj { public: typedef BitMap::idx_t idx_t; @@ -46,9 +45,6 @@ class ParMarkBitMap: public CHeapObj inline bool mark_obj(HeapWord* addr); inline bool mark_obj(oop obj); - // Traditional interface for testing whether an object is marked or not (these - // test only the begin bits). - inline bool is_marked(idx_t bit) const; inline bool is_marked(HeapWord* addr) const; inline bool is_marked(oop obj) const; @@ -57,18 +53,13 @@ class ParMarkBitMap: public CHeapObj size_t reserved_byte_size() const { return _reserved_byte_size; } - // Convert a heap address to/from a bit index. - inline idx_t addr_to_bit(HeapWord* addr) const; - inline HeapWord* bit_to_addr(idx_t bit) const; - inline HeapWord* find_obj_beg(HeapWord* beg, HeapWord* end) const; // Return the address of the last obj-start in the range [beg, end). If no // object is found, return end. inline HeapWord* find_obj_beg_reverse(HeapWord* beg, HeapWord* end) const; - // Clear a range of bits or the entire bitmap (both begin and end bits are - // cleared). - inline void clear_range(idx_t beg, idx_t end); + // Clear a range of bits corresponding to heap address range [beg, end). + inline void clear_range(HeapWord* beg, HeapWord* end); void print_on_error(outputStream* st) const { st->print_cr("Marking Bits: (ParMarkBitMap*) " PTR_FORMAT, p2i(this)); @@ -111,6 +102,10 @@ class ParMarkBitMap: public CHeapObj inline size_t region_size() const; inline size_t size() const; + // Convert a heap address to/from a bit index. + inline idx_t addr_to_bit(HeapWord* addr) const; + inline HeapWord* bit_to_addr(idx_t bit) const; + #ifdef ASSERT inline void verify_bit(idx_t bit) const; inline void verify_addr(HeapWord* addr) const; diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp index 6d4aba8e36f..07e2289fb0a 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.inline.hpp @@ -34,8 +34,10 @@ inline ParMarkBitMap::ParMarkBitMap(): _region_start(nullptr), _region_size(0), _beg_bits(), _virtual_space(nullptr), _reserved_byte_size(0) { } -inline void ParMarkBitMap::clear_range(idx_t beg, idx_t end) { - _beg_bits.clear_range(beg, end); +inline void ParMarkBitMap::clear_range(HeapWord* beg, HeapWord* end) { + const idx_t beg_bit = addr_to_bit(beg); + const idx_t end_bit = addr_to_bit(end); + _beg_bits.clear_range(beg_bit, end_bit); } inline ParMarkBitMap::idx_t ParMarkBitMap::bits_required(size_t words) { @@ -62,12 +64,8 @@ inline size_t ParMarkBitMap::size() const { return _beg_bits.size(); } -inline bool ParMarkBitMap::is_marked(idx_t bit) const { - return _beg_bits.at(bit); -} - inline bool ParMarkBitMap::is_marked(HeapWord* addr) const { - return is_marked(addr_to_bit(addr)); + return _beg_bits.at(addr_to_bit(addr)); } inline bool ParMarkBitMap::is_marked(oop obj) const { diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index e72fa42e6f6..4256be8870d 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -826,9 +826,7 @@ PSParallelCompact::clear_data_covering_space(SpaceId id) HeapWord* const top = space->top(); HeapWord* const max_top = MAX2(top, _space_info[id].new_top()); - const idx_t beg_bit = _mark_bitmap.addr_to_bit(bot); - const idx_t end_bit = _mark_bitmap.addr_to_bit(top); - _mark_bitmap.clear_range(beg_bit, end_bit); + _mark_bitmap.clear_range(bot, top); const size_t beg_region = _summary_data.addr_to_region_idx(bot); const size_t end_region = @@ -1001,10 +999,9 @@ void PSParallelCompact::fill_dense_prefix_end(SpaceId id) { return; } RegionData* const region_after_dense_prefix = _summary_data.addr_to_region_ptr(dense_prefix_end); - idx_t const dense_prefix_bit = _mark_bitmap.addr_to_bit(dense_prefix_end); if (region_after_dense_prefix->partial_obj_size() != 0 || - _mark_bitmap.is_marked(dense_prefix_bit)) { + _mark_bitmap.is_marked(dense_prefix_end)) { // The region after the dense prefix starts with live bytes. return; } From ffa4badb78118d154e47e41073e467c0e0e4273c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roberto=20Casta=C3=B1eda=20Lozano?= Date: Mon, 27 May 2024 08:42:40 +0000 Subject: [PATCH 51/99] 8332527: ZGC: generalize object cloning logic Reviewed-by: aboldtch, thartmann --- .../share/gc/shared/c2/barrierSetC2.cpp | 50 +++++++++++++++++++ .../share/gc/shared/c2/barrierSetC2.hpp | 2 + src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp | 46 ++--------------- 3 files changed, 56 insertions(+), 42 deletions(-) diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp index 53e4d7fdf8f..59e02452044 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp @@ -814,8 +814,58 @@ Node* BarrierSetC2::obj_allocate(PhaseMacroExpand* macro, Node* mem, Node* toobi return old_tlab_top; } +static const TypeFunc* clone_type() { + // Create input type (domain) + int argcnt = NOT_LP64(3) LP64_ONLY(4); + const Type** const domain_fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + domain_fields[argp++] = TypeInstPtr::NOTNULL; // src + domain_fields[argp++] = TypeInstPtr::NOTNULL; // dst + domain_fields[argp++] = TypeX_X; // size lower + LP64_ONLY(domain_fields[argp++] = Type::HALF); // size upper + assert(argp == TypeFunc::Parms+argcnt, "correct decoding"); + const TypeTuple* const domain = TypeTuple::make(TypeFunc::Parms + argcnt, domain_fields); + + // Create result type (range) + const Type** const range_fields = TypeTuple::fields(0); + const TypeTuple* const range = TypeTuple::make(TypeFunc::Parms + 0, range_fields); + + return TypeFunc::make(domain, range); +} + #define XTOP LP64_ONLY(COMMA phase->top()) +void BarrierSetC2::clone_in_runtime(PhaseMacroExpand* phase, ArrayCopyNode* ac, + address clone_addr, const char* clone_name) const { + Node* const ctrl = ac->in(TypeFunc::Control); + Node* const mem = ac->in(TypeFunc::Memory); + Node* const src = ac->in(ArrayCopyNode::Src); + Node* const dst = ac->in(ArrayCopyNode::Dest); + Node* const size = ac->in(ArrayCopyNode::Length); + + assert(size->bottom_type()->base() == Type_X, + "Should be of object size type (int for 32 bits, long for 64 bits)"); + + // The native clone we are calling here expects the object size in words. + // Add header/offset size to payload size to get object size. + Node* const base_offset = phase->MakeConX(arraycopy_payload_base_offset(ac->is_clone_array()) >> LogBytesPerLong); + Node* const full_size = phase->transform_later(new AddXNode(size, base_offset)); + // HeapAccess<>::clone expects size in heap words. + // For 64-bits platforms, this is a no-operation. + // For 32-bits platforms, we need to multiply full_size by HeapWordsPerLong (2). + Node* const full_size_in_heap_words = phase->transform_later(new LShiftXNode(full_size, phase->intcon(LogHeapWordsPerLong))); + + Node* const call = phase->make_leaf_call(ctrl, + mem, + clone_type(), + clone_addr, + clone_name, + TypeRawPtr::BOTTOM, + src, dst, full_size_in_heap_words XTOP); + phase->transform_later(call); + phase->igvn().replace_node(ac, call); +} + void BarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const { Node* ctrl = ac->in(TypeFunc::Control); Node* mem = ac->in(TypeFunc::Memory); diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp index 8787fe83d14..d03f416ff68 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp @@ -280,6 +280,8 @@ class BarrierSetC2: public CHeapObj { virtual Node* atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* val_type) const; virtual Node* atomic_add_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* val_type) const; void pin_atomic_op(C2AtomicParseAccess& access) const; + void clone_in_runtime(PhaseMacroExpand* phase, ArrayCopyNode* ac, + address call_addr, const char* call_name) const; public: // This is the entry-point for the backend to perform accesses through the Access API. diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp index 4b79b568241..dbec45fd96e 100644 --- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp +++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp @@ -407,23 +407,6 @@ bool ZBarrierSetC2::array_copy_requires_gc_barriers(bool tightly_coupled_alloc, return type == T_OBJECT || type == T_ARRAY; } -// This TypeFunc assumes a 64bit system -static const TypeFunc* clone_type() { - // Create input type (domain) - const Type** const domain_fields = TypeTuple::fields(4); - domain_fields[TypeFunc::Parms + 0] = TypeInstPtr::NOTNULL; // src - domain_fields[TypeFunc::Parms + 1] = TypeInstPtr::NOTNULL; // dst - domain_fields[TypeFunc::Parms + 2] = TypeLong::LONG; // size lower - domain_fields[TypeFunc::Parms + 3] = Type::HALF; // size upper - const TypeTuple* const domain = TypeTuple::make(TypeFunc::Parms + 4, domain_fields); - - // Create result type (range) - const Type** const range_fields = TypeTuple::fields(0); - const TypeTuple* const range = TypeTuple::make(TypeFunc::Parms + 0, range_fields); - - return TypeFunc::make(domain, range); -} - #define XTOP LP64_ONLY(COMMA phase->top()) void ZBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const { @@ -479,31 +462,10 @@ void ZBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* a return; } - // Clone instance - Node* const ctrl = ac->in(TypeFunc::Control); - Node* const mem = ac->in(TypeFunc::Memory); - Node* const dst = ac->in(ArrayCopyNode::Dest); - Node* const size = ac->in(ArrayCopyNode::Length); - - assert(size->bottom_type()->is_long(), "Should be long"); - - // The native clone we are calling here expects the instance size in words - // Add header/offset size to payload size to get instance size. - Node* const base_offset = phase->longcon(arraycopy_payload_base_offset(ac->is_clone_array()) >> LogBytesPerLong); - Node* const full_size = phase->transform_later(new AddLNode(size, base_offset)); - - Node* const call = phase->make_leaf_call(ctrl, - mem, - clone_type(), - ZBarrierSetRuntime::clone_addr(), - "ZBarrierSetRuntime::clone", - TypeRawPtr::BOTTOM, - src, - dst, - full_size, - phase->top()); - phase->transform_later(call); - phase->igvn().replace_node(ac, call); + // Clone instance or array where 'src' is only known to be an object (ary_ptr + // is null). This can happen in bytecode generated dynamically to implement + // reflective array clones. + clone_in_runtime(phase, ac, ZBarrierSetRuntime::clone_addr(), "ZBarrierSetRuntime::clone"); } #undef XTOP From 617edf3f0dea2b73e4b444e085de2ad282826e31 Mon Sep 17 00:00:00 2001 From: Evemose Date: Mon, 27 May 2024 08:54:20 +0000 Subject: [PATCH 52/99] 8332497: javac prints an AssertionError when annotation processing runs on program with module imports Reviewed-by: liach, vromero, jlahoda --- .../com/sun/tools/javac/tree/TreeScanner.java | 5 + .../sun/tools/javac/tree/TreeTranslator.java | 5 + .../ModuleImportProcessingTest.java | 103 ++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 test/langtools/tools/javac/processing/ModuleImportProcessingTest.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java index fc356047542..0336f3c4191 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java @@ -85,6 +85,11 @@ public void visitExports(JCExports tree) { scan(tree.moduleNames); } + @Override + public void visitModuleImport(JCModuleImport tree) { + scan(tree.module); + } + @Override public void visitOpens(JCOpens tree) { scan(tree.qualid); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java index 59a7457e6d0..63778fb42ff 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java @@ -131,6 +131,11 @@ public void visitImport(JCImport tree) { result = tree; } + public void visitModuleImport(JCModuleImport tree) { + tree.module = translate(tree.module); + result = tree; + } + public void visitClassDef(JCClassDecl tree) { tree.mods = translate(tree.mods); tree.typarams = translateTypeParams(tree.typarams); diff --git a/test/langtools/tools/javac/processing/ModuleImportProcessingTest.java b/test/langtools/tools/javac/processing/ModuleImportProcessingTest.java new file mode 100644 index 00000000000..71f65ca9641 --- /dev/null +++ b/test/langtools/tools/javac/processing/ModuleImportProcessingTest.java @@ -0,0 +1,103 @@ +/* + * 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 8332497 + * @summary error: javac prints an AssertionError when annotation processing runs on program with module imports + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.JavacTask toolbox.ToolBox toolbox.Task + * @run main ModuleImportProcessingTest + */ + +import toolbox.*; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; +import java.nio.file.Path; +import java.util.Set; + + +public class ModuleImportProcessingTest extends TestRunner { + final toolbox.ToolBox tb = new ToolBox(); + final String processedSource = """ + import module java.base; + import java.lang.annotation.*; + public class Main { + public static void main(String[] args) { + List.of(); + } + @Ann + private void test() {} + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + public @interface Ann {} + } + """; + + public ModuleImportProcessingTest() { + super(System.err); + } + + public static void main(String[] args) throws Exception { + new ModuleImportProcessingTest().runTests(); + } + + protected void runTests() throws Exception { + runTests(m -> new Object[] { Path.of(m.getName()) }); + } + + @Test + public void test(Path base) throws Exception { + tb.writeJavaFiles(base, processedSource); + new toolbox.JavacTask(tb) + .options( + "-processor", AP.class.getName(), + "--enable-preview", + "-source", Integer.toString(Runtime.version().feature()), + "-proc:only" + ) + .files(tb.findJavaFiles(base)) + .run(); + } + + @SupportedAnnotationTypes("*") + public static final class AP extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + } +} \ No newline at end of file From 7f0ad513c30359816ac840f821ca0a22d723a642 Mon Sep 17 00:00:00 2001 From: Ludvig Janiuk Date: Mon, 27 May 2024 09:35:52 +0000 Subject: [PATCH 53/99] 8332898: failure_handler: log directory of commands Reviewed-by: lmesnik --- .../classes/jdk/test/failurehandler/action/ActionHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java index 2f26654927d..76d4e8c1c71 100644 --- a/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java +++ b/test/failure_handler/src/share/classes/jdk/test/failurehandler/action/ActionHelper.java @@ -164,7 +164,7 @@ private ExitCode run(HtmlSection section, PrintWriter log, Writer out, ProcessBu Stopwatch stopwatch = new Stopwatch(); stopwatch.start(); - log.printf("%s%n[%tF % Date: Mon, 27 May 2024 09:43:31 +0000 Subject: [PATCH 54/99] 8332885: Clarify failure_handler self-tests Reviewed-by: lmesnik --- make/test/BuildFailureHandler.gmk | 4 ++++ test/failure_handler/README | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/make/test/BuildFailureHandler.gmk b/make/test/BuildFailureHandler.gmk index 005cbb330f6..e8f49e76b32 100644 --- a/make/test/BuildFailureHandler.gmk +++ b/make/test/BuildFailureHandler.gmk @@ -81,6 +81,10 @@ IMAGES_TARGETS += $(COPY_FH) # Use JTREG_TEST_OPTS for test VM options # Use JTREG_TESTS for jtreg tests parameter # +# Most likely you want to select a specific test from test/failure_handler/test +# and manually inspect the results. This target does not actually verify +# anything about the failure_handler's output or even if it ran at all. +# RUN_DIR := $(FH_SUPPORT)/test test: diff --git a/test/failure_handler/README b/test/failure_handler/README index a03136ae3aa..f629a1fbc91 100644 --- a/test/failure_handler/README +++ b/test/failure_handler/README @@ -102,3 +102,15 @@ $ ${JTREG_HOME}/bin/jtreg -jdk:${JAVA_HOME} \ -timeoutHandler:jdk.test.failurehandler.jtreg.GatherProcessInfoTimeoutHandler\ -observer:jdk.test.failurehandler.jtreg.GatherDiagnosticInfoObserver \ ${WS}/hotspot/test/ + +TESTING + +There are a few make targets for testing the failure_handler itself. + - Everything in `test/failure_handler/Makefile` + - The `test-failure-handler` target in `make/RunTests.gmk` + - The `test` target in `make/test/BuildFailureHandler.gmk` +All of these targets are written for manual testing only. They rely on +manual inspection of generated artifacts and cannot be run as part of a CI. +They are tests which timeout, crash, fail in various ways and you can check +the failure_handler output yourself. They might also leave processes running +on your machine so be extra careful about cleaning up. From 72fbfe18cb20274bab2057f3d67920e0c86c5793 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 27 May 2024 09:48:49 +0000 Subject: [PATCH 55/99] 8330577: G1 sometimes sends jdk.G1HeapRegionTypeChange for non-changes Co-authored-by: Andreas Steiner Reviewed-by: ayang, asteiner --- src/hotspot/share/gc/g1/g1HeapRegion.cpp | 7 +- ...estG1InvalidHeapRegionTypeChangeEvent.java | 107 ++++++++++++++++++ 2 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 test/jdk/jdk/jfr/event/gc/detailed/TestG1InvalidHeapRegionTypeChangeEvent.java diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index 895eba6500f..94382a3b256 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -150,7 +150,9 @@ double G1HeapRegion::calc_gc_efficiency() { } void G1HeapRegion::set_free() { - report_region_type_change(G1HeapRegionTraceType::Free); + if (!is_free()) { + report_region_type_change(G1HeapRegionTraceType::Free); + } _type.set_free(); } @@ -170,8 +172,9 @@ void G1HeapRegion::set_survivor() { } void G1HeapRegion::move_to_old() { + G1HeapRegionTraceType::Type prev_trace_type = _type.get_trace_type(); if (_type.relabel_as_old()) { - report_region_type_change(G1HeapRegionTraceType::Old); + report_region_type_change(prev_trace_type); } } diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestG1InvalidHeapRegionTypeChangeEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestG1InvalidHeapRegionTypeChangeEvent.java new file mode 100644 index 00000000000..023020f2a29 --- /dev/null +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestG1InvalidHeapRegionTypeChangeEvent.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.event.gc.detailed; + +import java.nio.file.Paths; +import java.time.Duration; +import java.util.List; + +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; +import jdk.test.lib.jfr.Events; +import jdk.test.lib.jfr.GCHelper; + +/** + * @test + * @bug 8330577 + * @requires vm.hasJFR + * @requires vm.gc == "G1" | vm.gc == null + * @requires vm.debug + * @key jfr + * @library /test/lib /test/jdk + * @summary Make sure that there are no Old->Old and Free->Free events sent. + * @run main/othervm -XX:+G1GCAllocationFailureALot -XX:NewSize=2m -XX:MaxNewSize=2m -XX:MaxTenuringThreshold=1 + * -Xmx32m -XX:G1HeapRegionSize=1m -XX:+UseG1GC -Xlog:gc jdk.jfr.event.gc.detailed.TestG1InvalidHeapRegionTypeChangeEvent + */ + +public class TestG1InvalidHeapRegionTypeChangeEvent { + private final static String EVENT_NAME = EventNames.G1HeapRegionTypeChange; + + public static void main(String[] args) throws Exception { + Recording recording = null; + try { + recording = new Recording(); + // activate the event we are interested in and start recording + recording.enable(EVENT_NAME).withThreshold(Duration.ofMillis(0)); + recording.start(); + + // Compact the heap, creating some Old regions. Previously this sent + // Free->Free transitions too. + System.gc(); + + // Setting NewSize and MaxNewSize will limit eden, so + // allocating 1024 20k byte arrays should trigger at + // least a few Young GCs. + // This fragments the heap a little (together with + // G1GCAllocationFailureALot), so that the next Full GC + // will generate Free -> Old transitions that were incorrectly + // sent as Old -> Old. + // Note that an Old -> Old transition is actually valid in case + // of evacuation failure in an old region, but this is no + // change of region and should not be sent either. + + byte[][] array = new byte[1024][]; + for (int i = 0; i < array.length; i++) { + array[i] = new byte[20 * 1024]; + } + + System.gc(); + recording.stop(); + + // Verify recording + List events = Events.fromRecording(recording); + Asserts.assertFalse(events.isEmpty(), "No events found"); + + for (RecordedEvent event : events) { + Events.assertField(event, "index").notEqual(-1); + Asserts.assertTrue(GCHelper.isValidG1HeapRegionType(Events.assertField(event, "from").getValue())); + Asserts.assertTrue(GCHelper.isValidG1HeapRegionType(Events.assertField(event, "to").getValue())); + Events.assertField(event, "used").atMost(1L*1024*1024); + // There should be no Old->Old and Free->Free "changes". + Asserts.assertFalse(Events.assertField(event, "from").getValue().equals("Old") && Events.assertField(event, "to").getValue().equals("Old")); + Asserts.assertFalse(Events.assertField(event, "from").getValue().equals("Free") && Events.assertField(event, "to").getValue().equals("Free")); + } + } catch (Throwable t) { + if (recording != null) { + recording.dump(Paths.get("TestG1HeapRegionTypeChangeEvent.jfr")); + } + throw t; + } finally { + if (recording != null) { + recording.close(); + } + } + } +} From 0e7ea390bb523888533265394a642071aba0c0c1 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 27 May 2024 10:25:38 +0000 Subject: [PATCH 56/99] 8332678: Serial: Remove use of should_clear_all_soft_refs in serial folder Reviewed-by: iwalulya --- src/hotspot/share/gc/serial/serialFullGC.cpp | 5 ----- src/hotspot/share/gc/serial/serialHeap.cpp | 3 --- 2 files changed, 8 deletions(-) diff --git a/src/hotspot/share/gc/serial/serialFullGC.cpp b/src/hotspot/share/gc/serial/serialFullGC.cpp index 6ebbfc3d6e6..897437e33c9 100644 --- a/src/hotspot/share/gc/serial/serialFullGC.cpp +++ b/src/hotspot/share/gc/serial/serialFullGC.cpp @@ -685,11 +685,6 @@ void SerialFullGC::invoke_at_safepoint(bool clear_all_softrefs) { assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); SerialHeap* gch = SerialHeap::heap(); -#ifdef ASSERT - if (gch->soft_ref_policy()->should_clear_all_soft_refs()) { - assert(clear_all_softrefs, "Policy should have been checked earlier"); - } -#endif gch->trace_heap_before_gc(_gc_tracer); diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index f34ed6cc29a..f4e9e5c6f2e 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -559,9 +559,6 @@ HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) { return result; } - assert(!soft_ref_policy()->should_clear_all_soft_refs(), - "Flag should have been handled and cleared prior to this point"); - // What else? We might try synchronous finalization later. If the total // space available is large enough for the allocation, then a more // complete compaction phase than we've tried so far might be From 1b8dea4a9288c1518dc501a58d806c7365ea68b3 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 27 May 2024 10:27:41 +0000 Subject: [PATCH 57/99] 8332894: ubsan: vmError.cpp:2090:26: runtime error: division by zero Reviewed-by: dholmes, stuefe --- src/hotspot/share/utilities/vmError.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 156a0fd2ec6..656fe9403fe 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -2082,8 +2082,13 @@ bool VMError::check_timeout() { #ifdef ASSERT typedef void (*voidfun_t)(); -// Crash with an authentic sigfpe +// Crash with an authentic sigfpe; behavior is subtly different from a real signal +// compared to one generated with raise (asynchronous vs synchronous). See JDK-8065895. volatile int sigfpe_int = 0; + +#if defined(__clang__) || defined(__GNUC__) +__attribute__((no_sanitize("undefined"))) +#endif static void ALWAYSINLINE crash_with_sigfpe() { // generate a native synchronous SIGFPE where possible; From f3d6fbf52eac44734695935f73c5cfc0fb9ba167 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 27 May 2024 11:20:10 +0000 Subject: [PATCH 58/99] 8330847: G1 accesses uninitialized memory when predicting eden copy time Reviewed-by: iwalulya, ayang --- src/hotspot/share/gc/g1/g1SurvRateGroup.cpp | 22 ++++++++++++++++----- src/hotspot/share/gc/g1/g1SurvRateGroup.hpp | 13 ++++-------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp index 15fc42d80fd..52e4033fd43 100644 --- a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp +++ b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1HeapRegion.hpp" #include "gc/g1/g1Predictions.hpp" #include "gc/g1/g1SurvRateGroup.hpp" @@ -57,10 +56,6 @@ void G1SurvRateGroup::reset() { // Seed initial _surv_rate_pred and _accum_surv_rate_pred values guarantee(_stats_arrays_length == 1, "invariant" ); - guarantee(_surv_rate_predictors[0] != nullptr, "invariant" ); - const double initial_surv_rate = 0.4; - _surv_rate_predictors[0]->add(initial_surv_rate); - _last_pred = _accum_surv_rate_pred[0] = initial_surv_rate; _num_added_regions = 0; } @@ -75,8 +70,12 @@ void G1SurvRateGroup::stop_adding_regions() { _surv_rate_predictors = REALLOC_C_HEAP_ARRAY(TruncatedSeq*, _surv_rate_predictors, _num_added_regions, mtGC); for (size_t i = _stats_arrays_length; i < _num_added_regions; ++i) { + // Initialize predictors and accumulated survivor rate predictions. _surv_rate_predictors[i] = new TruncatedSeq(10); + _surv_rate_predictors[i]->add(InitialSurvivorRate); + _accum_surv_rate_pred[i] = ((i == 0) ? 0.0 : _accum_surv_rate_pred[i-1]) + InitialSurvivorRate; } + _last_pred = InitialSurvivorRate; _stats_arrays_length = _num_added_regions; } @@ -96,6 +95,19 @@ void G1SurvRateGroup::all_surviving_words_recorded(const G1Predictions& predicto finalize_predictions(predictor); } +double G1SurvRateGroup::accum_surv_rate_pred(uint age) const { + assert(_stats_arrays_length > 0, "invariant" ); + double result; + if (age < _stats_arrays_length) { + result = _accum_surv_rate_pred[age]; + } else { + double diff = (double)(age - _stats_arrays_length + 1); + result = _accum_surv_rate_pred[_stats_arrays_length - 1] + diff * _last_pred; + } + assert(result <= (age + 1.0), "Accumulated survivor rate %.2f must be smaller than age+1 %u", result, age + 1); + return result; +} + void G1SurvRateGroup::fill_in_last_surv_rates() { if (_num_added_regions > 0) { // conservative double surv_rate = _surv_rate_predictors[_num_added_regions-1]->last(); diff --git a/src/hotspot/share/gc/g1/g1SurvRateGroup.hpp b/src/hotspot/share/gc/g1/g1SurvRateGroup.hpp index 1e1cc049caf..5522555f24a 100644 --- a/src/hotspot/share/gc/g1/g1SurvRateGroup.hpp +++ b/src/hotspot/share/gc/g1/g1SurvRateGroup.hpp @@ -52,6 +52,9 @@ class G1SurvRateGroup : public CHeapObj { uint _stats_arrays_length; uint _num_added_regions; // The number of regions in this survivor rate group. + // The initial survivor rate for predictors. Somewhat random value. + const double InitialSurvivorRate = 0.4; + double* _accum_surv_rate_pred; double _last_pred; TruncatedSeq** _surv_rate_predictors; @@ -73,15 +76,7 @@ class G1SurvRateGroup : public CHeapObj { void record_surviving_words(uint age, size_t surv_words); void all_surviving_words_recorded(const G1Predictions& predictor, bool update_predictors); - double accum_surv_rate_pred(uint age) const { - assert(_stats_arrays_length > 0, "invariant" ); - if (age < _stats_arrays_length) - return _accum_surv_rate_pred[age]; - else { - double diff = (double)(age - _stats_arrays_length + 1); - return _accum_surv_rate_pred[_stats_arrays_length - 1] + diff * _last_pred; - } - } + double accum_surv_rate_pred(uint age) const; double surv_rate_pred(G1Predictions const& predictor, uint age) const { assert(is_valid_age(age), "must be"); From 891d5aedf12e837c9a9c7cb800fb3affa7430f00 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Mon, 27 May 2024 11:21:31 +0000 Subject: [PATCH 59/99] 8332683: G1: G1CardSetArray::EntryDataType [2] triggers ubsan runtime errors Reviewed-by: tschatzl, ayang --- .../share/gc/g1/g1CardSetContainers.hpp | 11 ++++++- .../gc/g1/g1CardSetContainers.inline.hpp | 32 +++++++++++++++---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp index 261b7e5b20a..43e6c8a3bf7 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp @@ -163,7 +163,8 @@ class G1CardSetArray : public G1CardSetContainer { private: EntryCountType _size; EntryCountType volatile _num_entries; - EntryDataType _data[2]; + // VLA implementation. + EntryDataType _data[1]; static const EntryCountType LockBitMask = (EntryCountType)1 << (sizeof(EntryCountType) * BitsPerByte - 1); static const EntryCountType EntryMask = LockBitMask - 1; @@ -184,6 +185,14 @@ class G1CardSetArray : public G1CardSetContainer { Atomic::release_store(_num_entries_addr, _local_num_entries); } }; + + EntryDataType const* base_addr() const; + + EntryDataType const* entry_addr(EntryCountType index) const; + + EntryDataType* entry_addr(EntryCountType index); + + EntryDataType at(EntryCountType index) const; public: G1CardSetArray(uint const card_in_region, EntryCountType num_cards); diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp index 330e9d63600..94ca13b0a33 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp @@ -145,7 +145,7 @@ inline G1CardSetArray::G1CardSetArray(uint card_in_region, EntryCountType num_ca _num_entries(1) { assert(_size > 0, "CardSetArray of size 0 not supported."); assert(_size < LockBitMask, "Only support CardSetArray of size %u or smaller.", LockBitMask - 1); - _data[0] = checked_cast(card_in_region); + *entry_addr(0) = checked_cast(card_in_region); } inline G1CardSetArray::G1CardSetArrayLocker::G1CardSetArrayLocker(EntryCountType volatile* num_entries_addr) : @@ -167,13 +167,31 @@ inline G1CardSetArray::G1CardSetArrayLocker::G1CardSetArrayLocker(EntryCountType } } +inline G1CardSetArray::EntryDataType const* G1CardSetArray::base_addr() const { + const void* ptr = reinterpret_cast(this) + header_size_in_bytes(); + return reinterpret_cast(ptr); +} + +inline G1CardSetArray::EntryDataType const* G1CardSetArray::entry_addr(EntryCountType index) const { + assert(index < _num_entries, "precondition"); + return base_addr() + index; +} + +inline G1CardSetArray::EntryDataType* G1CardSetArray::entry_addr(EntryCountType index) { + return const_cast(const_cast(this)->entry_addr(index)); +} + +inline G1CardSetArray::EntryDataType G1CardSetArray::at(EntryCountType index) const { + return *entry_addr(index); +} + inline G1AddCardResult G1CardSetArray::add(uint card_idx) { - assert(card_idx < (1u << (sizeof(_data[0]) * BitsPerByte)), + assert(card_idx < (1u << (sizeof(EntryDataType) * BitsPerByte)), "Card index %u does not fit allowed card value range.", card_idx); EntryCountType num_entries = Atomic::load_acquire(&_num_entries) & EntryMask; EntryCountType idx = 0; for (; idx < num_entries; idx++) { - if (_data[idx] == card_idx) { + if (at(idx) == card_idx) { return Found; } } @@ -186,7 +204,7 @@ inline G1AddCardResult G1CardSetArray::add(uint card_idx) { num_entries = x.num_entries(); // Look if the cards added while waiting for the lock are the same as our card. for (; idx < num_entries; idx++) { - if (_data[idx] == card_idx) { + if (at(idx) == card_idx) { return Found; } } @@ -196,7 +214,7 @@ inline G1AddCardResult G1CardSetArray::add(uint card_idx) { return Overflow; } - _data[num_entries] = checked_cast(card_idx); + *entry_addr(num_entries) = checked_cast(card_idx); x.inc_num_entries(); @@ -207,7 +225,7 @@ inline bool G1CardSetArray::contains(uint card_idx) { EntryCountType num_entries = Atomic::load_acquire(&_num_entries) & EntryMask; for (EntryCountType idx = 0; idx < num_entries; idx++) { - if (_data[idx] == card_idx) { + if (at(idx) == card_idx) { return true; } } @@ -218,7 +236,7 @@ template void G1CardSetArray::iterate(CardVisitor& found) { EntryCountType num_entries = Atomic::load_acquire(&_num_entries) & EntryMask; for (EntryCountType idx = 0; idx < num_entries; idx++) { - found(_data[idx]); + found(at(idx)); } } From 793fd72fa66b1367b68fe798230ea61ea0aab1d8 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Mon, 27 May 2024 13:22:49 +0000 Subject: [PATCH 60/99] 8332956: Problem list CodeCacheFullCountTest.java until JDK-8332954 is fixed Reviewed-by: chagedorn --- test/hotspot/jtreg/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index a8cdad8b268..b6cc0489485 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -81,6 +81,8 @@ compiler/startup/StartupOutput.java 8326615 generic-x64 compiler/rangechecks/TestArrayAccessAboveRCAfterRCCastIIEliminated.java 8332369 generic-all +compiler/codecache/CodeCacheFullCountTest.java 8332954 generic-all + ############################################################################# # :hotspot_gc From 08face8c4cd2d0b6f48f99bae5a380b7f7e4f2c2 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 27 May 2024 14:19:26 +0000 Subject: [PATCH 61/99] 8332890: Module imports don't work inside the same module Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Modules.java | 3 + .../com/sun/tools/javac/comp/TypeEnter.java | 2 +- test/langtools/tools/javac/ImportModule.java | 58 ++++++++++++++++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java index 6dd4a368f44..1136cb5621a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java @@ -1598,6 +1598,9 @@ private void initVisiblePackages(ModuleSymbol msym, Collection rea addVisiblePackages(msym, seen, exportsFrom, exports); } }); + + //module readability is reflexive: + msym.readModules.add(msym); } private void addVisiblePackages(ModuleSymbol msym, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java index 72943e09f0f..eb48812f538 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java @@ -498,7 +498,7 @@ private void doModuleImport(JCModuleImport tree) { } for (ExportsDirective export : currentModule.exports) { - if (export.modules != null && !export.modules.contains(env.toplevel.packge.modle)) { + if (export.modules != null && !export.modules.contains(env.toplevel.modle)) { continue; } diff --git a/test/langtools/tools/javac/ImportModule.java b/test/langtools/tools/javac/ImportModule.java index efbc9c21077..f38b77062e2 100644 --- a/test/langtools/tools/javac/ImportModule.java +++ b/test/langtools/tools/javac/ImportModule.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8328481 8332236 + * @bug 8328481 8332236 8332890 * @summary Check behavior of module imports. * @library /tools/lib * @modules java.logging @@ -741,4 +741,60 @@ void main() { .writeAll(); } + @Test //JDK-8332890 + public void testModuleInfoSelfImport(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeJavaFiles(src, + """ + import module M; + module M { + exports p1 to M1; + exports p2; + exports p3 to M; + uses A; + uses B; + uses C; + } + """, + """ + package p1; + public class A {} + """, + """ + package p2; + public class B {} + """, + """ + package p3; + public class C {} + """); + + Files.createDirectories(classes); + + List actualErrors = new JavacTask(tb) + .options("-XDrawDiagnostics", + "--enable-preview", "--release", SOURCE_VERSION) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expectedErrors = List.of( + "module-info.java:3:18: compiler.warn.module.not.found: M1", + "module-info.java:6:9: compiler.err.cant.resolve: kindname.class, A, , ", + "- compiler.note.preview.filename: module-info.java, DEFAULT", + "- compiler.note.preview.recompile", + "1 error", + "1 warning" + ); + + if (!Objects.equals(expectedErrors, actualErrors)) { + throw new AssertionError("Incorrect Output, expected: " + expectedErrors + + ", actual: " + out); + + } + } } From ed81a478e175631f1de69eb4b43f927629fefd74 Mon Sep 17 00:00:00 2001 From: Yudi Zheng Date: Mon, 27 May 2024 14:25:13 +0000 Subject: [PATCH 62/99] 8327964: Simplify BigInteger.implMultiplyToLen intrinsic Reviewed-by: mdoerr, amitkumar, kvn, fyang --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 14 ++-- .../cpu/aarch64/macroAssembler_aarch64.hpp | 2 +- .../cpu/aarch64/stubGenerator_aarch64.cpp | 9 ++- src/hotspot/cpu/ppc/macroAssembler_ppc.cpp | 12 ++-- src/hotspot/cpu/ppc/macroAssembler_ppc.hpp | 4 +- src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 5 +- .../cpu/riscv/macroAssembler_riscv.cpp | 14 ++-- .../cpu/riscv/macroAssembler_riscv.hpp | 4 +- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 9 ++- src/hotspot/cpu/s390/macroAssembler_s390.cpp | 5 +- src/hotspot/cpu/s390/stubGenerator_s390.cpp | 5 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 18 ++--- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 2 +- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 14 ++-- src/hotspot/share/opto/library_call.cpp | 72 +++---------------- src/hotspot/share/opto/runtime.cpp | 3 +- .../share/classes/java/math/BigInteger.java | 7 +- 17 files changed, 64 insertions(+), 135 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index faba321afc7..1929077fa16 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -3879,7 +3879,7 @@ void MacroAssembler::multiply_128_x_128_loop(Register y, Register z, * r2: y * r3: ylen * r4: z - * r5: zlen + * r5: tmp0 * r10: tmp1 * r11: tmp2 * r12: tmp3 @@ -3890,11 +3890,11 @@ void MacroAssembler::multiply_128_x_128_loop(Register y, Register z, * */ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, - Register z, Register zlen, + Register z, Register tmp0, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6, Register product_hi) { - assert_different_registers(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + assert_different_registers(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, product_hi); const Register idx = tmp1; const Register kdx = tmp2; @@ -3903,7 +3903,7 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi const Register y_idx = tmp4; const Register carry = tmp5; const Register product = xlen; - const Register x_xstart = zlen; // reuse register + const Register x_xstart = tmp0; // First Loop. // @@ -3919,9 +3919,9 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi // z[xstart] = (int)carry; // - movw(idx, ylen); // idx = ylen; - movw(kdx, zlen); // kdx = xlen+ylen; - mov(carry, zr); // carry = 0; + movw(idx, ylen); // idx = ylen; + addw(kdx, xlen, ylen); // kdx = xlen+ylen; + mov(carry, zr); // carry = 0; Label L_done; diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 67fd7236842..7b7ecf49c8c 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1510,7 +1510,7 @@ class MacroAssembler: public Assembler { void ghash_load_wide(int index, Register data, FloatRegister result, FloatRegister state); public: void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, - Register zlen, Register tmp1, Register tmp2, Register tmp3, + Register tmp0, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6, Register tmp7); void mul_add(Register out, Register in, Register offs, Register len, Register k); void ghash_multiply(FloatRegister result_lo, FloatRegister result_hi, diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 8d207b3f665..4625bb44f6d 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -4645,7 +4645,6 @@ class StubGenerator: public StubCodeGenerator { * c_rarg2 - y address * c_rarg3 - y length * c_rarg4 - z address - * c_rarg5 - z length */ address generate_multiplyToLen() { __ align(CodeEntryAlignment); @@ -4657,8 +4656,8 @@ class StubGenerator: public StubCodeGenerator { const Register y = r2; const Register ylen = r3; const Register z = r4; - const Register zlen = r5; + const Register tmp0 = r5; const Register tmp1 = r10; const Register tmp2 = r11; const Register tmp3 = r12; @@ -4669,7 +4668,7 @@ class StubGenerator: public StubCodeGenerator { BLOCK_COMMENT("Entry:"); __ enter(); // required for proper stackwalking of RuntimeStub frame - __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); + __ multiply_to_len(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(lr); @@ -4687,10 +4686,10 @@ class StubGenerator: public StubCodeGenerator { const Register x = r0; const Register xlen = r1; const Register z = r2; - const Register zlen = r3; const Register y = r4; // == x const Register ylen = r5; // == xlen + const Register tmp0 = r3; const Register tmp1 = r10; const Register tmp2 = r11; const Register tmp3 = r12; @@ -4705,7 +4704,7 @@ class StubGenerator: public StubCodeGenerator { __ push(spilled_regs, sp); __ mov(y, x); __ mov(ylen, xlen); - __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); + __ multiply_to_len(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); __ pop(spilled_regs, sp); __ leave(); __ ret(lr); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 000d4510c07..4b74b1ae941 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.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) 2012, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -3898,7 +3898,7 @@ void MacroAssembler::muladd(Register out, Register in, void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, - Register z, Register zlen, + Register z, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6, @@ -3909,11 +3909,11 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, ShortBranchVerifier sbv(this); - assert_different_registers(x, xlen, y, ylen, z, zlen, + assert_different_registers(x, xlen, y, ylen, z, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); - assert_different_registers(x, xlen, y, ylen, z, zlen, + assert_different_registers(x, xlen, y, ylen, z, tmp1, tmp2, tmp3, tmp4, tmp5, tmp7); - assert_different_registers(x, xlen, y, ylen, z, zlen, + assert_different_registers(x, xlen, y, ylen, z, tmp1, tmp2, tmp3, tmp4, tmp5, tmp8); const Register idx = tmp1; @@ -3941,7 +3941,7 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, // z[xstart] = (int)carry; mr_if_needed(idx, ylen); // idx = ylen - mr_if_needed(kdx, zlen); // kdx = xlen + ylen + add(kdx, xlen, ylen); // kdx = xlen + ylen li(carry, 0); // carry = 0 Label L_done; diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 5a628674da1..c92f8564376 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -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. * Copyright (c) 2012, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -784,7 +784,7 @@ class MacroAssembler: public Assembler { Register tmp1, Register tmp2, Register carry); void multiply_to_len(Register x, Register xlen, Register y, Register ylen, - Register z, Register zlen, + Register z, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6, Register tmp7, Register tmp8, Register tmp9, Register tmp10, Register tmp11, Register tmp12, Register tmp13); diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index 63502c00b23..ad8b76ba667 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -3204,7 +3204,6 @@ class StubGenerator: public StubCodeGenerator { // R5 - y address // R6 - y length // R7 - z address - // R8 - z length // address generate_multiplyToLen() { @@ -3217,7 +3216,6 @@ class StubGenerator: public StubCodeGenerator { const Register y = R5; const Register ylen = R6; const Register z = R7; - const Register zlen = R8; const Register tmp1 = R2; // TOC not used. const Register tmp2 = R9; @@ -3240,7 +3238,6 @@ class StubGenerator: public StubCodeGenerator { // C2 does not respect int to long conversion for stub calls. __ clrldi(xlen, xlen, 32); __ clrldi(ylen, ylen, 32); - __ clrldi(zlen, zlen, 32); // Save non-volatile regs (frameless). int current_offs = 8; @@ -3253,7 +3250,7 @@ class StubGenerator: public StubCodeGenerator { __ std(R30, -current_offs, R1_SP); current_offs += 8; __ std(R31, -current_offs, R1_SP); - __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, + __ multiply_to_len(x, xlen, y, ylen, z, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9, tmp10, tmp11, tmp12, tmp13); // Restore non-volatile regs. diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index bfa68a88f57..836faccc0f6 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -4120,7 +4120,7 @@ void MacroAssembler::multiply_128_x_128_loop(Register y, Register z, * x12: y * x13: ylen * x14: z - * x15: zlen + * x15: tmp0 * x16: tmp1 * x17: tmp2 * x7: tmp3 @@ -4130,10 +4130,10 @@ void MacroAssembler::multiply_128_x_128_loop(Register y, Register z, * x31: tmp7 */ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, - Register z, Register zlen, + Register z, Register tmp0, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6, Register product_hi) { - assert_different_registers(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + assert_different_registers(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); const Register idx = tmp1; const Register kdx = tmp2; @@ -4142,11 +4142,11 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi const Register y_idx = tmp4; const Register carry = tmp5; const Register product = xlen; - const Register x_xstart = zlen; // reuse register + const Register x_xstart = tmp0; - mv(idx, ylen); // idx = ylen; - mv(kdx, zlen); // kdx = xlen+ylen; - mv(carry, zr); // carry = 0; + mv(idx, ylen); // idx = ylen; + addw(kdx, xlen, ylen); // kdx = xlen+ylen; + mv(carry, zr); // carry = 0; Label L_multiply_64_x_64_loop, L_done; diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 35a242e47fd..4e52cdaee38 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.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, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -1287,7 +1287,7 @@ class MacroAssembler: public Assembler { Register tmp, Register tmp3, Register tmp4, Register tmp6, Register product_hi); void multiply_to_len(Register x, Register xlen, Register y, Register ylen, - Register z, Register zlen, + Register z, Register tmp0, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6, Register product_hi); #endif diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 52fc126a459..c292f671325 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2840,7 +2840,6 @@ class StubGenerator: public StubCodeGenerator { * c_rarg2 - y address * c_rarg3 - y length * c_rarg4 - z address - * c_rarg5 - z length */ address generate_multiplyToLen() { @@ -2853,8 +2852,8 @@ class StubGenerator: public StubCodeGenerator { const Register y = x12; const Register ylen = x13; const Register z = x14; - const Register zlen = x15; + const Register tmp0 = x15; const Register tmp1 = x16; const Register tmp2 = x17; const Register tmp3 = x7; @@ -2865,7 +2864,7 @@ class StubGenerator: public StubCodeGenerator { BLOCK_COMMENT("Entry:"); __ enter(); // required for proper stackwalking of RuntimeStub frame - __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); + __ multiply_to_len(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(); @@ -2881,10 +2880,10 @@ class StubGenerator: public StubCodeGenerator { const Register x = x10; const Register xlen = x11; const Register z = x12; - const Register zlen = x13; const Register y = x14; // == x const Register ylen = x15; // == xlen + const Register tmp0 = x13; // zlen, unused const Register tmp1 = x16; const Register tmp2 = x17; const Register tmp3 = x7; @@ -2897,7 +2896,7 @@ class StubGenerator: public StubCodeGenerator { __ enter(); __ mv(y, x); __ mv(ylen, xlen); - __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); + __ multiply_to_len(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); __ leave(); __ ret(); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 224153f0e84..ef5216a12ba 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -5281,9 +5281,6 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, z_stmg(Z_R7, Z_R13, _z_abi(gpr7), Z_SP); - // In openJdk, we store the argument as 32-bit value to slot. - Address zlen(Z_SP, _z_abi(remaining_cargs)); // Int in long on big endian. - const Register idx = tmp1; const Register kdx = tmp2; const Register xstart = tmp3; @@ -5308,7 +5305,7 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, // lgr_if_needed(idx, ylen); // idx = ylen - z_llgf(kdx, zlen); // C2 does not respect int to long conversion for stub calls, thus load zero-extended. + z_agrk(kdx, xlen, ylen); // kdx = xlen + ylen clear_reg(carry); // carry = 0 Label L_done; diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index db686158f21..dfd20730b84 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -2981,7 +2981,6 @@ class StubGenerator: public StubCodeGenerator { // Z_ARG3 - y address // Z_ARG4 - y length // Z_ARG5 - z address - // 160[Z_SP] - z length address generate_multiplyToLen() { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", "multiplyToLen"); @@ -2993,8 +2992,6 @@ class StubGenerator: public StubCodeGenerator { const Register y = Z_ARG3; const Register ylen = Z_ARG4; const Register z = Z_ARG5; - // zlen is passed on the stack: - // Address zlen(Z_SP, _z_abi(remaining_cargs)); // Next registers will be saved on stack in multiply_to_len(). const Register tmp1 = Z_tmp_1; diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 01372f0c53a..851b89a0a06 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -6983,7 +6983,7 @@ void MacroAssembler::multiply_128_x_128_bmi2_loop(Register y, Register z, * rsi: y * rcx: ylen * r8: z - * r11: zlen + * r11: tmp0 * r12: tmp1 * r13: tmp2 * r14: tmp3 @@ -6991,11 +6991,12 @@ void MacroAssembler::multiply_128_x_128_bmi2_loop(Register y, Register z, * rbx: tmp5 * */ -void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, +void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register tmp0, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5) { ShortBranchVerifier sbv(this); - assert_different_registers(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx); + assert_different_registers(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, rdx); + push(tmp0); push(tmp1); push(tmp2); push(tmp3); @@ -7003,7 +7004,6 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi push(tmp5); push(xlen); - push(zlen); const Register idx = tmp1; const Register kdx = tmp2; @@ -7012,7 +7012,7 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi const Register y_idx = tmp4; const Register carry = tmp5; const Register product = xlen; - const Register x_xstart = zlen; // reuse register + const Register x_xstart = tmp0; // First Loop. // @@ -7028,9 +7028,9 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi // z[xstart] = (int)carry; // - movl(idx, ylen); // idx = ylen; - movl(kdx, zlen); // kdx = xlen+ylen; - xorq(carry, carry); // carry = 0; + movl(idx, ylen); // idx = ylen; + lea(kdx, Address(xlen, ylen)); // kdx = xlen+ylen; + xorq(carry, carry); // carry = 0; Label L_done; @@ -7134,7 +7134,6 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi bind(L_done); - pop(zlen); pop(xlen); pop(tmp5); @@ -7142,6 +7141,7 @@ void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Regi pop(tmp3); pop(tmp2); pop(tmp1); + pop(tmp0); } void MacroAssembler::vectorized_mismatch(Register obja, Register objb, Register length, Register log2_array_indxscale, diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index b9f14da3db6..fd989c7bd22 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -2018,7 +2018,7 @@ class MacroAssembler: public Assembler { Register yz_idx, Register idx, Register jdx, Register carry, Register product, Register carry2); - void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, + void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register tmp0, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5); void square_rshift(Register x, Register len, Register z, Register tmp1, Register tmp3, Register tmp4, Register tmp5, Register rdxReg, Register raxReg); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 3f2865e7465..577c56cb7a2 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -3044,10 +3044,8 @@ address StubGenerator::generate_updateBytesCRC32C(bool is_pclmulqdq_supported) { * c_rarg3 - y length * not Win64 * c_rarg4 - z address - * c_rarg5 - z length * Win64 * rsp+40 - z address - * rsp+48 - z length */ address StubGenerator::generate_multiplyToLen() { __ align(CodeEntryAlignment); @@ -3061,9 +3059,9 @@ address StubGenerator::generate_multiplyToLen() { const Register y = rsi; const Register ylen = rcx; const Register z = r8; - const Register zlen = r11; // Next registers will be saved on stack in multiply_to_len(). + const Register tmp0 = r11; const Register tmp1 = r12; const Register tmp2 = r13; const Register tmp3 = r14; @@ -3073,21 +3071,17 @@ address StubGenerator::generate_multiplyToLen() { BLOCK_COMMENT("Entry:"); __ enter(); // required for proper stackwalking of RuntimeStub frame -#ifndef _WIN64 - __ movptr(zlen, r9); // Save r9 in r11 - zlen -#endif setup_arg_regs(4); // x => rdi, xlen => rsi, y => rdx - // ylen => rcx, z => r8, zlen => r11 + // ylen => rcx, z => r8 // r9 and r10 may be used to save non-volatile registers #ifdef _WIN64 - // last 2 arguments (#4, #5) are on stack on Win64 + // last argument (#4) is on stack on Win64 __ movptr(z, Address(rsp, 6 * wordSize)); - __ movptr(zlen, Address(rsp, 7 * wordSize)); #endif __ movptr(xlen, rsi); __ movptr(y, rdx); - __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5); + __ multiply_to_len(x, xlen, y, ylen, z, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5); restore_arg_regs(); diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 96e88c1a96b..3a658b2e007 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -5978,71 +5978,17 @@ bool LibraryCallKit::inline_multiplyToLen() { return false; } - // Set the original stack and the reexecute bit for the interpreter to reexecute - // the bytecode that invokes BigInteger.multiplyToLen() if deoptimization happens - // on the return from z array allocation in runtime. - { PreserveReexecuteState preexecs(this); - jvms()->set_should_reexecute(true); - - Node* x_start = array_element_address(x, intcon(0), x_elem); - Node* y_start = array_element_address(y, intcon(0), y_elem); - // 'x_start' points to x array + scaled xlen - // 'y_start' points to y array + scaled ylen - - // Allocate the result array - Node* zlen = _gvn.transform(new AddINode(xlen, ylen)); - ciKlass* klass = ciTypeArrayKlass::make(T_INT); - Node* klass_node = makecon(TypeKlassPtr::make(klass)); - - IdealKit ideal(this); - -#define __ ideal. - Node* one = __ ConI(1); - Node* zero = __ ConI(0); - IdealVariable need_alloc(ideal), z_alloc(ideal); __ declarations_done(); - __ set(need_alloc, zero); - __ set(z_alloc, z); - __ if_then(z, BoolTest::eq, null()); { - __ increment (need_alloc, one); - } __ else_(); { - // Update graphKit memory and control from IdealKit. - sync_kit(ideal); - Node* cast = new CastPPNode(control(), z, TypePtr::NOTNULL); - _gvn.set_type(cast, cast->bottom_type()); - C->record_for_igvn(cast); - - Node* zlen_arg = load_array_length(cast); - // Update IdealKit memory and control from graphKit. - __ sync_kit(this); - __ if_then(zlen_arg, BoolTest::lt, zlen); { - __ increment (need_alloc, one); - } __ end_if(); - } __ end_if(); - - __ if_then(__ value(need_alloc), BoolTest::ne, zero); { - // Update graphKit memory and control from IdealKit. - sync_kit(ideal); - Node * narr = new_array(klass_node, zlen, 1); - // Update IdealKit memory and control from graphKit. - __ sync_kit(this); - __ set(z_alloc, narr); - } __ end_if(); - - sync_kit(ideal); - z = __ value(z_alloc); - // Can't use TypeAryPtr::INTS which uses Bottom offset. - _gvn.set_type(z, TypeOopPtr::make_from_klass(klass)); - // Final sync IdealKit and GraphKit. - final_sync(ideal); -#undef __ + Node* x_start = array_element_address(x, intcon(0), x_elem); + Node* y_start = array_element_address(y, intcon(0), y_elem); + // 'x_start' points to x array + scaled xlen + // 'y_start' points to y array + scaled ylen - Node* z_start = array_element_address(z, intcon(0), T_INT); + Node* z_start = array_element_address(z, intcon(0), T_INT); - Node* call = make_runtime_call(RC_LEAF|RC_NO_FP, - OptoRuntime::multiplyToLen_Type(), - stubAddr, stubName, TypePtr::BOTTOM, - x_start, xlen, y_start, ylen, z_start, zlen); - } // original reexecute is set back here + Node* call = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::multiplyToLen_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + x_start, xlen, y_start, ylen, z_start); C->set_has_split_ifs(true); // Has chance for split-if optimization set_result(z); diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 3b4519623ad..d8e5cdbab04 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1150,7 +1150,7 @@ const TypeFunc* OptoRuntime::digestBase_implCompressMB_Type(bool is_sha3) { const TypeFunc* OptoRuntime::multiplyToLen_Type() { // create input type (domain) - int num_args = 6; + int num_args = 5; int argcnt = num_args; const Type** fields = TypeTuple::fields(argcnt); int argp = TypeFunc::Parms; @@ -1159,7 +1159,6 @@ const TypeFunc* OptoRuntime::multiplyToLen_Type() { fields[argp++] = TypePtr::NOTNULL; // y fields[argp++] = TypeInt::INT; // ylen fields[argp++] = TypePtr::NOTNULL; // z - fields[argp++] = TypeInt::INT; // zlen assert(argp == TypeFunc::Parms+argcnt, "correct decoding"); const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields); diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index a972faafb45..1192bc50b78 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -1831,6 +1831,10 @@ BigInteger multiply(long v) { private static int[] multiplyToLen(int[] x, int xlen, int[] y, int ylen, int[] z) { multiplyToLenCheck(x, xlen); multiplyToLenCheck(y, ylen); + + if (z == null || z.length < (xlen + ylen)) + z = new int[xlen + ylen]; + return implMultiplyToLen(x, xlen, y, ylen, z); } @@ -1839,9 +1843,6 @@ private static int[] implMultiplyToLen(int[] x, int xlen, int[] y, int ylen, int int xstart = xlen - 1; int ystart = ylen - 1; - if (z == null || z.length < (xlen+ ylen)) - z = new int[xlen+ylen]; - long carry = 0; for (int j=ystart, k=ystart+1+xstart; j >= 0; j--, k--) { long product = (y[j] & LONG_MASK) * From be1d374bc54d43aae3b3c1feace22d38fe2156b6 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 27 May 2024 14:32:30 +0000 Subject: [PATCH 63/99] 8332825: ubsan: guardedMemory.cpp:35:11: runtime error: null pointer passed as argument 2, which is declared to never be null Reviewed-by: clanger, mdoerr --- src/hotspot/share/memory/guardedMemory.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/memory/guardedMemory.cpp b/src/hotspot/share/memory/guardedMemory.cpp index 91adb016c65..7b676d72588 100644 --- a/src/hotspot/share/memory/guardedMemory.cpp +++ b/src/hotspot/share/memory/guardedMemory.cpp @@ -32,7 +32,9 @@ void* GuardedMemory::wrap_copy(const void* ptr, const size_t len, const void* ta if (outerp != nullptr) { GuardedMemory guarded(outerp, len, tag); void* innerp = guarded.get_user_ptr(); - memcpy(innerp, ptr, len); + if (ptr != nullptr) { + memcpy(innerp, ptr, len); + } return innerp; } return nullptr; // OOM From 86eb5d9f3be30ff9df1318f18ab73c7129c978f6 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Mon, 27 May 2024 21:52:49 +0000 Subject: [PATCH 64/99] 8329958: Windows x86 build fails: downcallLinker.cpp(36) redefinition Reviewed-by: kvn, shade --- src/hotspot/share/prims/downcallLinker.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/prims/downcallLinker.hpp b/src/hotspot/share/prims/downcallLinker.hpp index 188987efbb5..01ee5c56776 100644 --- a/src/hotspot/share/prims/downcallLinker.hpp +++ b/src/hotspot/share/prims/downcallLinker.hpp @@ -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 @@ -41,7 +41,8 @@ class DowncallLinker: AllStatic { int captured_state_mask, bool needs_transition); - static void capture_state(int32_t* value_ptr, int captured_state_mask); + // This is defined as JVM_LEAF which adds the JNICALL modifier. + static void JNICALL capture_state(int32_t* value_ptr, int captured_state_mask); class StubGenerator : public StubCodeGenerator { BasicType* _signature; From b5e1615c0084538f2161fe9b56748d188983e972 Mon Sep 17 00:00:00 2001 From: Korov Date: Tue, 28 May 2024 06:43:07 +0000 Subject: [PATCH 65/99] 8292955: Collections.checkedMap Map.merge does not properly check key and value Reviewed-by: gli, liach, pminborg --- .../share/classes/java/util/Collections.java | 3 ++- test/jdk/java/util/Collections/CheckedMapBash.java | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/util/Collections.java b/src/java.base/share/classes/java/util/Collections.java index 63949db2cc0..4ec5756f712 100644 --- a/src/java.base/share/classes/java/util/Collections.java +++ b/src/java.base/share/classes/java/util/Collections.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 @@ -4050,6 +4050,7 @@ public V compute(K key, public V merge(K key, V value, BiFunction remappingFunction) { Objects.requireNonNull(remappingFunction); + typeCheck(key, value); return m.merge(key, value, (v1, v2) -> { V newValue = remappingFunction.apply(v1, v2); typeCheck(null, newValue); diff --git a/test/jdk/java/util/Collections/CheckedMapBash.java b/test/jdk/java/util/Collections/CheckedMapBash.java index 240ce649285..a8e3fd9e952 100644 --- a/test/jdk/java/util/Collections/CheckedMapBash.java +++ b/test/jdk/java/util/Collections/CheckedMapBash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, 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 @@ -23,13 +23,14 @@ /* * @test - * @bug 4904067 5023830 7129185 8072015 + * @bug 4904067 5023830 7129185 8072015 8292955 * @summary Unit test for Collections.checkedMap * @author Josh Bloch * @run testng CheckedMapBash * @key randomness */ +import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -183,4 +184,11 @@ public static Collection makeCheckedMaps() { }; return Arrays.asList(params); } + + @Test(groups = "type_check") + public static void testCheckedMapMerge() { + Map m = Collections.checkedMap(new HashMap<>(), Integer.class, Integer.class); + Assert.assertThrows(ClassCastException.class, () -> m.merge("key", "value", (v1, v2) -> null)); + Assert.assertThrows(ClassCastException.class, () -> m.merge("key", 3, (v1, v2) -> v2)); + } } From 2f2cf38bb5cecea698e519396574343cfbe4f359 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 28 May 2024 07:51:49 +0000 Subject: [PATCH 66/99] 8332883: Some simple cleanup in vectornode.cpp Reviewed-by: kvn --- src/hotspot/share/opto/vectornode.cpp | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 5489a13b871..600795bbc73 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -415,11 +415,7 @@ bool VectorNode::implemented(int opc, uint vlen, BasicType bt) { } bool VectorNode::is_type_transition_short_to_int(Node* n) { - switch (n->Opcode()) { - case Op_MulAddS2I: - return true; - } - return false; + return n->Opcode() == Op_MulAddS2I; } bool VectorNode::is_type_transition_to_int(Node* n) { @@ -427,17 +423,11 @@ bool VectorNode::is_type_transition_to_int(Node* n) { } bool VectorNode::is_muladds2i(const Node* n) { - if (n->Opcode() == Op_MulAddS2I) { - return true; - } - return false; + return n->Opcode() == Op_MulAddS2I; } bool VectorNode::is_roundopD(Node* n) { - if (n->Opcode() == Op_RoundDoubleMode) { - return true; - } - return false; + return n->Opcode() == Op_RoundDoubleMode; } bool VectorNode::is_vector_rotate_supported(int vopc, uint vlen, BasicType bt) { @@ -584,10 +574,7 @@ bool VectorNode::is_rotate_opcode(int opc) { } bool VectorNode::is_scalar_rotate(Node* n) { - if (is_rotate_opcode(n->Opcode())) { - return true; - } - return false; + return is_rotate_opcode(n->Opcode()); } bool VectorNode::is_vshift_cnt_opcode(int opc) { From 1850914380655ef3d08614a5656e7cc23478f38f Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 28 May 2024 08:08:42 +0000 Subject: [PATCH 67/99] 8332864: Parallel: Merge ParMarkBitMapClosure into MoveAndUpdateClosure Reviewed-by: tschatzl --- .../share/gc/parallel/psParallelCompact.cpp | 6 +- .../share/gc/parallel/psParallelCompact.hpp | 133 ++++++------------ 2 files changed, 44 insertions(+), 95 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 4256be8870d..f544831ca96 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -2523,7 +2523,7 @@ void PSParallelCompact::fill_region(ParCompactionManager* cm, MoveAndUpdateClosu void PSParallelCompact::fill_and_update_region(ParCompactionManager* cm, size_t region_idx) { - MoveAndUpdateClosure cl(mark_bitmap(), cm, region_idx); + MoveAndUpdateClosure cl(mark_bitmap(), region_idx); fill_region(cm, cl, region_idx); } @@ -2537,7 +2537,7 @@ void PSParallelCompact::fill_and_update_shadow_region(ParCompactionManager* cm, // so use MoveAndUpdateClosure to fill the normal region. Otherwise, use // MoveAndUpdateShadowClosure to fill the acquired shadow region. if (shadow_region == ParCompactionManager::InvalidShadow) { - MoveAndUpdateClosure cl(mark_bitmap(), cm, region_idx); + MoveAndUpdateClosure cl(mark_bitmap(), region_idx); region_ptr->shadow_to_normal(); return fill_region(cm, cl, region_idx); } else { @@ -2624,7 +2624,7 @@ void MoveAndUpdateClosure::complete_region(ParCompactionManager *cm, HeapWord *d region_ptr->set_completed(); } -ParMarkBitMapClosure::IterationStatus +MoveAndUpdateClosure::IterationStatus MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) { assert(destination() != nullptr, "sanity"); _source = addr; diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 67346d7eee5..713e9a1f84f 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -586,75 +586,6 @@ ParallelCompactData::is_region_aligned(HeapWord* addr) const // single subclass that uses it to avoid making is_full() virtual, and thus // adding a virtual call per live object. -class ParMarkBitMapClosure: public StackObj { - public: - typedef ParMarkBitMap::idx_t idx_t; - typedef ParMarkBitMap::IterationStatus IterationStatus; - - public: - inline ParMarkBitMapClosure(ParMarkBitMap* mbm, ParCompactionManager* cm, - size_t words = max_uintx); - - inline ParCompactionManager* compaction_manager() const; - inline ParMarkBitMap* bitmap() const; - inline size_t words_remaining() const; - inline bool is_full() const; - inline HeapWord* source() const; - - inline void set_source(HeapWord* addr); - - virtual IterationStatus do_addr(HeapWord* addr, size_t words) = 0; - - protected: - inline void decrement_words_remaining(size_t words); - - private: - ParMarkBitMap* const _bitmap; - ParCompactionManager* const _compaction_manager; - size_t _words_remaining; // Words left to copy. - - protected: - HeapWord* _source; // Next addr that would be read. -}; - -inline -ParMarkBitMapClosure::ParMarkBitMapClosure(ParMarkBitMap* bitmap, - ParCompactionManager* cm, - size_t words): - _bitmap(bitmap), _compaction_manager(cm) -{ - _words_remaining = words; - _source = nullptr; -} - -inline ParCompactionManager* ParMarkBitMapClosure::compaction_manager() const { - return _compaction_manager; -} - -inline ParMarkBitMap* ParMarkBitMapClosure::bitmap() const { - return _bitmap; -} - -inline size_t ParMarkBitMapClosure::words_remaining() const { - return _words_remaining; -} - -inline bool ParMarkBitMapClosure::is_full() const { - return words_remaining() == 0; -} - -inline HeapWord* ParMarkBitMapClosure::source() const { - return _source; -} - -inline void ParMarkBitMapClosure::set_source(HeapWord* addr) { - _source = addr; -} - -inline void ParMarkBitMapClosure::decrement_words_remaining(size_t words) { - assert(_words_remaining >= words, "processed too many words"); - _words_remaining -= words; -} // The Parallel collector is a stop-the-world garbage collector that // does parts of the collection using parallel threads. The collection includes @@ -955,21 +886,44 @@ class PSParallelCompact : AllStatic { #endif // #ifdef ASSERT }; -class MoveAndUpdateClosure: public ParMarkBitMapClosure { +class MoveAndUpdateClosure: public StackObj { + private: + ParMarkBitMap* const _bitmap; + size_t _words_remaining; // Words left to copy. static inline size_t calculate_words_remaining(size_t region); + + protected: + HeapWord* _source; // Next addr that would be read. + HeapWord* _destination; // Next addr to be written. + ObjectStartArray* const _start_array; + size_t _offset; + + inline void decrement_words_remaining(size_t words); + // Update variables to indicate that word_count words were processed. + inline void update_state(size_t words); + public: - inline MoveAndUpdateClosure(ParMarkBitMap* bitmap, ParCompactionManager* cm, - size_t region); + typedef ParMarkBitMap::idx_t idx_t; + typedef ParMarkBitMap::IterationStatus IterationStatus; - // Accessors. - HeapWord* destination() const { return _destination; } - HeapWord* copy_destination() const { return _destination + _offset; } + ParMarkBitMap* bitmap() const { return _bitmap; } + + size_t words_remaining() const { return _words_remaining; } + bool is_full() const { return _words_remaining == 0; } + HeapWord* source() const { return _source; } + void set_source(HeapWord* addr) { _source = addr; } // If the object will fit (size <= words_remaining()), copy it to the current // destination, update the interior oops and the start array and return either // full (if the closure is full) or incomplete. If the object will not fit, // return would_overflow. - IterationStatus do_addr(HeapWord* addr, size_t size); + virtual IterationStatus do_addr(HeapWord* addr, size_t words); + + inline MoveAndUpdateClosure(ParMarkBitMap* bitmap, size_t region); + + // Accessors. + HeapWord* destination() const { return _destination; } + HeapWord* copy_destination() const { return _destination + _offset; } // Copy enough words to fill this closure or to the end of an object, // whichever is smaller, starting at source(). The start array is not @@ -978,17 +932,13 @@ class MoveAndUpdateClosure: public ParMarkBitMapClosure { virtual void complete_region(ParCompactionManager* cm, HeapWord* dest_addr, PSParallelCompact::RegionData* region_ptr); - -protected: - // Update variables to indicate that word_count words were processed. - inline void update_state(size_t word_count); - - protected: - HeapWord* _destination; // Next addr to be written. - ObjectStartArray* const _start_array; - size_t _offset; }; +inline void MoveAndUpdateClosure::decrement_words_remaining(size_t words) { + assert(_words_remaining >= words, "processed too many words"); + _words_remaining -= words; +} + inline size_t MoveAndUpdateClosure::calculate_words_remaining(size_t region) { HeapWord* dest_addr = PSParallelCompact::summary_data().region_to_addr(region); PSParallelCompact::SpaceId dest_space_id = PSParallelCompact::space_id(dest_addr); @@ -999,14 +949,13 @@ inline size_t MoveAndUpdateClosure::calculate_words_remaining(size_t region) { } inline -MoveAndUpdateClosure::MoveAndUpdateClosure(ParMarkBitMap* bitmap, - ParCompactionManager* cm, - size_t region_idx) : - ParMarkBitMapClosure(bitmap, cm, calculate_words_remaining(region_idx)), +MoveAndUpdateClosure::MoveAndUpdateClosure(ParMarkBitMap* bitmap, size_t region_idx) : + _bitmap(bitmap), + _words_remaining(calculate_words_remaining(region_idx)), + _source(nullptr), _destination(PSParallelCompact::summary_data().region_to_addr(region_idx)), _start_array(PSParallelCompact::start_array(PSParallelCompact::space_id(_destination))), - _offset(0) { } - + _offset(0) {} inline void MoveAndUpdateClosure::update_state(size_t words) { @@ -1040,7 +989,7 @@ MoveAndUpdateShadowClosure::MoveAndUpdateShadowClosure(ParMarkBitMap *bitmap, ParCompactionManager *cm, size_t region, size_t shadow) : - MoveAndUpdateClosure(bitmap, cm, region), + MoveAndUpdateClosure(bitmap, region), _shadow(shadow) { _offset = calculate_shadow_offset(region, shadow); } From 2edb6d98133d8bd6dc4527c7497c460283fdc53e Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Tue, 28 May 2024 08:12:36 +0000 Subject: [PATCH 68/99] 8330386: Replace Opaque4Node of Initialized Assertion Predicate with new OpaqueInitializedAssertionPredicateNode Reviewed-by: kvn, roland --- src/hotspot/share/opto/classes.hpp | 1 + src/hotspot/share/opto/loopPredicate.cpp | 7 +- src/hotspot/share/opto/loopTransform.cpp | 95 ++-- src/hotspot/share/opto/loopnode.cpp | 7 +- src/hotspot/share/opto/loopnode.hpp | 3 +- src/hotspot/share/opto/loopopts.cpp | 21 +- src/hotspot/share/opto/macro.cpp | 16 +- src/hotspot/share/opto/node.cpp | 2 +- src/hotspot/share/opto/node.hpp | 9 +- src/hotspot/share/opto/opaquenode.cpp | 4 + src/hotspot/share/opto/opaquenode.hpp | 19 +- src/hotspot/share/opto/predicates.cpp | 10 +- src/hotspot/share/opto/predicates.hpp | 2 +- src/hotspot/share/opto/split_if.cpp | 6 +- ...aqueInitializedAssertionPredicateNode.java | 407 ++++++++++++++++++ 15 files changed, 542 insertions(+), 67 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/predicates/assertion/TestOpaqueInitializedAssertionPredicateNode.java diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index f1da18f464e..db6cb817d77 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -271,6 +271,7 @@ macro(OpaqueLoopStride) macro(OpaqueZeroTripGuard) macro(Opaque3) macro(Opaque4) +macro(OpaqueInitializedAssertionPredicate) macro(ProfileBoolean) macro(OrI) macro(OrL) diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index 9fcfbaf5e64..8d2cf9dc936 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -348,10 +348,13 @@ void PhaseIdealLoop::get_assertion_predicates(Node* predicate, Unique_Node_List& if (uncommon_proj->unique_ctrl_out() != rgn) { break; } - if (iff->in(1)->Opcode() == Op_Opaque4 && assertion_predicate_has_loop_opaque_node(iff)) { + Node* bol = iff->in(1); + assert(!bol->is_OpaqueInitializedAssertionPredicate(), "should not find an Initialized Assertion Predicate"); + if (bol->is_Opaque4()) { + assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes"); if (get_opaque) { // Collect the predicate Opaque4 node. - list.push(iff->in(1)); + list.push(bol); } else { // Collect the predicate projection. list.push(predicate); diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index f2022d35cf6..b2482edbf7a 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1201,11 +1201,12 @@ bool IdealLoopTree::policy_range_check(PhaseIdealLoop* phase, bool provisional, // Comparing trip+off vs limit Node *bol = iff->in(1); - if (bol->req() != 2) { + if (bol->req() < 2) { continue; // dead constant test } if (!bol->is_Bool()) { - assert(bol->Opcode() == Op_Conv2B, "predicate check only"); + assert(bol->is_Opaque4() || bol->is_OpaqueInitializedAssertionPredicate(), + "Opaque node of non-null-check or of Initialized Assertion Predicate"); continue; } if (bol->as_Bool()->_test._test == BoolTest::ne) { @@ -1385,8 +1386,10 @@ void PhaseIdealLoop::copy_assertion_predicates_to_main_loop_helper(const Predica uncommon_proj = iff->proj_out(1 - predicate_proj->as_Proj()->_con); if (uncommon_proj->unique_ctrl_out() != rgn) break; - if (iff->in(1)->Opcode() == Op_Opaque4) { - assert(assertion_predicate_has_loop_opaque_node(iff), "unexpected"); + Node* bol = iff->in(1); + assert(!bol->is_OpaqueInitializedAssertionPredicate(), "should not find an Initialized Assertion Predicate"); + if (bol->is_Opaque4()) { + assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes"); // Clone the Assertion Predicate twice and initialize one with the initial // value of the loop induction variable. Leave the other predicate // to be initialized when increasing the stride during loop unrolling. @@ -1496,20 +1499,25 @@ Node* PhaseIdealLoop::clone_assertion_predicate_and_initialize(Node* iff, Node* Node* uncommon_proj, Node* control, IdealLoopTree* outer_loop, Node* input_proj) { TemplateAssertionPredicateExpression template_assertion_predicate_expression(iff->in(1)->as_Opaque4()); - Opaque4Node* new_opaque4_node; + Node* new_opaque_node; if (new_stride == nullptr) { - // Only set a new OpaqueLoopInitNode node and clone the existing OpaqueLoopStrideNode without modification. + // Clone the Template Assertion Predicate and set a new OpaqueLoopInitNode to create a new Template Assertion Predicate. // This is done when creating a new Template Assertion Predicate for the main loop which requires a new init node. + // We keep the Opaque4 node since it's still a template. assert(new_init->is_OpaqueLoopInit(), "only for creating new Template Assertion Predicates"); - new_opaque4_node = template_assertion_predicate_expression.clone_and_replace_init(new_init, control, this); + new_opaque_node = template_assertion_predicate_expression.clone_and_replace_init(new_init, control, this); } else { - new_opaque4_node = template_assertion_predicate_expression.clone_and_replace_init_and_stride(new_init, new_stride, + // Create an Initialized Assertion Predicate from the Template Assertion Predicate. + new_opaque_node = template_assertion_predicate_expression.clone_and_replace_init_and_stride(new_init, new_stride, control, this); + // Since this is an Initialized Assertion Predicate, we use the dedicated opaque node. + new_opaque_node = new OpaqueInitializedAssertionPredicateNode(new_opaque_node->in(1)->as_Bool(), C); + register_new_node(new_opaque_node, control); } Node* proj = predicate->clone(); Node* other_proj = uncommon_proj->clone(); Node* new_iff = iff->clone(); - new_iff->set_req(1, new_opaque4_node); + new_iff->set_req(1, new_opaque_node); proj->set_req(0, new_iff); other_proj->set_req(0, new_iff); Node* frame = new ParmNode(C->start(), TypeFunc::FramePtr); @@ -1965,25 +1973,30 @@ void PhaseIdealLoop::update_main_loop_assertion_predicates(Node* ctrl, CountedLo while (entry != nullptr && entry->is_Proj() && entry->in(0)->is_If()) { IfNode* iff = entry->in(0)->as_If(); ProjNode* proj = iff->proj_out(1 - entry->as_Proj()->_con); - if (proj->unique_ctrl_out()->Opcode() != Op_Halt) { + if (!proj->unique_ctrl_out()->is_Halt()) { break; } - if (iff->in(1)->Opcode() == Op_Opaque4) { - if (!assertion_predicate_has_loop_opaque_node(iff)) { - // No OpaqueLoop* node? Then it's one of the two Initialized Assertion Predicates: - // - For the initial access a[init] - // - For the last access a[init+old_stride-orig_stride] - // We could keep the one for the initial access but we do not know which one we currently have here. Just kill both. - // We will create new Initialized Assertion Predicates from the Template Assertion Predicates below: + Node* bol = iff->in(1); + if (bol->is_Opaque4()) { + if (assertion_predicate_has_loop_opaque_node(iff)) { + // This is a Template Assertion Predicate for the initial or last access. + // Create an Initialized Assertion Predicates for it accordingly: // - For the initial access a[init] (same as before) // - For the last access a[init+new_stride-orig_stride] (with the new unroll stride) - _igvn.replace_input_of(iff, 1, iff->in(1)->in(2)); - } else { - // Template Assertion Predicate: Clone it to create initialized version with new stride. prev_proj = clone_assertion_predicate_and_initialize(iff, init, max_value, entry, proj, ctrl, outer_loop, prev_proj); assert(!assertion_predicate_has_loop_opaque_node(prev_proj->in(0)->as_If()), "unexpected"); + } else { + // Ignore Opaque4 from a non-null-check for an intrinsic or unsafe access. This could happen when we maximally + // unroll a non-main loop with such an If with an Opaque4 node directly above the loop entry. + assert(!loop_head->is_main_loop(), "Opaque4 node from a non-null check - should not be at main loop"); } + } else if (bol->is_OpaqueInitializedAssertionPredicate()) { + // This is one of the two Initialized Assertion Predicates: + // - For the initial access a[init] + // - For the last access a[init+old_stride-orig_stride] + // We could keep the one for the initial access but we do not know which one we currently have here. Just kill both. + _igvn.replace_input_of(iff, 1, _igvn.intcon(1)); } entry = entry->in(0)->in(0); } @@ -2006,13 +2019,15 @@ void PhaseIdealLoop::copy_assertion_predicates_to_post_loop(LoopNode* main_loop_ while (ctrl != nullptr && ctrl->is_Proj() && ctrl->in(0)->is_If()) { IfNode* iff = ctrl->in(0)->as_If(); ProjNode* proj = iff->proj_out(1 - ctrl->as_Proj()->_con); - if (proj->unique_ctrl_out()->Opcode() != Op_Halt) { + if (!proj->unique_ctrl_out()->is_Halt()) { break; } - if (iff->in(1)->Opcode() == Op_Opaque4 && assertion_predicate_has_loop_opaque_node(iff)) { + if (iff->in(1)->is_Opaque4()) { + // Initialize from Template Assertion Predicate. + assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes"); prev_proj = clone_assertion_predicate_and_initialize(iff, init, stride, ctrl, proj, post_loop_entry, post_loop, prev_proj); - assert(!assertion_predicate_has_loop_opaque_node(prev_proj->in(0)->as_If()), "unexpected"); + assert(!assertion_predicate_has_loop_opaque_node(prev_proj->in(0)->as_If()), "must not find OpaqueLoop* nodes"); } ctrl = ctrl->in(0)->in(0); } @@ -2043,8 +2058,11 @@ void PhaseIdealLoop::initialize_assertion_predicates_for_peeled_loop(const Predi // Does not belong to this Predicate Block anymore. break; } - if (iff->in(1)->Opcode() == Op_Opaque4) { - assert(assertion_predicate_has_loop_opaque_node(iff), "unexpected"); + Node* bol = iff->in(1); + assert(!bol->is_OpaqueInitializedAssertionPredicate(), "should not find an Initialized Assertion Predicate"); + if (bol->is_Opaque4()) { + // Initialize from Template Assertion Predicate. + assert(assertion_predicate_has_loop_opaque_node(iff), "must find OpaqueLoop* nodes"); input_proj = clone_assertion_predicate_and_initialize(iff, init, stride, next_regular_predicate_proj, uncommon_proj, control, outer_loop, input_proj); @@ -2767,20 +2785,25 @@ bool PhaseIdealLoop::is_scaled_iv_plus_extra_offset(Node* exp1, Node* offset3, N // Same as PhaseIdealLoop::duplicate_predicates() but for range checks // eliminated by iteration splitting. -Node* PhaseIdealLoop::add_range_check_elimination_assertion_predicate(IdealLoopTree* loop, - Node* ctrl, const int scale_con, - Node* offset, Node* limit, jint stride_con, - Node* value) { +Node* PhaseIdealLoop::add_range_check_elimination_assertion_predicate(IdealLoopTree* loop, Node* ctrl, + const int scale_con, Node* offset, Node* limit, + jint stride_con, Node* value, + const bool is_template) { bool overflow = false; BoolNode* bol = rc_predicate(ctrl, scale_con, offset, value, nullptr, stride_con, limit, (stride_con > 0) != (scale_con > 0), overflow); - Node* opaque_bol = new Opaque4Node(C, bol, _igvn.intcon(1)); - register_new_node(opaque_bol, ctrl); + Node* opaque_assertion_predicate; + if (is_template) { + opaque_assertion_predicate = new Opaque4Node(C, bol, _igvn.intcon(1)); + } else { + opaque_assertion_predicate = new OpaqueInitializedAssertionPredicateNode(bol, C); + } + register_new_node(opaque_assertion_predicate, ctrl); IfNode* new_iff = nullptr; if (overflow) { - new_iff = new IfNode(ctrl, opaque_bol, PROB_MAX, COUNT_UNKNOWN); + new_iff = new IfNode(ctrl, opaque_assertion_predicate, PROB_MAX, COUNT_UNKNOWN); } else { - new_iff = new RangeCheckNode(ctrl, opaque_bol, PROB_MAX, COUNT_UNKNOWN); + new_iff = new RangeCheckNode(ctrl, opaque_assertion_predicate, PROB_MAX, COUNT_UNKNOWN); } register_control(new_iff, loop->_parent, ctrl); Node* iffalse = new IfFalseNode(new_iff); @@ -2981,13 +3004,13 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { // Initialized Assertion Predicate for the value of the initial main-loop. loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset, - int_limit, stride_con, init); + int_limit, stride_con, init, false); assert(!assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); // Add two Template Assertion Predicates to create new Initialized Assertion Predicates from when either // unrolling or splitting this main-loop further. loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset, - int_limit, stride_con, opaque_init); + int_limit, stride_con, opaque_init, true); assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); Node* opaque_stride = new OpaqueLoopStrideNode(C, cl->stride()); @@ -3000,7 +3023,7 @@ void PhaseIdealLoop::do_range_check(IdealLoopTree *loop, Node_List &old_new) { max_value = new CastIINode(max_value, loop->_head->as_CountedLoop()->phi()->bottom_type()); register_new_node(max_value, loop_entry); loop_entry = add_range_check_elimination_assertion_predicate(loop, loop_entry, scale_con, int_offset, - int_limit, stride_con, max_value); + int_limit, stride_con, max_value, true); assert(assertion_predicate_has_loop_opaque_node(loop_entry->in(0)->as_If()), "unexpected"); } else { diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index fac7cf32f60..b877888fccb 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -4380,10 +4380,9 @@ void PhaseIdealLoop::collect_useful_template_assertion_predicates_for_loop(Ideal void PhaseIdealLoop::eliminate_useless_template_assertion_predicates(Unique_Node_List& useful_predicates) { for (int i = C->template_assertion_predicate_count(); i > 0; i--) { - Node* opaque4 = C->template_assertion_predicate_opaq_node(i - 1); - assert(opaque4->Opcode() == Op_Opaque4, "must be"); - if (!useful_predicates.member(opaque4)) { // not in the useful list - _igvn.replace_node(opaque4, opaque4->in(2)); + Opaque4Node* opaque4_node = C->template_assertion_predicate_opaq_node(i - 1)->as_Opaque4(); + if (!useful_predicates.member(opaque4_node)) { // not in the useful list + _igvn.replace_node(opaque4_node, opaque4_node->in(2)); } } } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index f7ba4578a51..ad603439e59 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1380,7 +1380,8 @@ class PhaseIdealLoop : public PhaseTransform { IfProjNode* upper_bound_proj, int scale, Node* offset, Node* init, Node* limit, jint stride, Node* rng, bool& overflow, Deoptimization::DeoptReason reason); Node* add_range_check_elimination_assertion_predicate(IdealLoopTree* loop, Node* predicate_proj, int scale_con, - Node* offset, Node* limit, jint stride_con, Node* value); + Node* offset, Node* limit, int stride_con, Node* value, + bool is_template); // Helper function to collect predicate for eliminating the useless ones void eliminate_useless_predicates(); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 25000f10000..200adc34494 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -779,8 +779,12 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { } }//for Node* bol = iff->in(1); - if (bol->Opcode() == Op_Opaque4) { - return nullptr; // Ignore loop predicate checks (the Opaque4 ensures they will go away) + assert(!bol->is_OpaqueInitializedAssertionPredicate(), "Initialized Assertion Predicates cannot form a diamond with Halt"); + if (bol->is_Opaque4()) { + // Ignore Template Assertion Predicates with Opaque4 nodes. + assert(assertion_predicate_has_loop_opaque_node(iff), + "must be Template Assertion Predicate, non-null-check with Opaque4 cannot form a diamond with Halt"); + return nullptr; } assert(bol->Opcode() == Op_Bool, "Unexpected node"); int cmp_op = bol->in(1)->Opcode(); @@ -1663,7 +1667,8 @@ void PhaseIdealLoop::try_sink_out_of_loop(Node* n) { !n->is_Proj() && !n->is_MergeMem() && !n->is_CMove() && - n->Opcode() != Op_Opaque4 && + !n->is_Opaque4() && + !n->is_OpaqueInitializedAssertionPredicate() && !n->is_Type()) { Node *n_ctrl = get_ctrl(n); IdealLoopTree *n_loop = get_loop(n_ctrl); @@ -1976,18 +1981,18 @@ Node* PhaseIdealLoop::clone_iff(PhiNode* phi) { // Convert this Phi into a Phi merging Bools uint i; for (i = 1; i < phi->req(); i++) { - Node *b = phi->in(i); + Node* b = phi->in(i); if (b->is_Phi()) { _igvn.replace_input_of(phi, i, clone_iff(b->as_Phi())); } else { - assert(b->is_Bool() || b->Opcode() == Op_Opaque4, ""); + assert(b->is_Bool() || b->is_Opaque4() || b->is_OpaqueInitializedAssertionPredicate(), + "bool, non-null check with Opaque4 node or Initialized Assertion Predicate with its Opaque node"); } } - Node* n = phi->in(1); Node* sample_opaque = nullptr; Node *sample_bool = nullptr; - if (n->Opcode() == Op_Opaque4) { + if (n->is_Opaque4() || n->is_OpaqueInitializedAssertionPredicate()) { sample_opaque = n; sample_bool = n->in(1); assert(sample_bool->is_Bool(), "wrong type"); @@ -2160,7 +2165,7 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new, // make sure the Bool/Cmp input is cloned down to avoid a Phi between // the AllocateArray node and its ValidLengthTest input that could cause // split if to break. - if (use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque4 || + if (use->is_If() || use->is_CMove() || use->is_Opaque4() || (use->Opcode() == Op_AllocateArray && use->in(AllocateNode::ValidLengthTest) == old)) { // Since this code is highly unlikely, we lazily build the worklist // of such Nodes to go split. diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 2a26a4ebed3..ce1a8a61134 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -2429,7 +2429,8 @@ void PhaseMacroExpand::eliminate_macro_nodes() { default: assert(n->Opcode() == Op_LoopLimit || n->Opcode() == Op_Opaque3 || - n->Opcode() == Op_Opaque4 || + n->is_Opaque4() || + n->is_OpaqueInitializedAssertionPredicate() || n->Opcode() == Op_MaxL || n->Opcode() == Op_MinL || BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(n), @@ -2504,7 +2505,7 @@ bool PhaseMacroExpand::expand_macro_nodes() { _igvn.replace_node(n, repl); success = true; #endif - } else if (n->Opcode() == Op_Opaque4) { + } else if (n->is_Opaque4()) { // With Opaque4 nodes, the expectation is that the test of input 1 // is always equal to the constant value of input 2. So we can // remove the Opaque4 and replace it by input 2. In debug builds, @@ -2517,6 +2518,17 @@ bool PhaseMacroExpand::expand_macro_nodes() { _igvn.replace_node(n, n->in(2)); #endif success = true; + } else if (n->is_OpaqueInitializedAssertionPredicate()) { + // Initialized Assertion Predicates must always evaluate to true. Therefore, we get rid of them in product + // builds as they are useless. In debug builds we keep them as additional verification code. Even though + // loop opts are already over, we want to keep Initialized Assertion Predicates alive as long as possible to + // enable folding of dead control paths within which cast nodes become top after due to impossible types - + // even after loop opts are over. Therefore, we delay the removal of these opaque nodes until now. +#ifdef ASSERT + _igvn.replace_node(n, n->in(1)); +#else + _igvn.replace_node(n, _igvn.intcon(1)); +#endif // ASSERT } else if (n->Opcode() == Op_OuterStripMinedLoop) { n->as_OuterStripMinedLoop()->adjust_strip_mined_loop(&_igvn); C->remove_macro_node(n); diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index fa85344d0da..d290541dffa 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -610,7 +610,7 @@ void Node::destruct(PhaseValues* phase) { if (is_expensive()) { compile->remove_expensive_node(this); } - if (Opcode() == Op_Opaque4) { + if (is_Opaque4()) { compile->remove_template_assertion_predicate_opaq(this); } if (is_ParsePredicate()) { diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 314f165ac8b..dc9dc6654b5 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -138,6 +138,7 @@ class Opaque1Node; class OpaqueLoopInitNode; class OpaqueLoopStrideNode; class Opaque4Node; +class OpaqueInitializedAssertionPredicateNode; class OuterStripMinedLoopNode; class OuterStripMinedLoopEndNode; class Node; @@ -797,9 +798,10 @@ class Node { DEFINE_CLASS_ID(OpaqueLoopInit, Opaque1, 0) DEFINE_CLASS_ID(OpaqueLoopStride, Opaque1, 1) DEFINE_CLASS_ID(Opaque4, Node, 17) - DEFINE_CLASS_ID(Move, Node, 18) - DEFINE_CLASS_ID(LShift, Node, 19) - DEFINE_CLASS_ID(Neg, Node, 20) + DEFINE_CLASS_ID(OpaqueInitializedAssertionPredicate, Node, 18) + DEFINE_CLASS_ID(Move, Node, 19) + DEFINE_CLASS_ID(LShift, Node, 20) + DEFINE_CLASS_ID(Neg, Node, 21) _max_classes = ClassMask_Neg }; @@ -968,6 +970,7 @@ class Node { DEFINE_CLASS_QUERY(NeverBranch) DEFINE_CLASS_QUERY(Opaque1) DEFINE_CLASS_QUERY(Opaque4) + DEFINE_CLASS_QUERY(OpaqueInitializedAssertionPredicate) DEFINE_CLASS_QUERY(OpaqueLoopInit) DEFINE_CLASS_QUERY(OpaqueLoopStride) DEFINE_CLASS_QUERY(OuterStripMinedLoop) diff --git a/src/hotspot/share/opto/opaquenode.cpp b/src/hotspot/share/opto/opaquenode.cpp index 5075ccd4664..0abc6f86ed0 100644 --- a/src/hotspot/share/opto/opaquenode.cpp +++ b/src/hotspot/share/opto/opaquenode.cpp @@ -102,6 +102,10 @@ const Type* Opaque4Node::Value(PhaseGVN* phase) const { return phase->type(in(1)); } +const Type* OpaqueInitializedAssertionPredicateNode::Value(PhaseGVN* phase) const { + return phase->type(in(1)); +} + //============================================================================= uint ProfileBooleanNode::hash() const { return NO_HASH; } diff --git a/src/hotspot/share/opto/opaquenode.hpp b/src/hotspot/share/opto/opaquenode.hpp index 12a95ce2edb..2337989e974 100644 --- a/src/hotspot/share/opto/opaquenode.hpp +++ b/src/hotspot/share/opto/opaquenode.hpp @@ -121,17 +121,32 @@ class Opaque3Node : public Node { // GraphKit::must_be_not_null(). class Opaque4Node : public Node { public: - Opaque4Node(Compile* C, Node *tst, Node* final_tst) : Node(nullptr, tst, final_tst) { + Opaque4Node(Compile* C, Node* tst, Node* final_tst) : Node(nullptr, tst, final_tst) { init_class_id(Class_Opaque4); init_flags(Flag_is_macro); C->add_macro_node(this); } virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::BOOL; } virtual const Type* Value(PhaseGVN* phase) const; + virtual const Type* bottom_type() const { return TypeInt::BOOL; } }; +// This node is used for Initialized Assertion Predicate BoolNodes. Initialized Assertion Predicates must always evaluate +// to true. Therefore, we get rid of them in product builds during macro expansion as they are useless. In debug builds +// we keep them as additional verification code (i.e. removing this node and use the BoolNode input instead). +class OpaqueInitializedAssertionPredicateNode : public Node { + public: + OpaqueInitializedAssertionPredicateNode(BoolNode* bol, Compile* C) : Node(nullptr, bol) { + init_class_id(Class_OpaqueInitializedAssertionPredicate); + init_flags(Flag_is_macro); + C->add_macro_node(this); + } + + virtual int Opcode() const; + virtual const Type* Value(PhaseGVN* phase) const; + virtual const Type* bottom_type() const { return TypeInt::BOOL; } +}; //------------------------------ProfileBooleanNode------------------------------- // A node represents value profile for a boolean during parsing. diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 7f873e1fb6f..9f782f34bdb 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -42,13 +42,15 @@ bool AssertionPredicatesWithHalt::is_assertion_predicate_success_proj(const Node if (predicate_proj == nullptr || !predicate_proj->is_IfProj() || !predicate_proj->in(0)->is_If()) { return false; } - return has_opaque4(predicate_proj) && has_halt(predicate_proj); + return has_assertion_predicate_opaque(predicate_proj) && has_halt(predicate_proj); } -// Check if the If node of `predicate_proj` has an Opaque4 node as input. -bool AssertionPredicatesWithHalt::has_opaque4(const Node* predicate_proj) { +// Check if the If node of `predicate_proj` has an Opaque4 (Template Assertion Predicate) or an +// OpaqueInitializedAssertionPredicate (Initialized Assertion Predicate) node as input. +bool AssertionPredicatesWithHalt::has_assertion_predicate_opaque(const Node* predicate_proj) { IfNode* iff = predicate_proj->in(0)->as_If(); - return iff->in(1)->Opcode() == Op_Opaque4; + Node* bol = iff->in(1); + return bol->is_Opaque4() || bol->is_OpaqueInitializedAssertionPredicate(); } // Check if the other projection (UCT projection) of `success_proj` has a Halt node as output. diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index 670ca58cc47..bf12aeb6a51 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -199,7 +199,7 @@ class AssertionPredicatesWithHalt : public StackObj { Node* _entry; static Node* find_entry(Node* start_proj); - static bool has_opaque4(const Node* predicate_proj); + static bool has_assertion_predicate_opaque(const Node* predicate_proj); static bool has_halt(const Node* success_proj); static bool is_assertion_predicate_success_proj(const Node* predicate_proj); diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index 70369a2c9c4..ad4053e2c98 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -322,7 +322,7 @@ bool PhaseIdealLoop::clone_cmp_down(Node* n, const Node* blk1, const Node* blk2) assert( bol->is_Bool(), "" ); if (bol->outcnt() == 1) { Node* use = bol->unique_out(); - if (use->Opcode() == Op_Opaque4) { + if (use->is_Opaque4() || use->is_OpaqueInitializedAssertionPredicate()) { if (use->outcnt() == 1) { Node* iff = use->unique_out(); assert(iff->is_If(), "unexpected node type"); @@ -351,8 +351,8 @@ bool PhaseIdealLoop::clone_cmp_down(Node* n, const Node* blk1, const Node* blk2) #endif for (DUIterator j = bol->outs(); bol->has_out(j); j++) { Node* u = bol->out(j); - // Uses are either IfNodes, CMoves or Opaque4 - if (u->Opcode() == Op_Opaque4) { + // Uses are either IfNodes, CMoves, Opaque4, or OpaqueInitializedAssertionPredicates + if (u->is_Opaque4() || u->is_OpaqueInitializedAssertionPredicate()) { assert(u->in(1) == bol, "bad input"); for (DUIterator_Last kmin, k = u->last_outs(kmin); k >= kmin; --k) { Node* iff = u->last_out(k); diff --git a/test/hotspot/jtreg/compiler/predicates/assertion/TestOpaqueInitializedAssertionPredicateNode.java b/test/hotspot/jtreg/compiler/predicates/assertion/TestOpaqueInitializedAssertionPredicateNode.java new file mode 100644 index 00000000000..8fb9e693eb6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/predicates/assertion/TestOpaqueInitializedAssertionPredicateNode.java @@ -0,0 +1,407 @@ +/* + * 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 8330386 + * @summary Test that replacing Opaque4 nodes with OpaqueInitializedAssertionPredicate for Initialized Assertion Predicates + * works. We test following cases explicitly: + * 1) Cloning down CmpUNode in Split If with involved OpaqueInitializedAssertionPredicateNodes + * 2) Special casing OpaqueInitializedAssertionPredicate in IdealLoopTree::policy_range_check() + * 3) Special casing Opaque4 node from non-null check for intrinsics and unsafe accesses inside + * PhaseIdealLoop::update_main_loop_assertion_predicates(). + * @requires vm.compiler2.enabled + * @modules java.base/jdk.internal.misc:+open + * @run main/othervm -Xbatch -XX:LoopMaxUnroll=0 + * -XX:CompileCommand=compileonly,*TestOpaqueInitializedAssertionPredicateNode::test* + * -XX:CompileCommand=dontinline,*TestOpaqueInitializedAssertionPredicateNode::dontInline + * compiler.predicates.assertion.TestOpaqueInitializedAssertionPredicateNode + * @run main/othervm -Xcomp -XX:LoopMaxUnroll=0 -XX:-LoopUnswitching + * -XX:CompileCommand=compileonly,*TestOpaqueInitializedAssertionPredicateNode::test* + * -XX:CompileCommand=dontinline,*TestOpaqueInitializedAssertionPredicateNode::dontInline + * compiler.predicates.assertion.TestOpaqueInitializedAssertionPredicateNode + * @run main/othervm -Xbatch -XX:LoopMaxUnroll=0 -XX:PerMethodTrapLimit=0 + * -XX:CompileCommand=compileonly,*TestOpaqueInitializedAssertionPredicateNode::test* + * -XX:CompileCommand=dontinline,*TestOpaqueInitializedAssertionPredicateNode::dontInline + * compiler.predicates.assertion.TestOpaqueInitializedAssertionPredicateNode + */ + +/* + * @test id=noflags + * @bug 8330386 + * @modules java.base/jdk.internal.misc:+open + * @run main compiler.predicates.assertion.TestOpaqueInitializedAssertionPredicateNode + */ + +package compiler.predicates.assertion; + +import jdk.internal.misc.Unsafe; +import java.lang.reflect.Field; + +public class TestOpaqueInitializedAssertionPredicateNode { + + static boolean flag, flag2; + static int iFld; + static int x; + static int y = 51; + static int iArrLength; + static int[] iArr = new int[100]; + + static final Unsafe UNSAFE = Unsafe.getUnsafe(); + static final long OFFSET; + + static { + try { + Field fieldIFld = A.class.getDeclaredField("iFld"); + OFFSET = UNSAFE.objectFieldOffset(fieldIFld); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void main(String[] args) { + Integer.compareUnsigned(23, 34); // Make sure loaded with -Xcomp. + A a = new A(34); + for (int i = 0; i < 10000; i++) { + iArrLength = i % 15 == 0 ? 30 : 100; + flag = i % 3 == 0; + flag2 = i % 5 == 0; + x = (i % 15 == 0 ? 100 : 0); + testCloneDown(); + testOnlyCloneDownCmp(); + testCloneDownInsideLoop(); + maybeNull(null); // Make sure return value is sometimes null. + testPolicyRangeCheck(a); + testUnsafeAccess(a); + testOpaqueOutsideLoop(); + testOpaqueInsideIfOutsideLoop(); + } + } + + // Profiling will tell us that the return value is sometimes null and sometimes not. + static A maybeNull(Object o) { + return (A)o; + } + + static void testCloneDown() { + int a; + int b; + int[] iArr = new int[iArrLength]; + + for (int i = 2; i < 4; i *= 2) ; // Make sure to run with loop opts. + + if (flag) { + a = 34; + } else { + a = 3; + } + // Region to split through + + // --- BLOCK start --- + + // CMoveI(Bool(CmpU(y, iArr.length))), 34, 23) (**) + if (Integer.compareUnsigned(y, iArr.length) < 0) { + b = 34; + } else { + b = 23; + } + iFld = b; // iFld = CMoveI -> make sure CMoveI is inside BLOCK + + // --- BLOCK end --- + + if (a > 23) { // If to split -> need to empty BLOCK + iFld = 34; + } + + if (flag2) { + // Avoid out-of-bounds access in loop below + return; + } + + // When peeling the loop, we create an Initialized Assertion Predicate with the same CmpU as (**) above: + // IAP(CmpU(y, iArr.length)) + // + // At Split If: Need to clone CmpU down because it has two uses: + // - Bool of Cmove used in "iFld = b" + // - Bool for IAP + // + // => IAP uses OpaqueInitializedAssertionPredicate -> clone_cmp_down() therefore needs to handle that. + for (int i = y - 1; i < 100; i++) { + iArr[i] = 34; // Hoisted with Loop Predicate + if (flag) { // Reason to peel. + return; + } + } + } + + // Same as test() but we only clone down the CmpU and not the Bool with the OpaqueInitializedAssertionPredicate + static void testOnlyCloneDownCmp() { + int a; + int b; + int[] iArr = new int[iArrLength]; + + for (int i = 2; i < 4; i *= 2) ; // Make sure to run with loop opts. + + if (flag) { + a = 34; + } else { + a = 3; + } + // Region to split through + + // --- BLOCK start --- + + // CMoveI(Bool(CmpU(51, iArr.length))), 34, 23) (**) + // Using constant 51 -> cannot common up with Bool from Initialized Assertion Predicate + if (Integer.compareUnsigned(51, iArr.length) < 0) { + b = 34; + } else { + b = 23; + } + iFld = b; // iFld = CMoveI -> make sure CMoveI is inside BLOCK + + // --- BLOCK end --- + + if (a > 23) { // If to split -> need to empty BLOCK + iFld = 34; + } + + if (flag2) { + // Avoid out-of-bounds access in loop below + return; + } + + // When peeling the loop, we create an Initialized Assertion Predicate with the same CmpU as (**) above: + // IAP(CmpU(y, iArr.length)) + // + // At Split If: Need to clone CmpU down because it has two uses: + // - Bool of Cmove used in "iFld = b" + // - Bool for IAP + // + // => IAP uses OpaqueInitializedAssertionPredicate -> clone_cmp_down() therefore needs to handle that. + for (int i = 50; i < 100; i++) { + iArr[i] = 34; // Hoisted with Loop Predicate + if (flag) { // Reason to peel. + return; + } + } + } + + // Same as test() but everything inside another loop. + static void testCloneDownInsideLoop() { + int a; + int b; + int[] iArr = new int[iArrLength]; + + for (int i = 3; i < 30; i *= 2) { // Non-counted loop + if (i < 10) { + a = 34; + } else { + a = 3; + } + // Region to split through + + // --- BLOCK start --- + + // CMoveI(Bool(CmpU(a + i, iArr.length))), 34, 23) (**) + if (Integer.compareUnsigned(a + i, iArr.length) < 0) { + b = 34; + } else { + b = 23; + } + iFld = b; // iFld = CMoveI -> make sure CMoveI is inside BLOCK + + // --- BLOCK end --- + + if (a > 23) { // If to split -> need to empty BLOCK + iFld = 34; + } + + if (i < x) { + // Avoid out-of-bounds access in loop below + return; + } + + // When peeling the loop, we create an Initialized Assertion Predicate with the same CmpU as (**) above: + // IAP(CmpU(a + i, iArr.length)) + // + // At Split If: Need to clone CmpU down because it has two uses: + // - Bool of Cmove used in "iFld = b" + // - Bool for IAP + // + // => IAP uses OpaqueInitializedAssertionPredicate -> clone_cmp_down() therefore needs to handle that. + for (int j = a + i - 1; j < 100; j++) { + iArr[j] = 34; // Hoisted with Loop Predicate + if (flag) { // Reason to peel. + return; + } + } + } + } + + static void testPolicyRangeCheck(Object o) { + int two = 100; + int limit = 2; + for (; limit < 4; limit *= 2); + for (int i = 2; i < limit; i++) { + two = 2; + } + + // 4) We call IdealLoopTree::policy_range_check() for this loop: + // - Initialized Assertion Predicate is now part of loop body. + // - Opaque4 node for null-check is also part of loop body. + // We also check the If nodes for these Opaque nodes could be eliminated with + // Range Check Elimination. We thus need to exclude Ifs with + // Opaque4 and OpaqueInitializedAssertionPredicate nodes in policy_range_check(). + for (int i = 0; i < 100; i++) { + A a = maybeNull(o); // Profiling tells us that return value *might* be null. + iFld = UNSAFE.getInt(a, OFFSET); // Emits If with Opaque4Node for null check. + + // 1) Apply Loop Predication: Loop Predicate + Template Assertion Predicate + // 2) Apply Loop Peeling: Create Initialized Assertion Predicate with + // OpaqueInitializedAssertionPredicate + // 3) After CCP: C2 knows that two == 2. CountedLoopEnd found to be true + // (only execute loop once) -> CountedLoop removed + for (int j = 0; j < two; j++) { + iArr[j] = 34; // Hoisted in Loop Predication + if (flag) { + return; + } + } + } + } + + static void testUnsafeAccess(Object o) { + A a = maybeNull(o); // Profiling tells us that return value *might* be null. + iFld = UNSAFE.getInt(a, OFFSET); // Emits If with Opaque4Node for null check. + + // We don't have any Parse Predicates with -XX:PerMethodTrapLimit=0. And therefore, If with Opaque4 will + // directly be above CountedLoop. When maximally unrolling the counted loop, we try to update any Assertion + // Predicate. We will find the If with the Opaque4 node for the non-null check which is not an Assertion + // Predicate. This needs to be handled separately in PhaseIdealLoop::update_main_loop_assertion_predicates(). + for (int i = 0; i < 10; i++) { + iFld *= 34; + } + } + + // [If->OpaqueInitializedAssertionPredicate]->Bool->Cmp, []: Inside Loop, other nodes outside. + static void testOpaqueOutsideLoop() { + int two = 100; + int limit = 2; + for (; limit < 4; limit *= 2); + for (int i = 2; i < limit; i++) { + two = 2; + } + + // 4) After CCP, we can apply Loop Peeling since we removed enough nodes to bring the body size down below 255. + // When cloning the Bool for the IAP, we have a use inside the loop (initializedAssertionPredicateBool) and one + // outside for the IAP (input to the OpaqueInitializedAssertionPredicate being outside the loop) + // As a result, we add the OpaqueInitializedAssertionPredicate to the split if set in clone_loop_handle_data_uses(). + for (short i = 3; i < 30; i*=2) { // Use short such that we do not need overflow protection for Loop Predicates + if (two == 100) { + // Before CCP: Uninlined method call prevents peeling. + // After CCP: C2 knows that two == 2 and we remove this call which enables Loop Peeling for i-loop. + dontInline(); + } + + // Same condition as used for IAP in j-loop below. + boolean initializedAssertionPredicateBool = Integer.compareUnsigned(1 + i, iArr.length) < 0; + + if (flag) { + // 1) Loop Predicate + Template Assertion Predicate + // 2) Loop Peeling: Create IAP with same condition as initializedAssertionPredicateBool -> can be shared. + // The IAP is on a loop-exit and therefore outside the loop. + // 3) After CCP: C2 knows that two == 2 and loop is removed. + for (short j = 0; j < two; j++) { + iArr[i + j] = 34; // Hoisted in Loop Predication + if (flag2) { + break; + } + } + break; + } + + // Use Bool inside i-loop such that when applying Loop Peeling for i-loop, ctrl of Bool is inside loop and + // OpaqueInitializedAssertionPredicate of IAP is outside of i-loop. + if (initializedAssertionPredicateBool) { + iFld = 3; + } + } + } + + // Similar to testOpaqueOutside loop but Opaque is now also inside loop. + // [If]->OpaqueInitializedAssertionPredicate->Bool->Cmp, []: Inside Loop, other nodes outside. + static void testOpaqueInsideIfOutsideLoop() { + int two = 100; + int limit = 2; + for (; limit < 4; limit *= 2); + for (int i = 2; i < limit; i++) { + two = 2; + } + + for (short i = 3; i < 30; i*=2) { + if (two == 100) { + // Before CCP: Uninlined method call prevents peeling. + // After CCP: C2 knows that two == 2 and we remove this call which enables Loop Peeling for i-loop. + dontInline(); + } + + // 1) Loop Predicate + Template Assertion Predicate + // 2) Loop Peeling: Create IAP with same condition as initializedAssertionPredicateBool -> can be shared. + // The IAP is on a loop-exit and therefore outside the loop. + // 3) After CCP: C2 knows that two == 2 and loop is removed. + for (short j = 0; j < two; j++) { + iArr[i + j] = 34; // Hoisted in Loop Predication + if (flag2) { + break; + } + } + + if (flag) { + // Same loop as above. We create the same IAP which can share the same OpaqueInitializedAssertionPredicate. + // Therefore, the OpaqueInitializedAssertionPredicate is inside the loop while this If is outside the loop. + // At Loop Peeling, we clone the Opaque node and create a Phi to merge both loop versions into the IAP If. In + // clone_loop_handle_data_uses(), we add the If for the IAP to the split if set in (). Later, we + // process its input phi with their OpaqueInitializedAssertionPredicate inputs. + for (short j = 0; j < two; j++) { + iArr[i + j] = 34; // Hoisted in Loop Predication + if (flag2) { + break; + } + } + break; + } + } + } + + // Not inlined + static void dontInline() {} + + static class A { + int iFld; + A(int i) { + this.iFld = i; + } + } +} From cabe337400a0bd61d73bf3ca66e16266267299c7 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 28 May 2024 11:37:36 +0000 Subject: [PATCH 69/99] 8331921: Hotspot assembler files should use common logic to setup exported functions Reviewed-by: coleenp, erikj, dholmes --- make/hotspot/lib/CompileJvm.gmk | 6 ++ src/hotspot/os/bsd/defs.S.inc | 40 +++++++++++ src/hotspot/os/posix/defs.S.inc | 31 ++++++++ .../os_cpu/bsd_aarch64/copy_bsd_aarch64.S | 17 ++--- src/hotspot/os_cpu/bsd_aarch64/defs.S.inc | 40 +++++++++++ .../bsd_aarch64/safefetch_bsd_aarch64.S | 39 ++-------- src/hotspot/os_cpu/bsd_x86/bsd_x86_32.S | 72 ++++--------------- src/hotspot/os_cpu/bsd_x86/bsd_x86_64.S | 53 +++----------- .../os_cpu/bsd_x86/safefetch_bsd_x86_64.S | 39 ++-------- .../linux_aarch64/atomic_linux_aarch64.S | 67 +++++------------ .../os_cpu/linux_aarch64/copy_linux_aarch64.S | 10 ++- .../linux_aarch64/safefetch_linux_aarch64.S | 26 ++----- .../linux_aarch64/threadLS_linux_aarch64.S | 9 ++- src/hotspot/os_cpu/linux_arm/linux_arm_32.S | 52 +++----------- .../os_cpu/linux_arm/safefetch_linux_arm.S | 16 ++--- .../os_cpu/linux_ppc/safefetch_linux_ppc.S | 26 ++----- .../linux_riscv/safefetch_linux_riscv.S | 26 ++----- .../os_cpu/linux_s390/safefetch_linux_s390.S | 26 ++----- src/hotspot/os_cpu/linux_x86/linux_x86_32.S | 56 +++------------ src/hotspot/os_cpu/linux_x86/linux_x86_64.S | 44 +++--------- .../os_cpu/linux_x86/safefetch_linux_x86_32.S | 14 ++-- .../os_cpu/linux_x86/safefetch_linux_x86_64.S | 28 ++------ 22 files changed, 257 insertions(+), 480 deletions(-) create mode 100644 src/hotspot/os/bsd/defs.S.inc create mode 100644 src/hotspot/os/posix/defs.S.inc create mode 100644 src/hotspot/os_cpu/bsd_aarch64/defs.S.inc diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index c2ff0064025..ad374d57cee 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -47,6 +47,12 @@ JVM_LDFLAGS += \ JVM_ASFLAGS += $(EXTRA_ASFLAGS) +JVM_ASFLAGS += \ + -I$(TOPDIR)/src/hotspot/os_cpu/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH) \ + -I$(TOPDIR)/src/hotspot/os/$(HOTSPOT_TARGET_OS) \ + -I$(TOPDIR)/src/hotspot/os/$(HOTSPOT_TARGET_OS_TYPE) \ + # + JVM_LIBS += \ $(JVM_LIBS_FEATURES) \ # diff --git a/src/hotspot/os/bsd/defs.S.inc b/src/hotspot/os/bsd/defs.S.inc new file mode 100644 index 00000000000..0d6950631a5 --- /dev/null +++ b/src/hotspot/os/bsd/defs.S.inc @@ -0,0 +1,40 @@ +# +# 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. +# + +#ifdef __APPLE__ + # macOS prefixes symbols with _ + #define SYMBOL(s) _ ## s + + #define DECLARE_FUNC(func) \ + .globl SYMBOL(func) ; \ + .private_extern SYMBOL(func) ; \ + SYMBOL(func) +#else + #define SYMBOL(s) s + + #define DECLARE_FUNC(func) \ + .globl func ; \ + .hidden func ; \ + .type func, %function ; \ + func +#endif diff --git a/src/hotspot/os/posix/defs.S.inc b/src/hotspot/os/posix/defs.S.inc new file mode 100644 index 00000000000..ec8c4994699 --- /dev/null +++ b/src/hotspot/os/posix/defs.S.inc @@ -0,0 +1,31 @@ +# +# Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# Used to get a reference to a symbol. (Overridden by macOS.) +#define SYMBOL(s) s + +#define DECLARE_FUNC(func) \ + .globl func ; \ + .hidden func ; \ + .type func, %function ; \ + func diff --git a/src/hotspot/os_cpu/bsd_aarch64/copy_bsd_aarch64.S b/src/hotspot/os_cpu/bsd_aarch64/copy_bsd_aarch64.S index 187cd20ddbd..a2099f39c70 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/copy_bsd_aarch64.S +++ b/src/hotspot/os_cpu/bsd_aarch64/copy_bsd_aarch64.S @@ -1,6 +1,7 @@ /* * Copyright (c) 2016, Linaro Ltd. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,15 +24,7 @@ * */ -#define CFUNC(x) _##x - - .global CFUNC(_Copy_conjoint_words) - .global CFUNC(_Copy_disjoint_words) - -#ifdef __APPLE__ - .private_extern CFUNC(_Copy_conjoint_words) - .private_extern CFUNC(_Copy_disjoint_words) -#endif +#include "defs.S.inc" s .req x0 d .req x1 @@ -46,7 +39,7 @@ t6 .req x9 t7 .req x10 .align 6 -CFUNC(_Copy_disjoint_words): +DECLARE_FUNC(_Copy_disjoint_words): // Ensure 2 word aligned tbz s, #3, fwd_copy_aligned ldr t0, [s], #8 @@ -144,10 +137,10 @@ fwd_copy_drain: ret .align 6 -CFUNC(_Copy_conjoint_words): +DECLARE_FUNC(_Copy_conjoint_words): sub t0, d, s cmp t0, count, lsl #3 - bhs CFUNC(_Copy_disjoint_words) + bhs SYMBOL(_Copy_disjoint_words) add s, s, count, lsl #3 add d, d, count, lsl #3 diff --git a/src/hotspot/os_cpu/bsd_aarch64/defs.S.inc b/src/hotspot/os_cpu/bsd_aarch64/defs.S.inc new file mode 100644 index 00000000000..717568380a9 --- /dev/null +++ b/src/hotspot/os_cpu/bsd_aarch64/defs.S.inc @@ -0,0 +1,40 @@ +# +# 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. +# + +#ifdef __APPLE__ + # macOS prefixes symbols with _ + #define SYMBOL(s) _ ## s + + #define DECLARE_FUNC(func) \ + .globl SYMBOL(func) %% \ + .private_extern SYMBOL(func) %% \ + SYMBOL(func) +#else + #define SYMBOL(s) s + + #define DECLARE_FUNC(func) \ + .globl func %% \ + .hidden func %% \ + .type func, %function %% \ + func +#endif diff --git a/src/hotspot/os_cpu/bsd_aarch64/safefetch_bsd_aarch64.S b/src/hotspot/os_cpu/bsd_aarch64/safefetch_bsd_aarch64.S index b9b6df9b23a..7cb2b69d955 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/safefetch_bsd_aarch64.S +++ b/src/hotspot/os_cpu/bsd_aarch64/safefetch_bsd_aarch64.S @@ -23,30 +23,7 @@ * */ -#ifdef __APPLE__ -# Darwin uses _ prefixed global symbols -#define SYMBOL(s) _ ## s -#define ELF_TYPE(name, description) -#else -#define SYMBOL(s) s -#define ELF_TYPE(name, description) .type name,description -#endif - - .global SYMBOL(SafeFetchN_impl) - .global SYMBOL(_SafeFetchN_fault) - .global SYMBOL(_SafeFetchN_continuation) - .global SYMBOL(SafeFetch32_impl) - .global SYMBOL(_SafeFetch32_fault) - .global SYMBOL(_SafeFetch32_continuation) - -#ifdef __APPLE__ - .private_extern SYMBOL(SafeFetchN_impl) - .private_extern SYMBOL(_SafeFetchN_fault) - .private_extern SYMBOL(_SafeFetchN_continuation) - .private_extern SYMBOL(SafeFetch32_impl) - .private_extern SYMBOL(_SafeFetch32_fault) - .private_extern SYMBOL(_SafeFetch32_continuation) -#endif +#include "defs.S.inc" # Support for int SafeFetch32(int* address, int defaultval); # @@ -55,12 +32,11 @@ # needed to align function start to 4 byte .align 6 - ELF_TYPE(SafeFetch32_impl,@function) -SYMBOL(SafeFetch32_impl): -SYMBOL(_SafeFetch32_fault): +DECLARE_FUNC(SafeFetch32_impl): +DECLARE_FUNC(_SafeFetch32_fault): ldr w0, [x0] ret -SYMBOL(_SafeFetch32_continuation): +DECLARE_FUNC(_SafeFetch32_continuation): mov x0, x1 ret @@ -70,11 +46,10 @@ SYMBOL(_SafeFetch32_continuation): # x0 : defaultval .align 6 - ELF_TYPE(SafeFetchN_impl,@function) -SYMBOL(SafeFetchN_impl): -SYMBOL(_SafeFetchN_fault): +DECLARE_FUNC(SafeFetchN_impl): +DECLARE_FUNC(_SafeFetchN_fault): ldr x0, [x0] ret -SYMBOL(_SafeFetchN_continuation): +DECLARE_FUNC(_SafeFetchN_continuation): mov x0, x1 ret diff --git a/src/hotspot/os_cpu/bsd_x86/bsd_x86_32.S b/src/hotspot/os_cpu/bsd_x86/bsd_x86_32.S index 5cad379df3f..7d8892bcd87 100644 --- a/src/hotspot/os_cpu/bsd_x86/bsd_x86_32.S +++ b/src/hotspot/os_cpu/bsd_x86/bsd_x86_32.S @@ -21,18 +21,7 @@ # questions. # - -#ifdef __APPLE__ -# Darwin uses _ prefixed global symbols -#define SYMBOL(s) _ ## s -#define ELF_TYPE(name, description) -#else -#define SYMBOL(s) s -#define ELF_TYPE(name, description) .type name,description -#endif - - .globl SYMBOL(fixcw) - .globl SYMBOL(SpinPause) +#include "defs.S.inc" # NOTE WELL! The _Copy functions are called directly # from server-compiler-generated code via CallLeafNoFP, @@ -40,46 +29,18 @@ # point or use it in the same manner as does the server # compiler. - .globl SYMBOL(_Copy_arrayof_conjoint_bytes) - .globl SYMBOL(_Copy_conjoint_jshorts_atomic) - .globl SYMBOL(_Copy_arrayof_conjoint_jshorts) - .globl SYMBOL(_Copy_conjoint_jints_atomic) - .globl SYMBOL(_Copy_arrayof_conjoint_jints) - .globl SYMBOL(_Copy_conjoint_jlongs_atomic) - .globl SYMBOL(_mmx_Copy_arrayof_conjoint_jshorts) - - .globl SYMBOL(_Atomic_cmpxchg_long) - .globl SYMBOL(_Atomic_move_long) - -#ifdef __APPLE__ - .private_extern SYMBOL(fixcw) - .private_extern SYMBOL(SpinPause) - .private_extern SYMBOL(_Copy_arrayof_conjoint_bytes) - .private_extern SYMBOL(_Copy_conjoint_jshorts_atomic) - .private_extern SYMBOL(_Copy_arrayof_conjoint_jshorts) - .private_extern SYMBOL(_Copy_conjoint_jints_atomic) - .private_extern SYMBOL(_Copy_arrayof_conjoint_jints) - .private_extern SYMBOL(_Copy_conjoint_jlongs_atomic) - .private_extern SYMBOL(_mmx_Copy_arrayof_conjoint_jshorts) - .private_extern SYMBOL(_Atomic_cmpxchg_long) - .private_extern SYMBOL(_Atomic_move_long) -#endif - .text -# Support for void os::Solaris::init_thread_fpu_state() in os_solaris_i486.cpp # Set fpu to 53 bit precision. This happens too early to use a stub. -# ported from solaris_x86_32.s .p2align 4,,15 -SYMBOL(fixcw): +DECLARE_FUNC(fixcw): pushl $0x27f fldcw 0(%esp) popl %eax ret - ELF_TYPE(SpinPause,@function) .p2align 4,,15 -SYMBOL(SpinPause): +DECLARE_FUNC(SpinPause): rep nop movl $1, %eax @@ -90,8 +51,7 @@ SYMBOL(SpinPause): # size_t count) # .p2align 4,,15 - ELF_TYPE(_Copy_arrayof_conjoint_bytes,@function) -SYMBOL(_Copy_arrayof_conjoint_bytes): +DECLARE_FUNC(_Copy_arrayof_conjoint_bytes): pushl %esi movl 4+12(%esp),%ecx # count pushl %edi @@ -178,8 +138,7 @@ acb_CopyLeft: # void* to, # size_t count) .p2align 4,,15 - ELF_TYPE(_Copy_conjoint_jshorts_atomic,@function) -SYMBOL(_Copy_conjoint_jshorts_atomic): +DECLARE_FUNC(_Copy_conjoint_jshorts_atomic): pushl %esi movl 4+12(%esp),%ecx # count pushl %edi @@ -265,8 +224,7 @@ cs_CopyLeft: # void* to, # size_t count) .p2align 4,,15 - ELF_TYPE(_Copy_arrayof_conjoint_jshorts,@function) -SYMBOL(_Copy_arrayof_conjoint_jshorts): +DECLARE_FUNC(_Copy_arrayof_conjoint_jshorts): pushl %esi movl 4+12(%esp),%ecx # count pushl %edi @@ -342,10 +300,8 @@ acs_CopyLeft: # Equivalent to # arrayof_conjoint_jints .p2align 4,,15 - ELF_TYPE(_Copy_conjoint_jints_atomic,@function) - ELF_TYPE(_Copy_arrayof_conjoint_jints,@function) -SYMBOL(_Copy_conjoint_jints_atomic): -SYMBOL(_Copy_arrayof_conjoint_jints): +DECLARE_FUNC(_Copy_conjoint_jints_atomic): +DECLARE_FUNC(_Copy_arrayof_conjoint_jints): pushl %esi movl 4+12(%esp),%ecx # count pushl %edi @@ -417,8 +373,7 @@ ci_CopyLeft: # } # } .p2align 4,,15 - ELF_TYPE(_Copy_conjoint_jlongs_atomic,@function) -SYMBOL(_Copy_conjoint_jlongs_atomic): +DECLARE_FUNC(_Copy_conjoint_jlongs_atomic): movl 4+8(%esp),%ecx # count movl 4+0(%esp),%eax # from movl 4+4(%esp),%edx # to @@ -446,8 +401,7 @@ cla_CopyLeft: # void* to, # size_t count) .p2align 4,,15 - ELF_TYPE(_mmx_Copy_arrayof_conjoint_jshorts,@function) -SYMBOL(_mmx_Copy_arrayof_conjoint_jshorts): +DECLARE_FUNC(_mmx_Copy_arrayof_conjoint_jshorts): pushl %esi movl 4+12(%esp),%ecx pushl %edi @@ -544,8 +498,7 @@ mmx_acs_CopyLeft: # int64_t exchange_value) # .p2align 4,,15 - ELF_TYPE(_Atomic_cmpxchg_long,@function) -SYMBOL(_Atomic_cmpxchg_long): +DECLARE_FUNC(_Atomic_cmpxchg_long): # 8(%esp) : return PC pushl %ebx # 4(%esp) : old %ebx pushl %edi # 0(%esp) : old %edi @@ -564,8 +517,7 @@ SYMBOL(_Atomic_cmpxchg_long): # Support for int64_t Atomic::load and Atomic::store. # void _Atomic_move_long(const volatile int64_t* src, volatile int64_t* dst) .p2align 4,,15 - ELF_TYPE(_Atomic_move_long,@function) -SYMBOL(_Atomic_move_long): +DECLARE_FUNC(_Atomic_move_long): movl 4(%esp), %eax # src fildll (%eax) movl 8(%esp), %eax # dest diff --git a/src/hotspot/os_cpu/bsd_x86/bsd_x86_64.S b/src/hotspot/os_cpu/bsd_x86/bsd_x86_64.S index 5e2addc4e6f..d664b929559 100644 --- a/src/hotspot/os_cpu/bsd_x86/bsd_x86_64.S +++ b/src/hotspot/os_cpu/bsd_x86/bsd_x86_64.S @@ -21,14 +21,7 @@ # questions. # -#ifdef __APPLE__ -# Darwin uses _ prefixed global symbols -#define SYMBOL(s) _ ## s -#define ELF_TYPE(name, description) -#else -#define SYMBOL(s) s -#define ELF_TYPE(name, description) .type name,description -#endif +#include "defs.S.inc" # NOTE WELL! The _Copy functions are called directly # from server-compiler-generated code via CallLeafNoFP, @@ -36,31 +29,10 @@ # point or use it in the same manner as does the server # compiler. - .globl SYMBOL(SpinPause) - .globl SYMBOL(_Copy_arrayof_conjoint_bytes) - .globl SYMBOL(_Copy_arrayof_conjoint_jshorts) - .globl SYMBOL(_Copy_conjoint_jshorts_atomic) - .globl SYMBOL(_Copy_arrayof_conjoint_jints) - .globl SYMBOL(_Copy_conjoint_jints_atomic) - .globl SYMBOL(_Copy_arrayof_conjoint_jlongs) - .globl SYMBOL(_Copy_conjoint_jlongs_atomic) - -#ifdef __APPLE__ - .private_extern SYMBOL(SpinPause) - .private_extern SYMBOL(_Copy_arrayof_conjoint_bytes) - .private_extern SYMBOL(_Copy_arrayof_conjoint_jshorts) - .private_extern SYMBOL(_Copy_conjoint_jshorts_atomic) - .private_extern SYMBOL(_Copy_arrayof_conjoint_jints) - .private_extern SYMBOL(_Copy_conjoint_jints_atomic) - .private_extern SYMBOL(_Copy_arrayof_conjoint_jlongs) - .private_extern SYMBOL(_Copy_conjoint_jlongs_atomic) -#endif - .text .p2align 4,,15 - ELF_TYPE(SpinPause,@function) -SYMBOL(SpinPause): +DECLARE_FUNC(SpinPause): rep nop movq $1, %rax @@ -74,8 +46,7 @@ SYMBOL(SpinPause): # rdx - count, treated as ssize_t # .p2align 4,,15 - ELF_TYPE(_Copy_arrayof_conjoint_bytes,@function) -SYMBOL(_Copy_arrayof_conjoint_bytes): +DECLARE_FUNC(_Copy_arrayof_conjoint_bytes): movq %rdx,%r8 # byte count shrq $3,%rdx # qword count cmpq %rdi,%rsi @@ -176,10 +147,8 @@ acb_CopyLeft: # rdx - count, treated as ssize_t # .p2align 4,,15 - ELF_TYPE(_Copy_arrayof_conjoint_jshorts,@function) - ELF_TYPE(_Copy_conjoint_jshorts_atomic,@function) -SYMBOL(_Copy_arrayof_conjoint_jshorts): -SYMBOL(_Copy_conjoint_jshorts_atomic): +DECLARE_FUNC(_Copy_arrayof_conjoint_jshorts): +DECLARE_FUNC(_Copy_conjoint_jshorts_atomic): movq %rdx,%r8 # word count shrq $2,%rdx # qword count cmpq %rdi,%rsi @@ -266,10 +235,8 @@ acs_CopyLeft: # rdx - count, treated as ssize_t # .p2align 4,,15 - ELF_TYPE(_Copy_arrayof_conjoint_jints,@function) - ELF_TYPE(_Copy_conjoint_jints_atomic,@function) -SYMBOL(_Copy_arrayof_conjoint_jints): -SYMBOL(_Copy_conjoint_jints_atomic): +DECLARE_FUNC(_Copy_arrayof_conjoint_jints): +DECLARE_FUNC(_Copy_conjoint_jints_atomic): movq %rdx,%r8 # dword count shrq %rdx # qword count cmpq %rdi,%rsi @@ -345,10 +312,8 @@ aci_CopyLeft: # rdx - count, treated as ssize_t # .p2align 4,,15 - ELF_TYPE(_Copy_arrayof_conjoint_jlongs,@function) - ELF_TYPE(_Copy_conjoint_jlongs_atomic,@function) -SYMBOL(_Copy_arrayof_conjoint_jlongs): -SYMBOL(_Copy_conjoint_jlongs_atomic): +DECLARE_FUNC(_Copy_arrayof_conjoint_jlongs): +DECLARE_FUNC(_Copy_conjoint_jlongs_atomic): cmpq %rdi,%rsi leaq -8(%rdi,%rdx,8),%rax # from + count*8 - 8 jbe acl_CopyRight diff --git a/src/hotspot/os_cpu/bsd_x86/safefetch_bsd_x86_64.S b/src/hotspot/os_cpu/bsd_x86/safefetch_bsd_x86_64.S index 1697f6f03b5..36815c9b1fb 100644 --- a/src/hotspot/os_cpu/bsd_x86/safefetch_bsd_x86_64.S +++ b/src/hotspot/os_cpu/bsd_x86/safefetch_bsd_x86_64.S @@ -22,30 +22,7 @@ # questions. # -#ifdef __APPLE__ -# Darwin uses _ prefixed global symbols -#define SYMBOL(s) _ ## s -#define ELF_TYPE(name, description) -#else -#define SYMBOL(s) s -#define ELF_TYPE(name, description) .type name,description -#endif - - .globl SYMBOL(SafeFetch32_impl) - .globl SYMBOL(SafeFetchN_impl) - .globl SYMBOL(_SafeFetch32_fault) - .globl SYMBOL(_SafeFetchN_fault) - .globl SYMBOL(_SafeFetch32_continuation) - .globl SYMBOL(_SafeFetchN_continuation) - -#ifdef __APPLE__ - .private_extern SYMBOL(SafeFetch32_impl) - .private_extern SYMBOL(SafeFetchN_impl) - .private_extern SYMBOL(_SafeFetch32_fault) - .private_extern SYMBOL(_SafeFetchN_fault) - .private_extern SYMBOL(_SafeFetch32_continuation) - .private_extern SYMBOL(_SafeFetchN_continuation) -#endif +#include "defs.S.inc" .text @@ -53,12 +30,11 @@ # # %rdi : address # %esi : defaultval - ELF_TYPE(SafeFetch32_impl,@function) -SYMBOL(SafeFetch32_impl:) -SYMBOL(_SafeFetch32_fault:) +DECLARE_FUNC(SafeFetch32_impl): +DECLARE_FUNC(_SafeFetch32_fault): movl (%rdi), %eax ret -SYMBOL(_SafeFetch32_continuation:) +DECLARE_FUNC(_SafeFetch32_continuation): movl %esi, %eax ret @@ -66,11 +42,10 @@ SYMBOL(_SafeFetch32_continuation:) # # %rdi : address # %rsi : defaultval - ELF_TYPE(SafeFetchN_impl,@function) -SYMBOL(SafeFetchN_impl:) -SYMBOL(_SafeFetchN_fault:) +DECLARE_FUNC(SafeFetchN_impl): +DECLARE_FUNC(_SafeFetchN_fault): movq (%rdi), %rax ret -SYMBOL(_SafeFetchN_continuation:) +DECLARE_FUNC(_SafeFetchN_continuation): movq %rsi, %rax ret diff --git a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S index e67206a9d49..2724e78862d 100644 --- a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.S @@ -1,4 +1,5 @@ // Copyright (c) 2021, Red Hat Inc. All rights reserved. +// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -19,14 +20,12 @@ // or visit www.oracle.com if you need additional information or have any // questions. - +#include "defs.S.inc" .text - .globl aarch64_atomic_fetch_add_8_default_impl - .hidden aarch64_atomic_fetch_add_8_default_impl .align 5 -aarch64_atomic_fetch_add_8_default_impl: +DECLARE_FUNC(aarch64_atomic_fetch_add_8_default_impl): #ifdef __ARM_FEATURE_ATOMICS ldaddal x1, x2, [x0] #else @@ -40,10 +39,8 @@ aarch64_atomic_fetch_add_8_default_impl: mov x0, x2 ret - .globl aarch64_atomic_fetch_add_4_default_impl - .hidden aarch64_atomic_fetch_add_4_default_impl .align 5 -aarch64_atomic_fetch_add_4_default_impl: +DECLARE_FUNC(aarch64_atomic_fetch_add_4_default_impl): #ifdef __ARM_FEATURE_ATOMICS ldaddal w1, w2, [x0] #else @@ -57,10 +54,8 @@ aarch64_atomic_fetch_add_4_default_impl: mov w0, w2 ret - .global aarch64_atomic_fetch_add_8_relaxed_default_impl - .hidden aarch64_atomic_fetch_add_8_relaxed_default_impl .align 5 -aarch64_atomic_fetch_add_8_relaxed_default_impl: +DECLARE_FUNC(aarch64_atomic_fetch_add_8_relaxed_default_impl): #ifdef __ARM_FEATURE_ATOMICS ldadd x1, x2, [x0] #else @@ -73,10 +68,8 @@ aarch64_atomic_fetch_add_8_relaxed_default_impl: mov x0, x2 ret - .global aarch64_atomic_fetch_add_4_relaxed_default_impl - .hidden aarch64_atomic_fetch_add_4_relaxed_default_impl .align 5 -aarch64_atomic_fetch_add_4_relaxed_default_impl: +DECLARE_FUNC(aarch64_atomic_fetch_add_4_relaxed_default_impl): #ifdef __ARM_FEATURE_ATOMICS ldadd w1, w2, [x0] #else @@ -89,10 +82,8 @@ aarch64_atomic_fetch_add_4_relaxed_default_impl: mov w0, w2 ret - .globl aarch64_atomic_xchg_4_default_impl - .hidden aarch64_atomic_xchg_4_default_impl .align 5 -aarch64_atomic_xchg_4_default_impl: +DECLARE_FUNC(aarch64_atomic_xchg_4_default_impl): #ifdef __ARM_FEATURE_ATOMICS swpal w1, w2, [x0] #else @@ -105,10 +96,8 @@ aarch64_atomic_xchg_4_default_impl: mov w0, w2 ret - .globl aarch64_atomic_xchg_8_default_impl - .hidden aarch64_atomic_xchg_8_default_impl .align 5 -aarch64_atomic_xchg_8_default_impl: +DECLARE_FUNC(aarch64_atomic_xchg_8_default_impl): #ifdef __ARM_FEATURE_ATOMICS swpal x1, x2, [x0] #else @@ -121,10 +110,8 @@ aarch64_atomic_xchg_8_default_impl: mov x0, x2 ret - .globl aarch64_atomic_cmpxchg_1_default_impl - .hidden aarch64_atomic_cmpxchg_1_default_impl .align 5 -aarch64_atomic_cmpxchg_1_default_impl: +DECLARE_FUNC(aarch64_atomic_cmpxchg_1_default_impl): #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casalb w3, w2, [x0] @@ -142,10 +129,8 @@ aarch64_atomic_cmpxchg_1_default_impl: mov w0, w3 ret - .globl aarch64_atomic_cmpxchg_4_default_impl - .hidden aarch64_atomic_cmpxchg_4_default_impl .align 5 -aarch64_atomic_cmpxchg_4_default_impl: +DECLARE_FUNC(aarch64_atomic_cmpxchg_4_default_impl): #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casal w3, w2, [x0] @@ -162,10 +147,8 @@ aarch64_atomic_cmpxchg_4_default_impl: mov w0, w3 ret - .globl aarch64_atomic_cmpxchg_8_default_impl - .hidden aarch64_atomic_cmpxchg_8_default_impl .align 5 -aarch64_atomic_cmpxchg_8_default_impl: +DECLARE_FUNC(aarch64_atomic_cmpxchg_8_default_impl): #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casal x3, x2, [x0] @@ -182,10 +165,8 @@ aarch64_atomic_cmpxchg_8_default_impl: mov x0, x3 ret - .globl aarch64_atomic_cmpxchg_4_release_default_impl - .hidden aarch64_atomic_cmpxchg_4_release_default_impl .align 5 -aarch64_atomic_cmpxchg_4_release_default_impl: +DECLARE_FUNC(aarch64_atomic_cmpxchg_4_release_default_impl): #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casl w3, w2, [x0] @@ -200,10 +181,8 @@ aarch64_atomic_cmpxchg_4_release_default_impl: 1: mov w0, w3 ret - .globl aarch64_atomic_cmpxchg_8_release_default_impl - .hidden aarch64_atomic_cmpxchg_8_release_default_impl .align 5 -aarch64_atomic_cmpxchg_8_release_default_impl: +DECLARE_FUNC(aarch64_atomic_cmpxchg_8_release_default_impl): #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casl x3, x2, [x0] @@ -218,10 +197,8 @@ aarch64_atomic_cmpxchg_8_release_default_impl: 1: mov x0, x3 ret - .globl aarch64_atomic_cmpxchg_4_seq_cst_default_impl - .hidden aarch64_atomic_cmpxchg_4_seq_cst_default_impl .align 5 -aarch64_atomic_cmpxchg_4_seq_cst_default_impl: +DECLARE_FUNC(aarch64_atomic_cmpxchg_4_seq_cst_default_impl): #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casal w3, w2, [x0] @@ -236,10 +213,8 @@ aarch64_atomic_cmpxchg_4_seq_cst_default_impl: 1: mov w0, w3 ret - .globl aarch64_atomic_cmpxchg_8_seq_cst_default_impl - .hidden aarch64_atomic_cmpxchg_8_seq_cst_default_impl .align 5 -aarch64_atomic_cmpxchg_8_seq_cst_default_impl: +DECLARE_FUNC(aarch64_atomic_cmpxchg_8_seq_cst_default_impl): #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casal x3, x2, [x0] @@ -254,10 +229,8 @@ aarch64_atomic_cmpxchg_8_seq_cst_default_impl: 1: mov x0, x3 ret -.globl aarch64_atomic_cmpxchg_1_relaxed_default_impl -.hidden aarch64_atomic_cmpxchg_1_relaxed_default_impl .align 5 -aarch64_atomic_cmpxchg_1_relaxed_default_impl: +DECLARE_FUNC(aarch64_atomic_cmpxchg_1_relaxed_default_impl): #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 casb w3, w2, [x0] @@ -273,10 +246,8 @@ aarch64_atomic_cmpxchg_1_relaxed_default_impl: 1: mov w0, w3 ret - .globl aarch64_atomic_cmpxchg_4_relaxed_default_impl - .hidden aarch64_atomic_cmpxchg_4_relaxed_default_impl .align 5 -aarch64_atomic_cmpxchg_4_relaxed_default_impl: +DECLARE_FUNC(aarch64_atomic_cmpxchg_4_relaxed_default_impl): #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 cas w3, w2, [x0] @@ -291,10 +262,8 @@ aarch64_atomic_cmpxchg_4_relaxed_default_impl: 1: mov w0, w3 ret - .globl aarch64_atomic_cmpxchg_8_relaxed_default_impl - .hidden aarch64_atomic_cmpxchg_8_relaxed_default_impl .align 5 -aarch64_atomic_cmpxchg_8_relaxed_default_impl: +DECLARE_FUNC(aarch64_atomic_cmpxchg_8_relaxed_default_impl): #ifdef __ARM_FEATURE_ATOMICS mov x3, x1 cas x3, x2, [x0] diff --git a/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S index ade867ace01..f9702d5e554 100644 --- a/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/copy_linux_aarch64.S @@ -1,5 +1,6 @@ /* * Copyright (c) 2016, Linaro Ltd. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,11 +22,8 @@ * questions. * */ - .global _Copy_conjoint_words - .global _Copy_disjoint_words - .hidden _Copy_conjoint_words - .hidden _Copy_disjoint_words +#include "defs.S.inc" s .req x0 d .req x1 @@ -40,7 +38,7 @@ t6 .req x9 t7 .req x10 .align 6 -_Copy_disjoint_words: +DECLARE_FUNC(_Copy_disjoint_words): // Ensure 2 word aligned tbz s, #3, fwd_copy_aligned ldr t0, [s], #8 @@ -138,7 +136,7 @@ fwd_copy_drain: ret .align 6 -_Copy_conjoint_words: +DECLARE_FUNC(_Copy_conjoint_words): sub t0, d, s cmp t0, count, lsl #3 bhs _Copy_disjoint_words diff --git a/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S index cfbd8f45f28..82d989a9b88 100644 --- a/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/safefetch_linux_aarch64.S @@ -23,29 +23,17 @@ * */ - .globl SafeFetchN_impl - .globl _SafeFetchN_fault - .globl _SafeFetchN_continuation - .globl SafeFetch32_impl - .globl _SafeFetch32_fault - .globl _SafeFetch32_continuation - - .hidden SafeFetchN_impl - .hidden _SafeFetchN_fault - .hidden _SafeFetchN_continuation - .hidden SafeFetch32_impl - .hidden _SafeFetch32_fault - .hidden _SafeFetch32_continuation +#include "defs.S.inc" # Support for int SafeFetch32(int* address, int defaultval); # # x0 : address # x1 : defaultval -SafeFetch32_impl: -_SafeFetch32_fault: +DECLARE_FUNC(SafeFetch32_impl): +DECLARE_FUNC(_SafeFetch32_fault): ldr w0, [x0] ret -_SafeFetch32_continuation: +DECLARE_FUNC(_SafeFetch32_continuation): mov x0, x1 ret @@ -53,10 +41,10 @@ _SafeFetch32_continuation: # # x1 : address # x0 : defaultval -SafeFetchN_impl: -_SafeFetchN_fault: +DECLARE_FUNC(SafeFetchN_impl): +DECLARE_FUNC(_SafeFetchN_fault): ldr x0, [x0] ret -_SafeFetchN_continuation: +DECLARE_FUNC(_SafeFetchN_continuation): mov x0, x1 ret diff --git a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S index f9f5aab2a6b..ca31585871d 100644 --- a/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S +++ b/src/hotspot/os_cpu/linux_aarch64/threadLS_linux_aarch64.S @@ -1,4 +1,5 @@ // Copyright (c) 2015, 2022, Red Hat Inc. All rights reserved. +// Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -19,17 +20,15 @@ // or visit www.oracle.com if you need additional information or have any // questions. +#include "defs.S.inc" + // JavaThread::aarch64_get_thread_helper() // // Return the current thread pointer in x0. // Clobber x1, flags. // All other registers are preserved, - .global _ZN10JavaThread25aarch64_get_thread_helperEv - .hidden _ZN10JavaThread25aarch64_get_thread_helperEv - .type _ZN10JavaThread25aarch64_get_thread_helperEv, %function - -_ZN10JavaThread25aarch64_get_thread_helperEv: +DECLARE_FUNC(_ZN10JavaThread25aarch64_get_thread_helperEv): hint #0x19 // paciasp stp x29, x30, [sp, -16]! adrp x0, :tlsdesc:_ZN6Thread12_thr_currentE diff --git a/src/hotspot/os_cpu/linux_arm/linux_arm_32.S b/src/hotspot/os_cpu/linux_arm/linux_arm_32.S index ad88c58ce78..a866858dae5 100644 --- a/src/hotspot/os_cpu/linux_arm/linux_arm_32.S +++ b/src/hotspot/os_cpu/linux_arm/linux_arm_32.S @@ -21,6 +21,7 @@ # questions. # +#include "defs.S.inc" # NOTE WELL! The _Copy functions are called directly # from server-compiler-generated code via CallLeafNoFP, @@ -28,55 +29,24 @@ # point or use it in the same manner as does the server # compiler. - .globl SpinPause - .hidden SpinPause - .type SpinPause, %function - .globl _Copy_arrayof_conjoint_bytes - .hidden _Copy_arrayof_conjoint_bytes - .type _Copy_arrayof_conjoint_bytes, %function - .globl _Copy_disjoint_words - .hidden _Copy_disjoint_words - .type _Copy_disjoint_words, %function - .globl _Copy_conjoint_words - .hidden _Copy_conjoint_words - .type _Copy_conjoint_words, %function - .globl _Copy_conjoint_jshorts_atomic - .hidden _Copy_conjoint_jshorts_atomic - .type _Copy_conjoint_jshorts_atomic, %function - .globl _Copy_arrayof_conjoint_jshorts - .hidden _Copy_arrayof_conjoint_jshorts - .type _Copy_arrayof_conjoint_jshorts, %function - .globl _Copy_conjoint_jints_atomic - .hidden _Copy_conjoint_jints_atomic - .type _Copy_conjoint_jints_atomic, %function - .globl _Copy_arrayof_conjoint_jints - .hidden _Copy_arrayof_conjoint_jints - .type _Copy_arrayof_conjoint_jints, %function - .globl _Copy_conjoint_jlongs_atomic - .hidden _Copy_conjoint_jlongs_atomic - .type _Copy_conjoint_jlongs_atomic, %function - .globl _Copy_arrayof_conjoint_jlongs - .hidden _Copy_arrayof_conjoint_jlongs - .type _Copy_arrayof_conjoint_jlongs, %function - from .req r0 to .req r1 .text -SpinPause: +DECLARE_FUNC(SpinPause): bx LR # Support for void Copy::arrayof_conjoint_bytes(void* from, # void* to, # size_t count) -_Copy_arrayof_conjoint_bytes: +DECLARE_FUNC(_Copy_arrayof_conjoint_bytes): swi 0x9f0001 # Support for void Copy::disjoint_words(void* from, # void* to, # size_t count) -_Copy_disjoint_words: +DECLARE_FUNC(_Copy_disjoint_words): stmdb sp!, {r3 - r9, ip} cmp r2, #0 @@ -121,7 +91,7 @@ disjoint_words_finish: # Support for void Copy::conjoint_words(void* from, # void* to, # size_t count) -_Copy_conjoint_words: +DECLARE_FUNC(_Copy_conjoint_words): stmdb sp!, {r3 - r9, ip} cmp r2, #0 @@ -201,7 +171,7 @@ conjoint_words_finish: # Support for void Copy::conjoint_jshorts_atomic(void* from, # void* to, # size_t count) -_Copy_conjoint_jshorts_atomic: +DECLARE_FUNC(_Copy_conjoint_jshorts_atomic): stmdb sp!, {r3 - r9, ip} cmp r2, #0 @@ -425,21 +395,21 @@ conjoint_shorts_finish: # Support for void Copy::arrayof_conjoint_jshorts(void* from, # void* to, # size_t count) -_Copy_arrayof_conjoint_jshorts: +DECLARE_FUNC(_Copy_arrayof_conjoint_jshorts): swi 0x9f0001 # Support for void Copy::conjoint_jints_atomic(void* from, # void* to, # size_t count) -_Copy_conjoint_jints_atomic: -_Copy_arrayof_conjoint_jints: +DECLARE_FUNC(_Copy_conjoint_jints_atomic): +DECLARE_FUNC(_Copy_arrayof_conjoint_jints): swi 0x9f0001 # Support for void Copy::conjoint_jlongs_atomic(jlong* from, # jlong* to, # size_t count) -_Copy_conjoint_jlongs_atomic: -_Copy_arrayof_conjoint_jlongs: +DECLARE_FUNC(_Copy_conjoint_jlongs_atomic): +DECLARE_FUNC(_Copy_arrayof_conjoint_jlongs): stmdb sp!, {r3 - r9, ip} cmp r2, #0 diff --git a/src/hotspot/os_cpu/linux_arm/safefetch_linux_arm.S b/src/hotspot/os_cpu/linux_arm/safefetch_linux_arm.S index 07e90fa3079..5c61774a71d 100644 --- a/src/hotspot/os_cpu/linux_arm/safefetch_linux_arm.S +++ b/src/hotspot/os_cpu/linux_arm/safefetch_linux_arm.S @@ -23,24 +23,16 @@ * */ - .globl SafeFetch32_impl - .globl _SafeFetch32_fault - .globl _SafeFetch32_continuation - - .hidden SafeFetch32_impl - .hidden _SafeFetch32_fault - .hidden _SafeFetch32_continuation - - .type SafeFetch32_impl, %function +#include "defs.S.inc" # Support for int SafeFetch32(int* address, int defaultval); # # r0 : address # r1 : defaultval -SafeFetch32_impl: -_SafeFetch32_fault: +DECLARE_FUNC(SafeFetch32_impl): +DECLARE_FUNC(_SafeFetch32_fault): ldr r0, [r0] bx lr -_SafeFetch32_continuation: +DECLARE_FUNC(_SafeFetch32_continuation): mov r0, r1 bx lr diff --git a/src/hotspot/os_cpu/linux_ppc/safefetch_linux_ppc.S b/src/hotspot/os_cpu/linux_ppc/safefetch_linux_ppc.S index 8c96edf01b4..43d8a4e5e98 100644 --- a/src/hotspot/os_cpu/linux_ppc/safefetch_linux_ppc.S +++ b/src/hotspot/os_cpu/linux_ppc/safefetch_linux_ppc.S @@ -23,30 +23,18 @@ * */ - .globl SafeFetchN_impl - .globl _SafeFetchN_fault - .globl _SafeFetchN_continuation - .globl SafeFetch32_impl - .globl _SafeFetch32_fault - .globl _SafeFetch32_continuation - - .hidden SafeFetchN_impl - .hidden _SafeFetchN_fault - .hidden _SafeFetchN_continuation - .hidden SafeFetch32_impl - .hidden _SafeFetch32_fault - .hidden _SafeFetch32_continuation +#include "defs.S.inc" # Support for int SafeFetch32(int* address, int defaultval); # # r3 : address # r4 : defaultval # r3 : retval -SafeFetch32_impl: -_SafeFetch32_fault: +DECLARE_FUNC(SafeFetch32_impl): +DECLARE_FUNC(_SafeFetch32_fault): lwa %r3, 0(%r3) blr -_SafeFetch32_continuation: +DECLARE_FUNC(_SafeFetch32_continuation): mr %r3, %r4 blr @@ -55,10 +43,10 @@ _SafeFetch32_continuation: # r3 : address # r4 : defaultval # r3 : retval -SafeFetchN_impl: -_SafeFetchN_fault: +DECLARE_FUNC(SafeFetchN_impl): +DECLARE_FUNC(_SafeFetchN_fault): ld %r3, 0(%r3) blr -_SafeFetchN_continuation: +DECLARE_FUNC(_SafeFetchN_continuation): mr %r3, %r4 blr diff --git a/src/hotspot/os_cpu/linux_riscv/safefetch_linux_riscv.S b/src/hotspot/os_cpu/linux_riscv/safefetch_linux_riscv.S index 150df7567bd..8c325fe55ca 100644 --- a/src/hotspot/os_cpu/linux_riscv/safefetch_linux_riscv.S +++ b/src/hotspot/os_cpu/linux_riscv/safefetch_linux_riscv.S @@ -23,30 +23,18 @@ * */ - .globl SafeFetchN_impl - .globl _SafeFetchN_fault - .globl _SafeFetchN_continuation - .globl SafeFetch32_impl - .globl _SafeFetch32_fault - .globl _SafeFetch32_continuation - - .hidden SafeFetchN_impl - .hidden _SafeFetchN_fault - .hidden _SafeFetchN_continuation - .hidden SafeFetch32_impl - .hidden _SafeFetch32_fault - .hidden _SafeFetch32_continuation +#include "defs.S.inc" # Support for int SafeFetch32(int* address, int defaultval); # # x10 (a0) : address # x11 (a1) : defaultval # x10 (a0) : retval -SafeFetch32_impl: -_SafeFetch32_fault: +DECLARE_FUNC(SafeFetch32_impl): +DECLARE_FUNC(_SafeFetch32_fault): lw a0, 0(a0) ret -_SafeFetch32_continuation: +DECLARE_FUNC(_SafeFetch32_continuation): mv a0, a1 ret @@ -55,10 +43,10 @@ _SafeFetch32_continuation: # x10 (a0) : address # x11 (a1) : defaultval # x10 (a0) : retval -SafeFetchN_impl: -_SafeFetchN_fault: +DECLARE_FUNC(SafeFetchN_impl): +DECLARE_FUNC(_SafeFetchN_fault): ld a0, 0(a0) ret -_SafeFetchN_continuation: +DECLARE_FUNC(_SafeFetchN_continuation): mv a0, a1 ret diff --git a/src/hotspot/os_cpu/linux_s390/safefetch_linux_s390.S b/src/hotspot/os_cpu/linux_s390/safefetch_linux_s390.S index 43d50c798e5..4ba9f7fb248 100644 --- a/src/hotspot/os_cpu/linux_s390/safefetch_linux_s390.S +++ b/src/hotspot/os_cpu/linux_s390/safefetch_linux_s390.S @@ -23,30 +23,18 @@ * */ - .globl SafeFetchN_impl - .globl _SafeFetchN_fault - .globl _SafeFetchN_continuation - .globl SafeFetch32_impl - .globl _SafeFetch32_fault - .globl _SafeFetch32_continuation - - .hidden SafeFetchN_impl - .hidden _SafeFetchN_fault - .hidden _SafeFetchN_continuation - .hidden SafeFetch32_impl - .hidden _SafeFetch32_fault - .hidden _SafeFetch32_continuation +#include "defs.S.inc" # Support for int SafeFetch32(int* address, int defaultval); # # r2 : address # r3 : defaultval # r2 : retval -SafeFetch32_impl: -_SafeFetch32_fault: +DECLARE_FUNC(SafeFetch32_impl): +DECLARE_FUNC(_SafeFetch32_fault): lgf %r2, 0(%r2) br %r14 -_SafeFetch32_continuation: +DECLARE_FUNC(_SafeFetch32_continuation): lgr %r2, %r3 br %r14 @@ -55,10 +43,10 @@ _SafeFetch32_continuation: # r2 : address # r3 : defaultval # r2 : retval -SafeFetchN_impl: -_SafeFetchN_fault: +DECLARE_FUNC(SafeFetchN_impl): +DECLARE_FUNC(_SafeFetchN_fault): lg %r2, 0(%r2) br %r14 -_SafeFetchN_continuation: +DECLARE_FUNC(_SafeFetchN_continuation): lgr %r2, %r3 br %r14 diff --git a/src/hotspot/os_cpu/linux_x86/linux_x86_32.S b/src/hotspot/os_cpu/linux_x86/linux_x86_32.S index e23cd2b9164..43a9a38e57f 100644 --- a/src/hotspot/os_cpu/linux_x86/linux_x86_32.S +++ b/src/hotspot/os_cpu/linux_x86/linux_x86_32.S @@ -21,7 +21,7 @@ # questions. # - .globl SpinPause +#include "defs.S.inc" # NOTE WELL! The _Copy functions are called directly # from server-compiler-generated code via CallLeafNoFP, @@ -29,35 +29,10 @@ # point or use it in the same manner as does the server # compiler. - .globl _Copy_arrayof_conjoint_bytes - .globl _Copy_conjoint_jshorts_atomic - .globl _Copy_arrayof_conjoint_jshorts - .globl _Copy_conjoint_jints_atomic - .globl _Copy_arrayof_conjoint_jints - .globl _Copy_conjoint_jlongs_atomic - .globl _mmx_Copy_arrayof_conjoint_jshorts - - .globl _Atomic_cmpxchg_long - .globl _Atomic_move_long - - .hidden SpinPause - - .hidden _Copy_arrayof_conjoint_bytes - .hidden _Copy_conjoint_jshorts_atomic - .hidden _Copy_arrayof_conjoint_jshorts - .hidden _Copy_conjoint_jints_atomic - .hidden _Copy_arrayof_conjoint_jints - .hidden _Copy_conjoint_jlongs_atomic - .hidden _mmx_Copy_arrayof_conjoint_jshorts - - .hidden _Atomic_cmpxchg_long - .hidden _Atomic_move_long - .text - .type SpinPause,@function .p2align 4,,15 -SpinPause: +DECLARE_FUNC(SpinPause): rep nop movl $1, %eax @@ -68,8 +43,7 @@ SpinPause: # size_t count) # .p2align 4,,15 - .type _Copy_arrayof_conjoint_bytes,@function -_Copy_arrayof_conjoint_bytes: +DECLARE_FUNC(_Copy_arrayof_conjoint_bytes): pushl %esi movl 4+12(%esp),%ecx # count pushl %edi @@ -156,8 +130,7 @@ acb_CopyLeft: # void* to, # size_t count) .p2align 4,,15 - .type _Copy_conjoint_jshorts_atomic,@function -_Copy_conjoint_jshorts_atomic: +DECLARE_FUNC(_Copy_conjoint_jshorts_atomic): pushl %esi movl 4+12(%esp),%ecx # count pushl %edi @@ -243,8 +216,7 @@ cs_CopyLeft: # void* to, # size_t count) .p2align 4,,15 - .type _Copy_arrayof_conjoint_jshorts,@function -_Copy_arrayof_conjoint_jshorts: +DECLARE_FUNC(_Copy_arrayof_conjoint_jshorts): pushl %esi movl 4+12(%esp),%ecx # count pushl %edi @@ -320,10 +292,8 @@ acs_CopyLeft: # Equivalent to # arrayof_conjoint_jints .p2align 4,,15 - .type _Copy_conjoint_jints_atomic,@function - .type _Copy_arrayof_conjoint_jints,@function -_Copy_conjoint_jints_atomic: -_Copy_arrayof_conjoint_jints: +DECLARE_FUNC(_Copy_conjoint_jints_atomic): +DECLARE_FUNC(_Copy_arrayof_conjoint_jints): pushl %esi movl 4+12(%esp),%ecx # count pushl %edi @@ -397,8 +367,7 @@ ci_CopyLeft: # } */ .p2align 4,,15 - .type _Copy_conjoint_jlongs_atomic,@function -_Copy_conjoint_jlongs_atomic: +DECLARE_FUNC(_Copy_conjoint_jlongs_atomic): movl 4+8(%esp),%ecx # count movl 4+0(%esp),%eax # from movl 4+4(%esp),%edx # to @@ -426,8 +395,7 @@ cla_CopyLeft: # void* to, # size_t count) .p2align 4,,15 - .type _mmx_Copy_arrayof_conjoint_jshorts,@function -_mmx_Copy_arrayof_conjoint_jshorts: +DECLARE_FUNC(_mmx_Copy_arrayof_conjoint_jshorts): pushl %esi movl 4+12(%esp),%ecx pushl %edi @@ -524,8 +492,7 @@ mmx_acs_CopyLeft: # jlong exchange_value) # .p2align 4,,15 - .type _Atomic_cmpxchg_long,@function -_Atomic_cmpxchg_long: +DECLARE_FUNC(_Atomic_cmpxchg_long): # 8(%esp) : return PC pushl %ebx # 4(%esp) : old %ebx pushl %edi # 0(%esp) : old %edi @@ -543,8 +510,7 @@ _Atomic_cmpxchg_long: # Support for jlong Atomic::load and Atomic::store. # void _Atomic_move_long(const volatile jlong* src, volatile jlong* dst) .p2align 4,,15 - .type _Atomic_move_long,@function -_Atomic_move_long: +DECLARE_FUNC(_Atomic_move_long): movl 4(%esp), %eax # src fildll (%eax) movl 8(%esp), %eax # dest diff --git a/src/hotspot/os_cpu/linux_x86/linux_x86_64.S b/src/hotspot/os_cpu/linux_x86/linux_x86_64.S index 65580a194af..e15f27f7a6a 100644 --- a/src/hotspot/os_cpu/linux_x86/linux_x86_64.S +++ b/src/hotspot/os_cpu/linux_x86/linux_x86_64.S @@ -21,7 +21,7 @@ # questions. # - .globl SpinPause +#include "defs.S.inc" # NOTE WELL! The _Copy functions are called directly # from server-compiler-generated code via CallLeafNoFP, @@ -29,29 +29,10 @@ # point or use it in the same manner as does the server # compiler. - .globl _Copy_arrayof_conjoint_bytes - .globl _Copy_arrayof_conjoint_jshorts - .globl _Copy_conjoint_jshorts_atomic - .globl _Copy_arrayof_conjoint_jints - .globl _Copy_conjoint_jints_atomic - .globl _Copy_arrayof_conjoint_jlongs - .globl _Copy_conjoint_jlongs_atomic - - .hidden SpinPause - - .hidden _Copy_arrayof_conjoint_bytes - .hidden _Copy_arrayof_conjoint_jshorts - .hidden _Copy_conjoint_jshorts_atomic - .hidden _Copy_arrayof_conjoint_jints - .hidden _Copy_conjoint_jints_atomic - .hidden _Copy_arrayof_conjoint_jlongs - .hidden _Copy_conjoint_jlongs_atomic - .text .align 16 - .type SpinPause,@function -SpinPause: +DECLARE_FUNC(SpinPause): rep nop movq $1, %rax @@ -65,8 +46,7 @@ SpinPause: # rdx - count, treated as ssize_t # .p2align 4,,15 - .type _Copy_arrayof_conjoint_bytes,@function -_Copy_arrayof_conjoint_bytes: +DECLARE_FUNC(_Copy_arrayof_conjoint_bytes): movq %rdx,%r8 # byte count shrq $3,%rdx # qword count cmpq %rdi,%rsi @@ -167,10 +147,8 @@ acb_CopyLeft: # rdx - count, treated as ssize_t # .p2align 4,,15 - .type _Copy_arrayof_conjoint_jshorts,@function - .type _Copy_conjoint_jshorts_atomic,@function -_Copy_arrayof_conjoint_jshorts: -_Copy_conjoint_jshorts_atomic: +DECLARE_FUNC(_Copy_arrayof_conjoint_jshorts): +DECLARE_FUNC(_Copy_conjoint_jshorts_atomic): movq %rdx,%r8 # word count shrq $2,%rdx # qword count cmpq %rdi,%rsi @@ -257,10 +235,8 @@ acs_CopyLeft: # rdx - count, treated as ssize_t # .p2align 4,,15 - .type _Copy_arrayof_conjoint_jints,@function - .type _Copy_conjoint_jints_atomic,@function -_Copy_arrayof_conjoint_jints: -_Copy_conjoint_jints_atomic: +DECLARE_FUNC(_Copy_arrayof_conjoint_jints): +DECLARE_FUNC(_Copy_conjoint_jints_atomic): movq %rdx,%r8 # dword count shrq %rdx # qword count cmpq %rdi,%rsi @@ -336,10 +312,8 @@ aci_CopyLeft: # rdx - count, treated as ssize_t # .p2align 4,,15 - .type _Copy_arrayof_conjoint_jlongs,@function - .type _Copy_conjoint_jlongs_atomic,@function -_Copy_arrayof_conjoint_jlongs: -_Copy_conjoint_jlongs_atomic: +DECLARE_FUNC(_Copy_arrayof_conjoint_jlongs): +DECLARE_FUNC(_Copy_conjoint_jlongs_atomic): cmpq %rdi,%rsi leaq -8(%rdi,%rdx,8),%rax # from + count*8 - 8 jbe acl_CopyRight diff --git a/src/hotspot/os_cpu/linux_x86/safefetch_linux_x86_32.S b/src/hotspot/os_cpu/linux_x86/safefetch_linux_x86_32.S index a0f8577d8d1..73f6cdf38c9 100644 --- a/src/hotspot/os_cpu/linux_x86/safefetch_linux_x86_32.S +++ b/src/hotspot/os_cpu/linux_x86/safefetch_linux_x86_32.S @@ -21,13 +21,8 @@ # or visit www.oracle.com if you need additional information or have any # questions. # - .globl SafeFetch32_impl - .globl _SafeFetch32_fault - .globl _SafeFetch32_continuation - .hidden SafeFetch32_impl - .hidden _SafeFetch32_fault - .hidden _SafeFetch32_continuation +#include "defs.S.inc" .text @@ -36,12 +31,11 @@ # 8(%esp) : default value # 4(%esp) : crash address # 0(%esp) : return pc - .type SafeFetch32_impl,@function -SafeFetch32_impl: +DECLARE_FUNC(SafeFetch32_impl): movl 4(%esp),%ecx # load address from stack -_SafeFetch32_fault: +DECLARE_FUNC(_SafeFetch32_fault): movl (%ecx), %eax # load target value, may fault ret -_SafeFetch32_continuation: +DECLARE_FUNC(_SafeFetch32_continuation): movl 8(%esp),%eax # load default value from stack ret diff --git a/src/hotspot/os_cpu/linux_x86/safefetch_linux_x86_64.S b/src/hotspot/os_cpu/linux_x86/safefetch_linux_x86_64.S index 1937e717088..b3145141cf2 100644 --- a/src/hotspot/os_cpu/linux_x86/safefetch_linux_x86_64.S +++ b/src/hotspot/os_cpu/linux_x86/safefetch_linux_x86_64.S @@ -21,33 +21,20 @@ # or visit www.oracle.com if you need additional information or have any # questions. # - .globl SafeFetch32_impl - .globl SafeFetchN_impl - .globl _SafeFetch32_fault - .globl _SafeFetchN_fault - .globl _SafeFetch32_continuation - .globl _SafeFetchN_continuation - .hidden SafeFetch32_impl - .hidden SafeFetchN_impl - .hidden _SafeFetch32_fault - .hidden _SafeFetchN_fault - .hidden _SafeFetch32_continuation - .hidden _SafeFetchN_continuation +#include "defs.S.inc" .text - # Support for int SafeFetch32(int* address, int defaultval); # # %rdi : address # %esi : defaultval - .type SafeFetch32_impl,@function -SafeFetch32_impl: -_SafeFetch32_fault: +DECLARE_FUNC(SafeFetch32_impl): +DECLARE_FUNC(_SafeFetch32_fault): movl (%rdi), %eax # load target value, may fault ret -_SafeFetch32_continuation: +DECLARE_FUNC(_SafeFetch32_continuation): movl %esi, %eax # return default ret @@ -55,11 +42,10 @@ _SafeFetch32_continuation: # # %rdi : address # %rsi : defaultval - .type SafeFetchN_impl,@function -SafeFetchN_impl: -_SafeFetchN_fault: +DECLARE_FUNC(SafeFetchN_impl): +DECLARE_FUNC(_SafeFetchN_fault): movq (%rdi), %rax # load target value, may fault ret -_SafeFetchN_continuation: +DECLARE_FUNC(_SafeFetchN_continuation): movq %rsi, %rax # return default ret From aa4c83a5bfe146714a46fb454aafc7393d2d8453 Mon Sep 17 00:00:00 2001 From: Adam Sotona Date: Tue, 28 May 2024 12:29:30 +0000 Subject: [PATCH 70/99] 8332505: JEP 457: ClassRemapper forgets to remap bootstrap method references Reviewed-by: jlahoda --- .../jdk/internal/classfile/impl/ClassRemapperImpl.java | 4 ++-- .../jdk/jdk/classfile/AdvancedTransformationsTest.java | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java index de6128a9f7f..d1a02d9a93c 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.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 @@ -239,7 +239,7 @@ public CodeTransform asCodeTransform() { ii.isInterface()); case InvokeDynamicInstruction idi -> cob.invokedynamic(DynamicCallSiteDesc.of( - idi.bootstrapMethod(), idi.name().stringValue(), + mapDirectMethodHandle(idi.bootstrapMethod()), idi.name().stringValue(), mapMethodDesc(idi.typeSymbol()), idi.bootstrapArgs().stream().map(this::mapConstantValue).toArray(ConstantDesc[]::new))); case NewObjectInstruction c -> diff --git a/test/jdk/jdk/classfile/AdvancedTransformationsTest.java b/test/jdk/jdk/classfile/AdvancedTransformationsTest.java index 2ef7dca11ae..88792eedcf1 100644 --- a/test/jdk/jdk/classfile/AdvancedTransformationsTest.java +++ b/test/jdk/jdk/classfile/AdvancedTransformationsTest.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,7 @@ /* * @test * @summary Testing ClassFile advanced transformations. + * @bug 8332505 * @run junit AdvancedTransformationsTest */ import helpers.ByteArrayClassLoader; @@ -65,6 +66,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import java.lang.runtime.ObjectMethods; import java.util.ArrayDeque; import jdk.internal.classfile.impl.AbstractPseudoInstruction; @@ -187,9 +189,10 @@ void testRemapDetails() throws Exception { var fooAnno = ClassDesc.ofDescriptor(FooAnno.class.descriptorString()); var barAnno = ClassDesc.ofDescriptor(BarAnno.class.descriptorString()); var rec = ClassDesc.ofDescriptor(Rec.class.descriptorString()); + var objectMethods = ClassDesc.ofDescriptor(ObjectMethods.class.descriptorString()); var cc = ClassFile.of(); var remapped = cc.parse( - ClassRemapper.of(Map.of(foo, bar, fooAnno, barAnno)).remapClass( + ClassRemapper.of(Map.of(foo, bar, fooAnno, barAnno, objectMethods, bar)).remapClass( cc, cc.parse( Rec.class.getResourceAsStream(Rec.class.getName() + ".class") @@ -211,7 +214,8 @@ void testRemapDetails() throws Exception { "PUTSTATIC, owner: AdvancedTransformationsTest$Bar, field name: fooField, field type: LAdvancedTransformationsTest$Bar;", "INVOKESTATIC, owner: AdvancedTransformationsTest$Bar, method name: fooMethod, method type: (LAdvancedTransformationsTest$Bar;)LAdvancedTransformationsTest$Bar", "method type: ()LAdvancedTransformationsTest$Bar;", - "GETFIELD, owner: AdvancedTransformationsTest$Rec, field name: foo, field type: LAdvancedTransformationsTest$Bar;"); + "GETFIELD, owner: AdvancedTransformationsTest$Rec, field name: foo, field type: LAdvancedTransformationsTest$Bar;", + "bootstrap method: STATIC AdvancedTransformationsTest$Bar::bootstrap"); assertFalse(out.contains("bootstrap method arguments indexes: []"), "bootstrap arguments lost"); } From 7b52d0acfc7d6083b407efa0877c139e9837f86b Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Tue, 28 May 2024 12:54:37 +0000 Subject: [PATCH 71/99] 8332265: RISC-V: Materialize pointers faster by using a temp register Reviewed-by: fyang, luhenry, mli --- .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 2 +- .../cpu/riscv/jvmciCodeInstaller_riscv.cpp | 6 +- .../cpu/riscv/macroAssembler_riscv.cpp | 140 +++++++++++++----- .../cpu/riscv/macroAssembler_riscv.hpp | 21 ++- src/hotspot/cpu/riscv/nativeInst_riscv.cpp | 30 +++- src/hotspot/cpu/riscv/nativeInst_riscv.hpp | 74 +++++---- src/hotspot/cpu/riscv/riscv.ad | 13 +- src/hotspot/cpu/riscv/upcallLinker_riscv.cpp | 2 +- 8 files changed, 199 insertions(+), 89 deletions(-) diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp index a15405f5323..b3168310e56 100644 --- a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -135,7 +135,7 @@ static jlong as_long(LIR_Opr data) { Address LIR_Assembler::as_Address(LIR_Address* addr, Register tmp) { if (addr->base()->is_illegal()) { assert(addr->index()->is_illegal(), "must be illegal too"); - __ movptr(tmp, addr->disp()); + __ movptr(tmp, (address)addr->disp()); return Address(tmp, 0); } diff --git a/src/hotspot/cpu/riscv/jvmciCodeInstaller_riscv.cpp b/src/hotspot/cpu/riscv/jvmciCodeInstaller_riscv.cpp index a7160bd7241..35bfbb1df8e 100644 --- a/src/hotspot/cpu/riscv/jvmciCodeInstaller_riscv.cpp +++ b/src/hotspot/cpu/riscv/jvmciCodeInstaller_riscv.cpp @@ -42,8 +42,10 @@ jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, JVMC return pc_offset + NativeCall::instruction_size; } else if (inst->is_jump()) { return pc_offset + NativeJump::instruction_size; - } else if (inst->is_movptr()) { - return pc_offset + NativeMovConstReg::movptr_instruction_size; + } else if (inst->is_movptr1()) { + return pc_offset + NativeMovConstReg::movptr1_instruction_size; + } else if (inst->is_movptr2()) { + return pc_offset + NativeMovConstReg::movptr2_instruction_size; } else { JVMCI_ERROR_0("unsupported type of instruction for call site"); } diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 836faccc0f6..78ea3af28be 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -640,7 +640,7 @@ void MacroAssembler::emit_static_call_stub() { // Jump to the entry point of the c2i stub. int32_t offset = 0; - movptr(t0, 0, offset); + movptr(t0, 0, offset, t1); // lui + lui + slli + add jr(t0, offset); } @@ -1425,15 +1425,34 @@ static int patch_offset_in_pc_relative(address branch, int64_t offset) { return PC_RELATIVE_INSTRUCTION_NUM * NativeInstruction::instruction_size; } -static int patch_addr_in_movptr(address branch, address target) { - const int MOVPTR_INSTRUCTIONS_NUM = 6; // lui + addi + slli + addi + slli + addi/jalr/load +static int patch_addr_in_movptr1(address branch, address target) { int32_t lower = ((intptr_t)target << 35) >> 35; int64_t upper = ((intptr_t)target - lower) >> 29; Assembler::patch(branch + 0, 31, 12, upper & 0xfffff); // Lui. target[48:29] + target[28] ==> branch[31:12] Assembler::patch(branch + 4, 31, 20, (lower >> 17) & 0xfff); // Addi. target[28:17] ==> branch[31:20] Assembler::patch(branch + 12, 31, 20, (lower >> 6) & 0x7ff); // Addi. target[16: 6] ==> branch[31:20] Assembler::patch(branch + 20, 31, 20, lower & 0x3f); // Addi/Jalr/Load. target[ 5: 0] ==> branch[31:20] - return MOVPTR_INSTRUCTIONS_NUM * NativeInstruction::instruction_size; + return NativeMovConstReg::movptr1_instruction_size; +} + +static int patch_addr_in_movptr2(address instruction_address, address target) { + uintptr_t addr = (uintptr_t)target; + + assert(addr < (1ull << 48), "48-bit overflow in address constant"); + unsigned int upper18 = (addr >> 30ull); + int lower30 = (addr & 0x3fffffffu); + int low12 = (lower30 << 20) >> 20; + int mid18 = ((lower30 - low12) >> 12); + + Assembler::patch(instruction_address + (NativeInstruction::instruction_size * 0), 31, 12, (upper18 & 0xfffff)); // Lui + Assembler::patch(instruction_address + (NativeInstruction::instruction_size * 1), 31, 12, (mid18 & 0xfffff)); // Lui + // Slli + // Add + Assembler::patch(instruction_address + (NativeInstruction::instruction_size * 4), 31, 20, low12 & 0xfff); // Addi/Jalr/Load + + assert(MacroAssembler::target_addr_for_insn(instruction_address) == target, "Must be"); + + return NativeMovConstReg::movptr2_instruction_size; } static int patch_imm_in_li64(address branch, address target) { @@ -1507,7 +1526,7 @@ static long get_offset_of_pc_relative(address insn_addr) { return offset; } -static address get_target_of_movptr(address insn_addr) { +static address get_target_of_movptr1(address insn_addr) { assert_cond(insn_addr != nullptr); intptr_t target_address = (((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr), 31, 12)) & 0xfffff) << 29; // Lui. target_address += ((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr + 4), 31, 20)) << 17; // Addi. @@ -1516,6 +1535,17 @@ static address get_target_of_movptr(address insn_addr) { return (address) target_address; } +static address get_target_of_movptr2(address insn_addr) { + assert_cond(insn_addr != nullptr); + int32_t upper18 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + NativeInstruction::instruction_size * 0), 31, 12)) & 0xfffff); // Lui + int32_t mid18 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + NativeInstruction::instruction_size * 1), 31, 12)) & 0xfffff); // Lui + // 2 // Slli + // 3 // Add + int32_t low12 = ((Assembler::sextract(Assembler::ld_instr(insn_addr + NativeInstruction::instruction_size * 4), 31, 20))); // Addi/Jalr/Load. + address ret = (address)(((intptr_t)upper18<<30ll) + ((intptr_t)mid18<<12ll) + low12); + return ret; +} + static address get_target_of_li64(address insn_addr) { assert_cond(insn_addr != nullptr); intptr_t target_address = (((int64_t)Assembler::sextract(Assembler::ld_instr(insn_addr), 31, 12)) & 0xfffff) << 44; // Lui. @@ -1535,30 +1565,32 @@ address MacroAssembler::get_target_of_li32(address insn_addr) { // Patch any kind of instruction; there may be several instructions. // Return the total length (in bytes) of the instructions. -int MacroAssembler::pd_patch_instruction_size(address branch, address target) { - assert_cond(branch != nullptr); - int64_t offset = target - branch; - if (NativeInstruction::is_jal_at(branch)) { // jal - return patch_offset_in_jal(branch, offset); - } else if (NativeInstruction::is_branch_at(branch)) { // beq/bge/bgeu/blt/bltu/bne - return patch_offset_in_conditional_branch(branch, offset); - } else if (NativeInstruction::is_pc_relative_at(branch)) { // auipc, addi/jalr/load - return patch_offset_in_pc_relative(branch, offset); - } else if (NativeInstruction::is_movptr_at(branch)) { // movptr - return patch_addr_in_movptr(branch, target); - } else if (NativeInstruction::is_li64_at(branch)) { // li64 - return patch_imm_in_li64(branch, target); - } else if (NativeInstruction::is_li32_at(branch)) { // li32 +int MacroAssembler::pd_patch_instruction_size(address instruction_address, address target) { + assert_cond(instruction_address != nullptr); + int64_t offset = target - instruction_address; + if (NativeInstruction::is_jal_at(instruction_address)) { // jal + return patch_offset_in_jal(instruction_address, offset); + } else if (NativeInstruction::is_branch_at(instruction_address)) { // beq/bge/bgeu/blt/bltu/bne + return patch_offset_in_conditional_branch(instruction_address, offset); + } else if (NativeInstruction::is_pc_relative_at(instruction_address)) { // auipc, addi/jalr/load + return patch_offset_in_pc_relative(instruction_address, offset); + } else if (NativeInstruction::is_movptr1_at(instruction_address)) { // movptr1 + return patch_addr_in_movptr1(instruction_address, target); + } else if (NativeInstruction::is_movptr2_at(instruction_address)) { // movptr2 + return patch_addr_in_movptr2(instruction_address, target); + } else if (NativeInstruction::is_li64_at(instruction_address)) { // li64 + return patch_imm_in_li64(instruction_address, target); + } else if (NativeInstruction::is_li32_at(instruction_address)) { // li32 int64_t imm = (intptr_t)target; - return patch_imm_in_li32(branch, (int32_t)imm); - } else if (NativeInstruction::is_li16u_at(branch)) { + return patch_imm_in_li32(instruction_address, (int32_t)imm); + } else if (NativeInstruction::is_li16u_at(instruction_address)) { int64_t imm = (intptr_t)target; - return patch_imm_in_li16u(branch, (uint16_t)imm); + return patch_imm_in_li16u(instruction_address, (uint16_t)imm); } else { #ifdef ASSERT tty->print_cr("pd_patch_instruction_size: instruction 0x%x at " INTPTR_FORMAT " could not be patched!\n", - Assembler::ld_instr(branch), p2i(branch)); - Disassembler::decode(branch - 16, branch + 16); + Assembler::ld_instr(instruction_address), p2i(instruction_address)); + Disassembler::decode(instruction_address - 16, instruction_address + 16); #endif ShouldNotReachHere(); return -1; @@ -1574,8 +1606,10 @@ address MacroAssembler::target_addr_for_insn(address insn_addr) { offset = get_offset_of_conditional_branch(insn_addr); } else if (NativeInstruction::is_pc_relative_at(insn_addr)) { // auipc, addi/jalr/load offset = get_offset_of_pc_relative(insn_addr); - } else if (NativeInstruction::is_movptr_at(insn_addr)) { // movptr - return get_target_of_movptr(insn_addr); + } else if (NativeInstruction::is_movptr1_at(insn_addr)) { // movptr1 + return get_target_of_movptr1(insn_addr); + } else if (NativeInstruction::is_movptr2_at(insn_addr)) { // movptr2 + return get_target_of_movptr2(insn_addr); } else if (NativeInstruction::is_li64_at(insn_addr)) { // li64 return get_target_of_li64(insn_addr); } else if (NativeInstruction::is_li32_at(insn_addr)) { // li32 @@ -1594,9 +1628,12 @@ int MacroAssembler::patch_oop(address insn_addr, address o) { // Move narrow OOP uint32_t n = CompressedOops::narrow_oop_value(cast_to_oop(o)); return patch_imm_in_li32(insn_addr, (int32_t)n); - } else if (NativeInstruction::is_movptr_at(insn_addr)) { + } else if (NativeInstruction::is_movptr1_at(insn_addr)) { + // Move wide OOP + return patch_addr_in_movptr1(insn_addr, o); + } else if (NativeInstruction::is_movptr2_at(insn_addr)) { // Move wide OOP - return patch_addr_in_movptr(insn_addr, o); + return patch_addr_in_movptr2(insn_addr, o); } ShouldNotReachHere(); return -1; @@ -1617,16 +1654,31 @@ void MacroAssembler::reinit_heapbase() { } } -void MacroAssembler::movptr(Register Rd, address addr, int32_t &offset) { - int64_t imm64 = (int64_t)addr; +void MacroAssembler::movptr(Register Rd, address addr, Register temp) { + int offset = 0; + movptr(Rd, addr, offset, temp); + addi(Rd, Rd, offset); +} + +void MacroAssembler::movptr(Register Rd, address addr, int32_t &offset, Register temp) { + uint64_t uimm64 = (uint64_t)addr; #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%" PRIx64, imm64); + snprintf(buffer, sizeof(buffer), "0x%" PRIx64, uimm64); block_comment(buffer); } #endif - assert((uintptr_t)imm64 < (1ull << 48), "48-bit overflow in address constant"); + assert(uimm64 < (1ull << 48), "48-bit overflow in address constant"); + + if (temp == noreg) { + movptr1(Rd, uimm64, offset); + } else { + movptr2(Rd, uimm64, offset, temp); + } +} + +void MacroAssembler::movptr1(Register Rd, uint64_t imm64, int32_t &offset) { // Load upper 31 bits int64_t imm = imm64 >> 17; int64_t upper = imm, lower = imm; @@ -1645,6 +1697,23 @@ void MacroAssembler::movptr(Register Rd, address addr, int32_t &offset) { offset = imm64 & 0x3f; } +void MacroAssembler::movptr2(Register Rd, uint64_t addr, int32_t &offset, Register tmp) { + assert_different_registers(Rd, tmp, noreg); + + uint32_t upper18 = (addr >> 30ull); + int32_t lower30 = (addr & 0x3fffffffu); + int32_t low12 = (lower30 << 20) >> 20; + int32_t mid18 = ((lower30 - low12) >> 12); + + lui(tmp, upper18 << 12); + lui(Rd, mid18 << 12); + + slli(tmp, tmp, 18); + add(Rd, Rd, tmp); + + offset = low12; +} + void MacroAssembler::add(Register Rd, Register Rn, int64_t increment, Register temp) { if (is_simm12(increment)) { addi(Rd, Rn, increment); @@ -2120,6 +2189,7 @@ void MacroAssembler::movoop(Register dst, jobject obj) { // Move a metadata address into a register. void MacroAssembler::mov_metadata(Register dst, Metadata* obj) { + assert((uintptr_t)obj < (1ull << 48), "48-bit overflow in metadata"); int oop_index; if (obj == nullptr) { oop_index = oop_recorder()->allocate_metadata_index(obj); @@ -3554,7 +3624,7 @@ address MacroAssembler::trampoline_call(Address entry) { address MacroAssembler::ic_call(address entry, jint method_index) { RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); IncompressibleRegion ir(this); // relocations - movptr(t1, (address)Universe::non_oop_word()); + movptr(t1, (address)Universe::non_oop_word(), t0); assert_cond(entry != nullptr); return trampoline_call(Address(entry, rh)); } @@ -3661,8 +3731,8 @@ int MacroAssembler::max_trampoline_stub_size() { } int MacroAssembler::static_call_stub_size() { - // (lui, addi, slli, addi, slli, addi) + (lui, addi, slli, addi, slli) + jalr - return 12 * NativeInstruction::instruction_size; + // (lui, addi, slli, addi, slli, addi) + (lui + lui + slli + add) + jalr + return 11 * NativeInstruction::instruction_size; } Address MacroAssembler::add_memory_helper(const Address dst, Register tmp) { diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 4e52cdaee38..e5800b0aa91 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -804,17 +804,16 @@ class MacroAssembler: public Assembler { } } - void movptr(Register Rd, address addr, int32_t &offset); - - void movptr(Register Rd, address addr) { - int offset = 0; - movptr(Rd, addr, offset); - addi(Rd, Rd, offset); - } - - inline void movptr(Register Rd, uintptr_t imm64) { - movptr(Rd, (address)imm64); - } + // Generates a load of a 48-bit constant which can be + // patched to any 48-bit constant, i.e. address. + // If common case supply additional temp register + // to shorten the instruction sequence. + void movptr(Register Rd, address addr, Register tmp = noreg); + void movptr(Register Rd, address addr, int32_t &offset, Register tmp = noreg); + private: + void movptr1(Register Rd, uintptr_t addr, int32_t &offset); + void movptr2(Register Rd, uintptr_t addr, int32_t &offset, Register tmp); + public: // arith void add (Register Rd, Register Rn, int64_t increment, Register temp = t0); diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index 399de3a2805..dd54329e521 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -84,7 +84,7 @@ bool NativeInstruction::is_load_pc_relative_at(address instr) { check_load_pc_relative_data_dependency(instr); } -bool NativeInstruction::is_movptr_at(address instr) { +bool NativeInstruction::is_movptr1_at(address instr) { return is_lui_at(instr) && // Lui is_addi_at(instr + instruction_size) && // Addi is_slli_shift_at(instr + instruction_size * 2, 11) && // Slli Rd, Rs, 11 @@ -93,7 +93,18 @@ bool NativeInstruction::is_movptr_at(address instr) { (is_addi_at(instr + instruction_size * 5) || is_jalr_at(instr + instruction_size * 5) || is_load_at(instr + instruction_size * 5)) && // Addi/Jalr/Load - check_movptr_data_dependency(instr); + check_movptr1_data_dependency(instr); +} + +bool NativeInstruction::is_movptr2_at(address instr) { + return is_lui_at(instr) && // lui + is_lui_at(instr + instruction_size) && // lui + is_slli_shift_at(instr + instruction_size * 2, 18) && // slli Rd, Rs, 18 + is_add_at(instr + instruction_size * 3) && + (is_addi_at(instr + instruction_size * 4) || + is_jalr_at(instr + instruction_size * 4) || + is_load_at(instr + instruction_size * 4)) && // Addi/Jalr/Load + check_movptr2_data_dependency(instr); } bool NativeInstruction::is_li16u_at(address instr) { @@ -201,10 +212,11 @@ void NativeCall::insert(address code_pos, address entry) { Unimplemented(); } //------------------------------------------------------------------- void NativeMovConstReg::verify() { - if (!(nativeInstruction_at(instruction_address())->is_movptr() || - is_auipc_at(instruction_address()))) { - fatal("should be MOVPTR or AUIPC"); + NativeInstruction* ni = nativeInstruction_at(instruction_address()); + if (ni->is_movptr() || ni->is_auipc()) { + return; } + fatal("should be MOVPTR or AUIPC"); } intptr_t NativeMovConstReg::data() const { @@ -223,7 +235,7 @@ void NativeMovConstReg::set_data(intptr_t x) { } else { // Store x into the instruction stream. MacroAssembler::pd_patch_instruction_size(instruction_address(), (address)x); - ICache::invalidate_range(instruction_address(), movptr_instruction_size); + ICache::invalidate_range(instruction_address(), movptr1_instruction_size /* > movptr2_instruction_size */ ); } // Find and replace the oop/metadata corresponding to this @@ -393,13 +405,15 @@ void NativeJump::patch_verified_entry(address entry, address verified_entry, add ICache::invalidate_range(verified_entry, instruction_size); } +//------------------------------------------------------------------- + void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { CodeBuffer cb(code_pos, instruction_size); MacroAssembler a(&cb); Assembler::IncompressibleRegion ir(&a); // Fixed length: see NativeGeneralJump::get_instruction_size() int32_t offset = 0; - a.movptr(t0, entry, offset); // lui, addi, slli, addi, slli + a.movptr(t0, entry, offset, t1); // lui, lui, slli, add a.jr(t0, offset); // jalr ICache::invalidate_range(code_pos, instruction_size); @@ -410,6 +424,8 @@ void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) ShouldNotCallThis(); } +//------------------------------------------------------------------- + address NativeCallTrampolineStub::destination(nmethod *nm) const { return ptr_at(data_offset); } diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp index 48bbb2b3b18..dcdf525aafb 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp @@ -64,7 +64,11 @@ class NativeInstruction { } bool is_jal() const { return is_jal_at(addr_at(0)); } - bool is_movptr() const { return is_movptr_at(addr_at(0)); } + bool is_movptr() const { return is_movptr1_at(addr_at(0)) || + is_movptr2_at(addr_at(0)); } + bool is_movptr1() const { return is_movptr1_at(addr_at(0)); } + bool is_movptr2() const { return is_movptr2_at(addr_at(0)); } + bool is_auipc() const { return is_auipc_at(addr_at(0)); } bool is_call() const { return is_call_at(addr_at(0)); } bool is_jump() const { return is_jump_at(addr_at(0)); } @@ -76,9 +80,10 @@ class NativeInstruction { static bool is_float_load_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0000111; } static bool is_auipc_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0010111; } static bool is_jump_at(address instr) { assert_cond(instr != nullptr); return is_branch_at(instr) || is_jal_at(instr) || is_jalr_at(instr); } + static bool is_add_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0110011 && extract_funct3(instr) == 0b000; } static bool is_addi_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0010011 && extract_funct3(instr) == 0b000; } static bool is_addiw_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0011011 && extract_funct3(instr) == 0b000; } - static bool is_addiw_to_zr_at(address instr) { assert_cond(instr != nullptr); return is_addiw_at(instr) && extract_rd(instr) == zr; } + static bool is_addiw_to_zr_at(address instr){ assert_cond(instr != nullptr); return is_addiw_at(instr) && extract_rd(instr) == zr; } static bool is_lui_at(address instr) { assert_cond(instr != nullptr); return extract_opcode(instr) == 0b0110111; } static bool is_lui_to_zr_at(address instr) { assert_cond(instr != nullptr); return is_lui_at(instr) && extract_rd(instr) == zr; } @@ -109,7 +114,7 @@ class NativeInstruction { // addi // slli // addi/jalr/load - static bool check_movptr_data_dependency(address instr) { + static bool check_movptr1_data_dependency(address instr) { address lui = instr; address addi1 = lui + instruction_size; address slli1 = addi1 + instruction_size; @@ -127,6 +132,26 @@ class NativeInstruction { extract_rs1(last_instr) == extract_rd(slli2); } + // the instruction sequence of movptr2 is as below: + // lui + // lui + // slli + // add + // addi/jalr/load + static bool check_movptr2_data_dependency(address instr) { + address lui1 = instr; + address lui2 = lui1 + instruction_size; + address slli = lui2 + instruction_size; + address add = slli + instruction_size; + address last_instr = add + instruction_size; + return extract_rd(add) == extract_rd(lui2) && + extract_rs1(add) == extract_rd(lui2) && + extract_rs2(add) == extract_rd(slli) && + extract_rs1(slli) == extract_rd(lui1) && + extract_rd(slli) == extract_rd(lui1) && + extract_rs1(last_instr) == extract_rd(add); + } + // the instruction sequence of li64 is as below: // lui // addi @@ -204,7 +229,8 @@ class NativeInstruction { extract_rs1(load) == extract_rd(load); } - static bool is_movptr_at(address instr); + static bool is_movptr1_at(address instr); + static bool is_movptr2_at(address instr); static bool is_li16u_at(address instr); static bool is_li32_at(address instr); static bool is_li64_at(address instr); @@ -351,26 +377,33 @@ inline NativeCall* nativeCall_before(address return_address) { class NativeMovConstReg: public NativeInstruction { public: enum RISCV_specific_constants { - movptr_instruction_size = 6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, addi. See movptr(). - load_pc_relative_instruction_size = 2 * NativeInstruction::instruction_size, // auipc, ld - instruction_offset = 0, - displacement_offset = 0 + movptr1_instruction_size = 6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, addi. See movptr1(). + movptr2_instruction_size = 5 * NativeInstruction::instruction_size, // lui, lui, slli, add, addi. See movptr2(). + load_pc_relative_instruction_size = 2 * NativeInstruction::instruction_size // auipc, ld }; - address instruction_address() const { return addr_at(instruction_offset); } + address instruction_address() const { return addr_at(0); } address next_instruction_address() const { // if the instruction at 5 * instruction_size is addi, // it means a lui + addi + slli + addi + slli + addi instruction sequence, // and the next instruction address should be addr_at(6 * instruction_size). // However, when the instruction at 5 * instruction_size isn't addi, // the next instruction address should be addr_at(5 * instruction_size) - if (nativeInstruction_at(instruction_address())->is_movptr()) { - if (is_addi_at(addr_at(movptr_instruction_size - NativeInstruction::instruction_size))) { + if (is_movptr1_at(instruction_address())) { + if (is_addi_at(addr_at(movptr1_instruction_size - NativeInstruction::instruction_size))) { // Assume: lui, addi, slli, addi, slli, addi - return addr_at(movptr_instruction_size); + return addr_at(movptr1_instruction_size); } else { // Assume: lui, addi, slli, addi, slli - return addr_at(movptr_instruction_size - NativeInstruction::instruction_size); + return addr_at(movptr1_instruction_size - NativeInstruction::instruction_size); + } + } else if (is_movptr2_at(instruction_address())) { + if (is_addi_at(addr_at(movptr2_instruction_size - NativeInstruction::instruction_size))) { + // Assume: lui, lui, slli, add, addi + return addr_at(movptr2_instruction_size); + } else { + // Assume: lui, lui, slli, add + return addr_at(movptr2_instruction_size - NativeInstruction::instruction_size); } } else if (is_load_pc_relative_at(instruction_address())) { // Assume: auipc, ld @@ -383,12 +416,6 @@ class NativeMovConstReg: public NativeInstruction { intptr_t data() const; void set_data(intptr_t x); - void flush() { - if (!maybe_cpool_ref(instruction_address())) { - ICache::invalidate_range(instruction_address(), movptr_instruction_size); - } - } - void verify(); void print(); @@ -399,14 +426,14 @@ class NativeMovConstReg: public NativeInstruction { inline NativeMovConstReg* nativeMovConstReg_at(address addr) { assert_cond(addr != nullptr); - NativeMovConstReg* test = (NativeMovConstReg*)(addr - NativeMovConstReg::instruction_offset); + NativeMovConstReg* test = (NativeMovConstReg*)(addr); DEBUG_ONLY(test->verify()); return test; } inline NativeMovConstReg* nativeMovConstReg_before(address addr) { assert_cond(addr != nullptr); - NativeMovConstReg* test = (NativeMovConstReg*)(addr - NativeMovConstReg::instruction_size - NativeMovConstReg::instruction_offset); + NativeMovConstReg* test = (NativeMovConstReg*)(addr - NativeMovConstReg::instruction_size); DEBUG_ONLY(test->verify()); return test; } @@ -484,10 +511,7 @@ inline NativeJump* nativeJump_at(address addr) { class NativeGeneralJump: public NativeJump { public: enum RISCV_specific_constants { - instruction_size = 6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, jalr - instruction_offset = 0, - data_offset = 0, - next_instruction_offset = 6 * NativeInstruction::instruction_size // lui, addi, slli, addi, slli, jalr + instruction_size = 5 * NativeInstruction::instruction_size, // lui, lui, slli, add, jalr }; address jump_destination() const; diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index a0d1b1921cd..8b28ec88efd 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1244,7 +1244,7 @@ int MachCallStaticJavaNode::ret_addr_offset() int MachCallDynamicJavaNode::ret_addr_offset() { - return 7 * NativeInstruction::instruction_size; // movptr, jal + return NativeMovConstReg::movptr2_instruction_size + NativeInstruction::instruction_size; // movptr2, jal } int MachCallRuntimeNode::ret_addr_offset() { @@ -1285,12 +1285,11 @@ int CallStaticJavaDirectNode::compute_padding(int current_offset) const // ensure that it does not span a cache line so that it can be patched. int CallDynamicJavaDirectNode::compute_padding(int current_offset) const { - // skip the movptr in MacroAssembler::ic_call(): - // lui + addi + slli + addi + slli + addi - // Though movptr() has already 4-byte aligned with or without RVC, + // skip the movptr2 in MacroAssembler::ic_call(): + // lui, lui, slli, add, addi + // Though movptr2() has already 4-byte aligned with or without RVC, // We need to prevent from further changes by explicitly calculating the size. - const int movptr_size = 6 * NativeInstruction::instruction_size; - current_offset += movptr_size; + current_offset += NativeMovConstReg::movptr2_instruction_size; // to make sure the address of jal 4-byte aligned. return align_up(current_offset, alignment_required()) - current_offset; } @@ -10014,7 +10013,7 @@ instruct CallDynamicJavaDirect(method meth, rFlagsReg cr) effect(USE meth, KILL cr); - ins_cost(BRANCH_COST + ALU_COST * 6); + ins_cost(BRANCH_COST + ALU_COST * 5); format %{ "CALL,dynamic $meth\t#@CallDynamicJavaDirect" %} diff --git a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp index 8a6557dde93..383f332f8fd 100644 --- a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp +++ b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp @@ -223,7 +223,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ la(c_rarg0, Address(sp, frame_data_offset)); - __ movptr(c_rarg1, (intptr_t) receiver); + __ movptr(c_rarg1, (address) receiver); __ rt_call(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry)); __ mv(xthread, x10); __ reinit_heapbase(); From e708d135e3af7e0652cdbb680388a0735582ba74 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Tue, 28 May 2024 13:08:02 +0000 Subject: [PATCH 72/99] 8332064: Implementation of Structured Concurrency (Third Preview) Reviewed-by: jpai, bpb, mcimadamore --- .../share/classes/jdk/internal/javac/PreviewFeature.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index f95ffd0e402..ca63f714f34 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -73,7 +73,7 @@ public enum Feature { IMPLICIT_CLASSES, @JEP(number=464, title="Scoped Values", status="Second Preview") SCOPED_VALUES, - @JEP(number=462, title="Structured Concurrency", status="Second Preview") + @JEP(number=480, title="Structured Concurrency", status="Third Preview") STRUCTURED_CONCURRENCY, @JEP(number=466, title="ClassFile API", status="Second Preview") CLASSFILE_API, From 87a06b6ce41f8623d9111b4e41c72f0ddf842acd Mon Sep 17 00:00:00 2001 From: Archie Cobbs Date: Tue, 28 May 2024 13:15:20 +0000 Subject: [PATCH 73/99] 8325805: Compiler Implementation for Flexible Constructor Bodies (Second Preview) Reviewed-by: vromero, jlahoda --- .../com/sun/tools/javac/code/Preview.java | 2 +- .../com/sun/tools/javac/code/Source.java | 2 +- .../com/sun/tools/javac/comp/Attr.java | 22 ++- .../com/sun/tools/javac/comp/Check.java | 4 +- .../com/sun/tools/javac/comp/Resolve.java | 69 +++++++- .../tools/javac/resources/compiler.properties | 8 +- .../DefiniteAssignment/DA_DUConstructors.java | 51 ++++++ .../DefiniteAssignment/DA_DUConstructors.out | 5 + .../javac/SuperInit/EarlyAssignments.java | 161 ++++++++++++++++++ .../javac/SuperInit/EarlyAssignments.out | 28 +++ .../javac/SuperInit/EarlyLocalClass.java | 19 +++ .../tools/javac/SuperInit/EarlyLocalClass.out | 4 + .../tools/javac/SuperInit/SuperInitFails.java | 40 +++-- .../tools/javac/SuperInit/SuperInitFails.out | 14 +- .../tools/javac/SuperInit/SuperInitGood.java | 51 ++++++ ...CantAssignInitializedBeforeCtorCalled.java | 35 ++++ ....java => FeatureFlexibleConstructors.java} | 8 +- 17 files changed, 494 insertions(+), 29 deletions(-) create mode 100644 test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java create mode 100644 test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out create mode 100644 test/langtools/tools/javac/SuperInit/EarlyAssignments.java create mode 100644 test/langtools/tools/javac/SuperInit/EarlyAssignments.out create mode 100644 test/langtools/tools/javac/SuperInit/EarlyLocalClass.java create mode 100644 test/langtools/tools/javac/SuperInit/EarlyLocalClass.out create mode 100644 test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java rename test/langtools/tools/javac/diags/examples/{FeatureStatementsBeforeSuper.java => FeatureFlexibleConstructors.java} (85%) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java index 6af766effa5..5e9a75a0b6b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java @@ -208,7 +208,7 @@ public boolean isEnabled() { public boolean isPreview(Feature feature) { return switch (feature) { case IMPLICIT_CLASSES -> true; - case SUPER_INIT -> true; + case FLEXIBLE_CONSTRUCTORS -> true; case PRIMITIVE_PATTERNS -> true; case MODULE_IMPORTS -> true; //Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing). diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java index f1cc1e89272..6288cbfb01b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java @@ -254,7 +254,7 @@ public enum Feature { WARN_ON_ILLEGAL_UTF8(MIN, JDK21), UNNAMED_VARIABLES(JDK22, Fragments.FeatureUnnamedVariables, DiagKind.PLURAL), PRIMITIVE_PATTERNS(JDK23, Fragments.FeaturePrimitivePatterns, DiagKind.PLURAL), - SUPER_INIT(JDK22, Fragments.FeatureSuperInit, DiagKind.NORMAL), + FLEXIBLE_CONSTRUCTORS(JDK22, Fragments.FeatureFlexibleConstructors, DiagKind.NORMAL), MODULE_IMPORTS(JDK23, Fragments.FeatureModuleImports, DiagKind.PLURAL), ; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index d0f3ae7464a..8a67d9f8870 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -293,7 +293,9 @@ boolean isAssignableAsBlankFinal(VarSymbol v, Env env) { void checkAssignable(DiagnosticPosition pos, VarSymbol v, JCTree base, Env env) { if (v.name == names._this) { log.error(pos, Errors.CantAssignValToThis); - } else if ((v.flags() & FINAL) != 0 && + return; + } + if ((v.flags() & FINAL) != 0 && ((v.flags() & HASINIT) != 0 || !((base == null || @@ -304,6 +306,23 @@ void checkAssignable(DiagnosticPosition pos, VarSymbol v, JCTree base, Env env, Name name) { (sym.flags() & STATIC) == 0) { if (staticOnly) return new StaticError(sym); - if (env1.info.ctorPrologue && (sym.flags_field & SYNTHETIC) == 0) + if (env1.info.ctorPrologue && !isAllowedEarlyReference(env1, (VarSymbol)sym)) return new RefBeforeCtorCalledError(sym); } return sym; @@ -3766,6 +3766,7 @@ Symbol resolveSelf(DiagnosticPosition pos, Env env, TypeSymbol c, Name name) { + Assert.check(name == names._this || name == names._super); Env env1 = env; boolean staticOnly = false; while (env1.outer != null) { @@ -3775,7 +3776,7 @@ Symbol resolveSelf(DiagnosticPosition pos, if (sym != null) { if (staticOnly) sym = new StaticError(sym); - else if (env1.info.ctorPrologue) + else if (env1.info.ctorPrologue && !isAllowedEarlyReference(env1, (VarSymbol)sym)) sym = new RefBeforeCtorCalledError(sym); return accessBase(sym, pos, env.enclClass.sym.type, name, true); @@ -3828,6 +3829,70 @@ private List pruneInterfaces(Type t) { return result.toList(); } + /** + * Determine if an early instance field reference may appear in a constructor prologue. + * + *

    + * This is only allowed when: + * - The field is being assigned a value (i.e., written but not read) + * - The field is not inherited from a superclass + * - The assignment is not within a lambda, because that would require + * capturing 'this' which is not allowed prior to super(). + * + *

    + * Note, this method doesn't catch all such scenarios, because this method + * is invoked for symbol "x" only for "x = 42" but not for "this.x = 42". + * We also don't verify that the field has no initializer, which is required. + * To catch those cases, we rely on similar logic in Attr.checkAssignable(). + */ + private boolean isAllowedEarlyReference(Env env, VarSymbol v) { + + // Check assumptions + Assert.check(env.info.ctorPrologue); + Assert.check((v.flags_field & STATIC) == 0); + + // The symbol must appear in the LHS of an assignment statement + if (!(env.tree instanceof JCAssign assign)) + return false; + + // The assignment statement must not be within a lambda + if (env.info.isLambda) + return false; + + // Get the symbol's qualifier, if any + JCExpression lhs = TreeInfo.skipParens(assign.lhs); + JCExpression base = lhs instanceof JCFieldAccess select ? select.selected : null; + + // If an early reference, the field must not be declared in a superclass + if (isEarlyReference(env, base, v) && v.owner != env.enclClass.sym) + return false; + + // OK + return true; + } + + /** + * Determine if the variable appearance constitutes an early reference to the current class. + * + *

    + * This means the variable is an instance field of the current class and it appears + * in an early initialization context of it (i.e., one of its constructor prologues). + * + *

    + * Such a reference is only allowed for assignments to non-initialized fields that are + * not inherited from a superclass, though that is not enforced by this method. + * + * @param env The current environment + * @param base Variable qualifier, if any, otherwise null + * @param v The variable + */ + public boolean isEarlyReference(Env env, JCTree base, VarSymbol v) { + return env.info.ctorPrologue && + (v.flags() & STATIC) == 0 && + v.owner.kind == TYP && + types.isSubtype(env.enclClass.type, v.owner.type) && + (base == null || TreeInfo.isExplicitThisReference(types, (ClassType)env.enclClass.type, base)); + } /** * Resolve `c.this' for an enclosing class c that contains the diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index a37d9041f43..74281b4ea0d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -399,6 +399,10 @@ compiler.err.cant.inherit.from.final=\ compiler.err.cant.ref.before.ctor.called=\ cannot reference {0} before supertype constructor has been called +# 0: symbol or name +compiler.err.cant.assign.initialized.before.ctor.called=\ + cannot assign initialized field ''{0}'' before supertype constructor has been called + compiler.err.cant.select.static.class.from.param.type=\ cannot select a static class from a parameterized type @@ -3215,8 +3219,8 @@ compiler.misc.feature.unconditional.patterns.in.instanceof=\ compiler.misc.feature.implicit.classes=\ implicitly declared classes -compiler.misc.feature.super.init=\ - statements before super() +compiler.misc.feature.flexible.constructors=\ + flexible constructors compiler.misc.feature.module.imports=\ module imports diff --git a/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java new file mode 100644 index 00000000000..7947b69b830 --- /dev/null +++ b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.java @@ -0,0 +1,51 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8325805 + * @summary Permit non-superclass instance field assignments before this/super in constructors + * @compile/fail/ref=DA_DUConstructors.out -XDrawDiagnostics DA_DUConstructors.java + * @enablePreview + */ + +public class DA_DUConstructors { + // identity + class C1 { + final int x; + final int y = x + 1; + C1() { + x = 12; + super(); + } + } + + class C2 { + final int x; + C2() { + this(x = 3); // error + } + C2(int i) { + x = 4; + } + } + + class C3 { + C3(int i) {} + } + class C4 extends C3 { + final int x; + C4() { + super(x = 3); // ok + } + } + + class C5 { + final int x; + final int y = x + 1; // x is not DA + C5() { + x = 12; super(); + } + C5(int i) { + /* no prologue */ + x = i; + } + } +} diff --git a/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out new file mode 100644 index 00000000000..78cd3d314a8 --- /dev/null +++ b/test/langtools/tools/javac/DefiniteAssignment/DA_DUConstructors.out @@ -0,0 +1,5 @@ +DA_DUConstructors.java:23:17: compiler.err.var.might.already.be.assigned: x +DA_DUConstructors.java:42:23: compiler.err.var.might.not.have.been.initialized: x +- compiler.note.preview.filename: DA_DUConstructors.java, DEFAULT +- compiler.note.preview.recompile +2 errors diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignments.java b/test/langtools/tools/javac/SuperInit/EarlyAssignments.java new file mode 100644 index 00000000000..89a13ccf0ff --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignments.java @@ -0,0 +1,161 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8325805 + * @summary Permit non-superclass instance field assignments before this/super in constructors + * @compile/fail/ref=EarlyAssignments.out -XDrawDiagnostics EarlyAssignments.java + * @enablePreview + */ +public class EarlyAssignments { + + public static class Inner1 { + public int x; + + public Inner1() { + x = 123; // OK - "x" belongs to this class + this.x = 123; // OK - "x" belongs to this class + Inner1.this.x = 123; // OK - "x" belongs to this class + super(); + } + + public Inner1(int y) { + y = x; // FAIL - early 'this' reference + y = this.x; // FAIL - early 'this' reference + y = Inner1.this.x; // FAIL - early 'this' reference + super(); + } + + public class Inner1a extends Inner1 { + public int z; + public Inner1a(byte value) { + Inner1.this.x = value; // OK - "x" belongs to outer class + z = super.x; // FAIL - "x" belongs to superclass + z = x; // FAIL - "x" belongs to superclass + this.z = x; // FAIL - "x" belongs to superclass + Inner1a.this.z = x; // FAIL - "x" belongs to superclass + Object o1 = Inner1.this; // OK - Inner1 is an outer class + Object o2 = Inner1a.this; // FAIL - Inner1a is this class + super(); + } + public Inner1a(short value) { + x = value; // FAIL - "x" belongs to superclass + super(); + } + public Inner1a(char value) { + this.x = value; // FAIL - "x" belongs to superclass + super(); + } + public Inner1a(int value) { + super.x = value; // FAIL - "x" belongs to superclass + super(); + } + } + + public class Inner1b { + public Inner1b(int value) { + Inner1.this.x = value; // OK - "x" belongs to outer class + super(); + } + } + } + + public static class Inner2 extends Inner1 { + int y; + public Inner2(int value) { + y = value; // OK - "y" belongs to this class + this.y = value; // OK - "y" belongs to this class + x = value; // FAIL - "x" belongs to superclass + this.x = value; // FAIL - "x" belongs to superclass + Object o1 = this; // FAIL - can't acces 'this' yet + Object o2 = Inner2.this; // FAIL - can't acces 'this' yet + super(); + } + } + + public static class Inner3 { + + public int e; + + public class Inner3a { + + public static int x; + + public Inner3a(int val) { + x = val; // OK - "x" is a static field + val = x; // OK - "x" is a static field + e = val; // OK - "e" belongs to outer class + val = e; // OK - "e" belongs to outer class + Inner3.this.e = val; // OK - "e" belongs to outer class + super(); + } + } + } + + public static class Inner4 { + public int x; + + public Inner4() { + x = 0; // OK + x = x + 1; // FAIL - illegal early access + super(); + } + + public Inner4(int a) { + this.x = 0; // OK + this.x = this.x + 1; // FAIL - illegal early access + super(); + } + + public Inner4(char a) { + Inner4.this.x = 0; // OK + Inner4.this.x = Inner4.this.x + 1; // FAIL - illegal early access + super(); + } + } + + public static class Inner5 extends Inner4 { + public int y; + + public Inner5() { + y = x + 1; // FAIL - illegal early access + super(); + } + + public Inner5(int a) { + this.y = x + 1; // FAIL - illegal early access + super(); + } + + public Inner5(char a) { + Inner5.this.y = x + 1; // FAIL - illegal early access + super(); + } + + public Inner5(short a) { + y = super.x + 1; // FAIL - illegal early access + super(); + } + + public Inner5(float a) { + y = Inner5.this.x + 1; // FAIL - illegal early access + super(); + } + } + + public static class Inner6 { + public int x = 1; + + public Inner6() { + x = 2; // FAIL - illegal early access + super(); + } + } + + public static class Inner7 { + public final int x = 1; + + public Inner7() { + x = 2; // FAIL - illegal early access + super(); + } + } +} diff --git a/test/langtools/tools/javac/SuperInit/EarlyAssignments.out b/test/langtools/tools/javac/SuperInit/EarlyAssignments.out new file mode 100644 index 00000000000..81b4f20b505 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyAssignments.out @@ -0,0 +1,28 @@ +EarlyAssignments.java:21:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:22:17: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:23:23: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:31:21: compiler.err.cant.ref.before.ctor.called: super +EarlyAssignments.java:32:21: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:33:26: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:34:34: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:36:36: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:40:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:44:21: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:48:22: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:66:13: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:67:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:68:25: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:69:31: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:98:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:104:22: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:110:35: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:119:17: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:124:22: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:129:29: compiler.err.cant.ref.before.ctor.called: x +EarlyAssignments.java:134:17: compiler.err.cant.ref.before.ctor.called: super +EarlyAssignments.java:139:23: compiler.err.cant.ref.before.ctor.called: this +EarlyAssignments.java:148:13: compiler.err.cant.assign.initialized.before.ctor.called: x +EarlyAssignments.java:157:13: compiler.err.cant.assign.val.to.var: final, x +- compiler.note.preview.filename: EarlyAssignments.java, DEFAULT +- compiler.note.preview.recompile +25 errors diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalClass.java b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.java new file mode 100644 index 00000000000..1c68de603fb --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.java @@ -0,0 +1,19 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8325805 + * @summary Verify local class in early construction context has no outer instance + * @compile/fail/ref=EarlyLocalClass.out -XDrawDiagnostics EarlyLocalClass.java + * @enablePreview + */ +public class EarlyLocalClass { + EarlyLocalClass() { + class Local { + void foo() { + EarlyLocalClass.this.hashCode(); // this should FAIL + } + } + new Local(); // this is OK + super(); + new Local(); // this is OK + } +} diff --git a/test/langtools/tools/javac/SuperInit/EarlyLocalClass.out b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.out new file mode 100644 index 00000000000..390b68ea2c9 --- /dev/null +++ b/test/langtools/tools/javac/SuperInit/EarlyLocalClass.out @@ -0,0 +1,4 @@ +EarlyLocalClass.java:12:32: compiler.err.no.encl.instance.of.type.in.scope: EarlyLocalClass +- compiler.note.preview.filename: EarlyLocalClass.java, DEFAULT +- compiler.note.preview.recompile +1 error diff --git a/test/langtools/tools/javac/SuperInit/SuperInitFails.java b/test/langtools/tools/javac/SuperInit/SuperInitFails.java index cd0fc3fd903..b3dd88fc242 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitFails.java +++ b/test/langtools/tools/javac/SuperInit/SuperInitFails.java @@ -91,7 +91,7 @@ public SuperInitFails(char[] x) { } public SuperInitFails(short[] x) { - this.x = x.length; // this should FAIL + this.x++; // this should FAIL super(); } @@ -145,16 +145,6 @@ public java.util.Iterator iterator() { return null; } - public SuperInitFails(short[][] x) { - class Foo { - Foo() { - SuperInitFails.this.hashCode(); - } - }; - new Foo(); // this should FAIL - super(); - } - public SuperInitFails(float[][] x) { Runnable r = () -> { super(); // this should FAIL @@ -168,4 +158,32 @@ public SuperInitFails(int[][] z) { public SuperInitFails(long[][] z) { super(new Inner1()); // this should FAIL } + + public static class Inner2 { + int x; + } + public static class Inner3 extends Inner2 { + int y; + Inner3(byte z) { + x = z; // this should FAIL + super(); + } + Inner3(short z) { + this.x = z; // this should FAIL + super(); + } + Inner3(char z) { + Inner3.this.x = z; // this should FAIL + super(); + } + Inner3(int z) { + super.x = z; // this should FAIL + super(); + } + } + + public SuperInitFails(double[][] x) { + Runnable r = () -> this.x = 7; // this should FAIL + super(); + } } diff --git a/test/langtools/tools/javac/SuperInit/SuperInitFails.out b/test/langtools/tools/javac/SuperInit/SuperInitFails.out index 60bbd83dcc0..c6b726ab173 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitFails.out +++ b/test/langtools/tools/javac/SuperInit/SuperInitFails.out @@ -12,9 +12,13 @@ SuperInitFails.java:119:22: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:125:9: compiler.err.cant.ref.before.ctor.called: this SuperInitFails.java:133:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record1 SuperInitFails.java:138:9: compiler.err.non.canonical.constructor.invoke.another.constructor: SuperInitFails.Record2 -SuperInitFails.java:154:9: compiler.err.cant.ref.before.ctor.called: this -SuperInitFails.java:165:31: compiler.err.cant.ref.before.ctor.called: x -SuperInitFails.java:169:15: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:155:31: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:159:15: compiler.err.cant.ref.before.ctor.called: this +SuperInitFails.java:168:13: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:172:17: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:176:24: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:180:18: compiler.err.cant.ref.before.ctor.called: x +SuperInitFails.java:186:28: compiler.err.cant.ref.before.ctor.called: this SuperInitFails.java:33:13: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:37:14: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:41:14: compiler.err.call.must.only.appear.in.ctor @@ -23,7 +27,7 @@ SuperInitFails.java:49:33: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:53:32: compiler.err.call.must.only.appear.in.ctor SuperInitFails.java:83:18: compiler.err.ctor.calls.not.allowed.here SuperInitFails.java:89:13: compiler.err.return.before.superclass.initialized -SuperInitFails.java:160:18: compiler.err.ctor.calls.not.allowed.here +SuperInitFails.java:150:18: compiler.err.ctor.calls.not.allowed.here - compiler.note.preview.filename: SuperInitFails.java, DEFAULT - compiler.note.preview.recompile -26 errors +30 errors diff --git a/test/langtools/tools/javac/SuperInit/SuperInitGood.java b/test/langtools/tools/javac/SuperInit/SuperInitGood.java index f82ee6188f1..68002e8d37e 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitGood.java +++ b/test/langtools/tools/javac/SuperInit/SuperInitGood.java @@ -407,6 +407,54 @@ public int hashCode() { } } + // we allow 'this' reference prior to super() for field assignments only + public static class Test20 { + private int x; + public Test20(short x) { + x = x; + super(); + } + public Test20(int x) { + this.x = x; + super(); + } + public Test20(char x) { + Test20.this.x = x; + super(); + } + public Test20(byte y) { + x = y; + this((int)y); + this.x++; + } + } + + // allow creating and using local and anonymous classes before super() + // they will not have enclosing instances though + public static class Test21 { + public Test21(int x) { + Runnable r = new Runnable() { + public void run() { + this.hashCode(); + } + }; + r.run(); + super(); + r.run(); + } + public Test21(float x) { + class Foo { + public void bar() { + this.hashCode(); + } + }; + new Foo().bar(); + super(); + new Foo().bar(); + } + } + + public static void main(String[] args) { new Test0(); new Test1(); @@ -448,5 +496,8 @@ public static void main(String[] args) { assert false : "unexpected exception: " + e; } new Test19(123); + new Test20(123); + new Test21((int)123); + new Test21((float)123); } } diff --git a/test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java b/test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java new file mode 100644 index 00000000000..55f5d19451d --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/CantAssignInitializedBeforeCtorCalled.java @@ -0,0 +1,35 @@ +/* + * 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. + */ + + // key: compiler.note.preview.filename + // key: compiler.note.preview.recompile + // key: compiler.err.cant.assign.initialized.before.ctor.called + // options: --enable-preview -source ${jdk.version} + +class CantAssignInitializedBeforeCtorCalled { + int x = 1; + CantAssignInitializedBeforeCtorCalled() { + x = 2; + super(); + } +} diff --git a/test/langtools/tools/javac/diags/examples/FeatureStatementsBeforeSuper.java b/test/langtools/tools/javac/diags/examples/FeatureFlexibleConstructors.java similarity index 85% rename from test/langtools/tools/javac/diags/examples/FeatureStatementsBeforeSuper.java rename to test/langtools/tools/javac/diags/examples/FeatureFlexibleConstructors.java index f0e44836850..6bdff09e96f 100644 --- a/test/langtools/tools/javac/diags/examples/FeatureStatementsBeforeSuper.java +++ b/test/langtools/tools/javac/diags/examples/FeatureFlexibleConstructors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,12 +21,12 @@ * questions. */ - // key: compiler.misc.feature.super.init + // key: compiler.misc.feature.flexible.constructors // key: compiler.warn.preview.feature.use // options: --enable-preview -source ${jdk.version} -Xlint:preview -class FeatureStatementsBeforeSuper { - FeatureStatementsBeforeSuper() { +class FeatureFlexibleConstructors { + FeatureFlexibleConstructors() { System.out.println(); super(); } From 4754f059f99a426cc8c5d94b0809e79d563ffc2e Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Tue, 28 May 2024 14:47:04 +0000 Subject: [PATCH 74/99] 8333035: Parallel: Remove ParMarkBitMap::IterationStatus Reviewed-by: tschatzl --- src/hotspot/share/gc/parallel/parMarkBitMap.hpp | 3 --- src/hotspot/share/gc/parallel/psParallelCompact.cpp | 4 +--- src/hotspot/share/gc/parallel/psParallelCompact.hpp | 7 ++----- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp index cedf7aca77c..be905be6e90 100644 --- a/src/hotspot/share/gc/parallel/parMarkBitMap.hpp +++ b/src/hotspot/share/gc/parallel/parMarkBitMap.hpp @@ -35,9 +35,6 @@ class ParMarkBitMap: public CHeapObj { public: typedef BitMap::idx_t idx_t; - // Values returned by the iterate() methods. - enum IterationStatus { incomplete, complete, full }; - inline ParMarkBitMap(); bool initialize(MemRegion covered_region); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index f544831ca96..48430dbe367 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -2624,8 +2624,7 @@ void MoveAndUpdateClosure::complete_region(ParCompactionManager *cm, HeapWord *d region_ptr->set_completed(); } -MoveAndUpdateClosure::IterationStatus -MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) { +void MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) { assert(destination() != nullptr, "sanity"); _source = addr; @@ -2648,7 +2647,6 @@ MoveAndUpdateClosure::do_addr(HeapWord* addr, size_t words) { } update_state(words); - return is_full() ? ParMarkBitMap::full : ParMarkBitMap::incomplete; } void MoveAndUpdateShadowClosure::complete_region(ParCompactionManager *cm, HeapWord *dest_addr, diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.hpp index 713e9a1f84f..7c16f969e2b 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp @@ -904,7 +904,6 @@ class MoveAndUpdateClosure: public StackObj { public: typedef ParMarkBitMap::idx_t idx_t; - typedef ParMarkBitMap::IterationStatus IterationStatus; ParMarkBitMap* bitmap() const { return _bitmap; } @@ -914,10 +913,8 @@ class MoveAndUpdateClosure: public StackObj { void set_source(HeapWord* addr) { _source = addr; } // If the object will fit (size <= words_remaining()), copy it to the current - // destination, update the interior oops and the start array and return either - // full (if the closure is full) or incomplete. If the object will not fit, - // return would_overflow. - virtual IterationStatus do_addr(HeapWord* addr, size_t words); + // destination, update the interior oops and the start array. + void do_addr(HeapWord* addr, size_t words); inline MoveAndUpdateClosure(ParMarkBitMap* bitmap, size_t region); From 51ae08f72b879bc611177ea643cd88e36185d9e8 Mon Sep 17 00:00:00 2001 From: Ashutosh Mehra Date: Tue, 28 May 2024 15:02:50 +0000 Subject: [PATCH 75/99] 8333093: Incorrect comment in zAddress_aarch64.cpp Reviewed-by: stefank --- src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp index e140525bcbc..cd834969e1a 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp @@ -38,7 +38,7 @@ // Default value if probing is not implemented for a certain platform // Max address bit is restricted by implicit assumptions in the code, for instance -// the bit layout of XForwardingEntry or Partial array entry (see XMarkStackEntry) in mark stack +// the bit layout of ZForwardingEntry or Partial array entry (see ZMarkStackEntry) in mark stack static const size_t DEFAULT_MAX_ADDRESS_BIT = 46; // Minimum value returned, if probing fail static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; From 0f3e2cc334e5926d53bbbce22e4a6bfeb2752140 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Tue, 28 May 2024 15:05:54 +0000 Subject: [PATCH 76/99] 8331670: Deprecate the Memory-Access Methods in sun.misc.Unsafe for Removal Reviewed-by: mcimadamore, jpai, pminborg --- make/test/BuildMicrobenchmark.gmk | 2 +- src/hotspot/share/runtime/arguments.cpp | 9 + .../launcher/resources/launcher.properties | 6 +- src/java.base/share/man/java.1 | 24 + .../share/classes/sun/misc/Unsafe.java | 835 ++++++++++++++++-- test/jdk/sun/misc/TryUnsafeMemoryAccess.java | 136 +++ .../sun/misc/UnsafeMemoryAccessWarnings.java | 212 +++++ .../org/openjdk/bench/sun/misc/UnsafeOps.java | 89 ++ 8 files changed, 1229 insertions(+), 84 deletions(-) create mode 100644 test/jdk/sun/misc/TryUnsafeMemoryAccess.java create mode 100644 test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java create mode 100644 test/micro/org/openjdk/bench/sun/misc/UnsafeOps.java diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk index 7b65e89610e..32d26be2270 100644 --- a/make/test/BuildMicrobenchmark.gmk +++ b/make/test/BuildMicrobenchmark.gmk @@ -94,7 +94,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \ TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \ SMALL_JAVA := false, \ CLASSPATH := $(JMH_COMPILE_JARS), \ - DISABLED_WARNINGS := restricted this-escape processing rawtypes cast \ + DISABLED_WARNINGS := restricted this-escape processing rawtypes removal cast \ serial preview dangling-doc-comments, \ SRC := $(MICROBENCHMARK_SRC), \ BIN := $(MICROBENCHMARK_CLASSES), \ diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 7a74ef6e248..7befe9cd734 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -2282,6 +2282,15 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m if (res != JNI_OK) { return res; } + } else if (match_option(option, "--sun-misc-unsafe-memory-access=", &tail)) { + if (strcmp(tail, "allow") == 0 || strcmp(tail, "warn") == 0 || strcmp(tail, "debug") == 0 || strcmp(tail, "deny") == 0) { + PropertyList_unique_add(&_system_properties, "sun.misc.unsafe.memory.access", tail, + AddProperty, WriteableProperty, InternalProperty); + } else { + jio_fprintf(defaultStream::error_stream(), + "Value specified to --sun-misc-unsafe-memory-access not recognized: '%s'\n", tail); + return JNI_ERR; + } } else if (match_option(option, "--illegal-access=", &tail)) { char version[256]; JDK_Version::jdk(17).to_string(version, sizeof(version)); diff --git a/src/java.base/share/classes/sun/launcher/resources/launcher.properties b/src/java.base/share/classes/sun/launcher/resources/launcher.properties index 489b1395a22..cd524955419 100644 --- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties +++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties @@ -212,7 +212,11 @@ java.launcher.X.usage=\n\ \ --finalization=\n\ \ controls whether the JVM performs finalization of objects,\n\ \ where is one of "enabled" or "disabled".\n\ -\ Finalization is enabled by default.\n\n\ +\ Finalization is enabled by default.\n\ +\ --sun-misc-unsafe-memory-access=\n\ +\ allow or deny usage of unsupported API sun.misc.Unsafe\n\ +\ is one of "allow", "warn", "debug", or "deny".\n\ +\ The default value is "allow".\n\n\ These extra options are subject to change without notice.\n # Translators please note do not translate the options themselves diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index 990fdccf8d5..6cef707d19a 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -1194,6 +1194,30 @@ or directories. .TP \f[V]--source\f[R] \f[I]version\f[R] Sets the version of the source in source-file mode. +.TP +\f[V]--sun-misc-unsafe-memory-acces=\f[R] \f[I]value\f[R] +Allow or deny usage of unsupported API \f[V]sun.misc.Unsafe\f[R]. +\f[I]value\f[R] is one of: +.RS +.TP +\f[V]allow\f[R] +Allow use of the memory-access methods with no warnings at run time. +.TP +\f[V]warn\f[R] +Allow use of the memory-access methods, but issues a warning on the +first occasion that any memory-access method is used. +At most one warning is issued. +.TP +\f[V]debug\f[R] +Allow use of the memory-access methods, but issue a one-line warning and +a stack trace when any memory-access method is used. +.TP +\f[V]deny\f[R] +Disallow use of the memory-access methods by throwing an +\f[V]UnsupportedOperationException\f[R] on every usage. +.PP +The default value when the option is not specified is \f[V]allow\f[R]. +.RE .SH EXTRA OPTIONS FOR MACOS .PP The following extra options are macOS specific. diff --git a/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java b/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java index 3f91fd70db4..e1a936117d4 100644 --- a/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java +++ b/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java @@ -25,16 +25,26 @@ package sun.misc; +import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; +import java.lang.invoke.VarHandle; +import java.lang.reflect.Field; +import java.net.URL; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.ProtectionDomain; +import java.security.PrivilegedAction; +import java.util.List; +import java.util.Set; + import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; import jdk.internal.misc.VM; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Field; -import java.util.Set; - - /** * A collection of methods for performing low-level, unsafe operations. * Although the class and all methods are public, use of this class is @@ -49,6 +59,11 @@ * the caller must not rely on the checks and corresponding * exceptions! * + * @apiNote + * This class pre-dates the introduction of {@link VarHandle}, low-level access to + * memory with {@linkplain java.lang.foreign}, and other standard APIs. New code + * should not use this API. + * * @author John R. Rose * @see #getUnsafe */ @@ -150,6 +165,9 @@ public static Unsafe getUnsafe() { * be portably confused with longs used in the single-register addressing * mode. * + * @deprecated Use {@link VarHandle#get(Object...)} or + * {@link MemorySegment#get(ValueLayout.OfInt, long)} instead. + * * @param o Java heap object in which the variable resides, if any, else * null * @param offset indication of where the variable resides in a Java heap @@ -159,8 +177,10 @@ public static Unsafe getUnsafe() { * @throws RuntimeException No defined exceptions are thrown, not even * {@link NullPointerException} */ + @Deprecated(since="23", forRemoval=true) @ForceInline public int getInt(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getInt(o, offset); } @@ -175,6 +195,9 @@ public int getInt(Object o, long offset) { * The variable must be of the same type as the method * parameter {@code x}. * + * @deprecated Use {@link VarHandle#set(Object...)} or + * {@link MemorySegment#set(ValueLayout.OfInt, long, int)} instead. + * * @param o Java heap object in which the variable resides, if any, else * null * @param offset indication of where the variable resides in a Java heap @@ -184,17 +207,22 @@ public int getInt(Object o, long offset) { * @throws RuntimeException No defined exceptions are thrown, not even * {@link NullPointerException} */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putInt(Object o, long offset, int x) { + beforeMemoryAccess(); theInternalUnsafe.putInt(o, offset, x); } /** * Fetches a reference value from a given Java variable. - * @see #getInt(Object, long) + * + * @deprecated Use {@link VarHandle#get(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public Object getObject(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getReference(o, offset); } @@ -206,94 +234,195 @@ public Object getObject(Object o, long offset) { * If the reference {@code o} is non-null, card marks or * other store barriers for that object (if the VM requires them) * are updated. - * @see #putInt(Object, long, int) + * + * @deprecated Use {@link VarHandle#set(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putObject(Object o, long offset, Object x) { + beforeMemoryAccess(); theInternalUnsafe.putReference(o, offset, x); } - /** @see #getInt(Object, long) */ + /** + * @deprecated Use {@link VarHandle#get(Object...)} or + * {@link MemorySegment#get(ValueLayout.OfBoolean, long)} instead. + * + * @see #getInt(Object, long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public boolean getBoolean(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getBoolean(o, offset); } - /** @see #putInt(Object, long, int) */ + /** + * @deprecated Use {@link VarHandle#set(Object...)} or + * {@link MemorySegment#set(ValueLayout.OfBoolean, long, boolean)} instead. + * + * @see #putInt(Object, long, int) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putBoolean(Object o, long offset, boolean x) { + beforeMemoryAccess(); theInternalUnsafe.putBoolean(o, offset, x); } - /** @see #getInt(Object, long) */ + /** + * @deprecated Use {@link VarHandle#get(Object...)} or + * {@link MemorySegment#get(ValueLayout.OfByte, long)} instead. + * + * @see #getInt(Object, long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public byte getByte(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getByte(o, offset); } - /** @see #putInt(Object, long, int) */ + /** + * @deprecated Use {@link VarHandle#set(Object...)} or + * {@link MemorySegment#set(ValueLayout.OfByte, long, byte)} instead. + * + * @see #putInt(Object, long, int) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putByte(Object o, long offset, byte x) { + beforeMemoryAccess(); theInternalUnsafe.putByte(o, offset, x); } - /** @see #getInt(Object, long) */ + /** + * @deprecated Use {@link VarHandle#get(Object...)} or + * {@link MemorySegment#get(ValueLayout.OfShort, long)} instead. + * + * @see #getInt(Object, long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public short getShort(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getShort(o, offset); } - /** @see #putInt(Object, long, int) */ + /** + * @deprecated Use {@link VarHandle#set(Object...)} or + * {@link MemorySegment#set(ValueLayout.OfShort, long, short)} instead. + * + * @see #putInt(Object, long, int) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putShort(Object o, long offset, short x) { + beforeMemoryAccess(); theInternalUnsafe.putShort(o, offset, x); } - /** @see #getInt(Object, long) */ + /** + * @deprecated Use {@link VarHandle#get(Object...)} or + * {@link MemorySegment#get(ValueLayout.OfChar, long)} instead. + * + * @see #getInt(Object, long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public char getChar(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getChar(o, offset); } - /** @see #putInt(Object, long, int) */ + /** + * @deprecated Use {@link VarHandle#set(Object...)} or + * {@link MemorySegment#set(ValueLayout.OfChar, long, char)} instead. + * + * @see #putInt(Object, long, int) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putChar(Object o, long offset, char x) { + beforeMemoryAccess(); theInternalUnsafe.putChar(o, offset, x); } - /** @see #getInt(Object, long) */ + /** + * @deprecated Use {@link VarHandle#get(Object...)} or + * {@link MemorySegment#get(ValueLayout.OfLong, long)} instead. + * + * @see #getInt(Object, long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public long getLong(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getLong(o, offset); } - /** @see #putInt(Object, long, int) */ + /** + * @deprecated Use {@link VarHandle#set(Object...)} or + * {@link MemorySegment#set(ValueLayout.OfLong, long, long)} instead. + * + * @see #putInt(Object, long, int) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putLong(Object o, long offset, long x) { + beforeMemoryAccess(); theInternalUnsafe.putLong(o, offset, x); } - /** @see #getInt(Object, long) */ + /** + * @deprecated Use {@link VarHandle#get(Object...)} or + * {@link MemorySegment#get(ValueLayout.OfFloat, long)} instead. + * + * @see #getInt(Object, long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public float getFloat(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getFloat(o, offset); } - /** @see #putInt(Object, long, int) */ + /** + * @deprecated Use {@link VarHandle#set(Object...)} or + * {@link MemorySegment#set(ValueLayout.OfFloat, long, float)} instead. + * + * @see #putInt(Object, long, int) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putFloat(Object o, long offset, float x) { + beforeMemoryAccess(); theInternalUnsafe.putFloat(o, offset, x); } - /** @see #getInt(Object, long) */ + /** + * @deprecated Use {@link VarHandle#get(Object...)} or + * {@link MemorySegment#get(ValueLayout.OfDouble, long)} instead. + * + * @see #getInt(Object, long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public double getDouble(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getDouble(o, offset); } - /** @see #putInt(Object, long, int) */ + /** + * @deprecated Use {@link VarHandle#set(Object...)} or + * {@link MemorySegment#set(ValueLayout.OfDouble, long, double)} instead. + * + * @see #putInt(Object, long, int) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putDouble(Object o, long offset, double x) { + beforeMemoryAccess(); theInternalUnsafe.putDouble(o, offset, x); } @@ -304,10 +433,14 @@ public void putDouble(Object o, long offset, double x) { * does not point into a block obtained from {@link #allocateMemory}, the * results are undefined. * + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * * @see #allocateMemory */ + @Deprecated(since="23", forRemoval=true) @ForceInline public byte getByte(long address) { + beforeMemoryAccess(); return theInternalUnsafe.getByte(address); } @@ -316,82 +449,158 @@ public byte getByte(long address) { * does not point into a block obtained from {@link #allocateMemory}, the * results are undefined. * + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * * @see #getByte(long) */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putByte(long address, byte x) { + beforeMemoryAccess(); theInternalUnsafe.putByte(address, x); } - /** @see #getByte(long) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #getByte(long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public short getShort(long address) { + beforeMemoryAccess(); return theInternalUnsafe.getShort(address); } - /** @see #putByte(long, byte) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #putByte(long, byte) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putShort(long address, short x) { + beforeMemoryAccess(); theInternalUnsafe.putShort(address, x); } - /** @see #getByte(long) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #getByte(long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public char getChar(long address) { + beforeMemoryAccess(); return theInternalUnsafe.getChar(address); } - /** @see #putByte(long, byte) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #putByte(long, byte) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putChar(long address, char x) { + beforeMemoryAccess(); theInternalUnsafe.putChar(address, x); } - /** @see #getByte(long) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #getByte(long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public int getInt(long address) { + beforeMemoryAccess(); return theInternalUnsafe.getInt(address); } - /** @see #putByte(long, byte) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #putByte(long, byte) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putInt(long address, int x) { + beforeMemoryAccess(); theInternalUnsafe.putInt(address, x); } - /** @see #getByte(long) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #getByte(long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public long getLong(long address) { + beforeMemoryAccess(); return theInternalUnsafe.getLong(address); } - /** @see #putByte(long, byte) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #putByte(long, byte) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putLong(long address, long x) { + beforeMemoryAccess(); theInternalUnsafe.putLong(address, x); } - /** @see #getByte(long) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #getByte(long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public float getFloat(long address) { + beforeMemoryAccess(); return theInternalUnsafe.getFloat(address); } - /** @see #putByte(long, byte) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #putByte(long, byte) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putFloat(long address, float x) { + beforeMemoryAccess(); theInternalUnsafe.putFloat(address, x); } - /** @see #getByte(long) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #getByte(long) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public double getDouble(long address) { + beforeMemoryAccess(); return theInternalUnsafe.getDouble(address); } - /** @see #putByte(long, byte) */ + /** + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * + * @see #putByte(long, byte) + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putDouble(long address, double x) { + beforeMemoryAccess(); theInternalUnsafe.putDouble(address, x); } @@ -408,10 +617,14 @@ public void putDouble(long address, double x) { * from the target address may be determined by consulting {@link * #addressSize}. * + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * * @see #allocateMemory */ + @Deprecated(since="23", forRemoval=true) @ForceInline public long getAddress(long address) { + beforeMemoryAccess(); return theInternalUnsafe.getAddress(address); } @@ -423,10 +636,14 @@ public long getAddress(long address) { *

    The number of bytes actually written at the target address may be * determined by consulting {@link #addressSize}. * + * @deprecated Use {@link java.lang.foreign} to access off-heap memory. + * * @see #getAddress(long) */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putAddress(long address, long x) { + beforeMemoryAccess(); theInternalUnsafe.putAddress(address, x); } @@ -450,6 +667,8 @@ public void putAddress(long address, long x) { * caller must not rely on the checks and corresponding * exceptions! * + * @deprecated Use {@link java.lang.foreign} to allocate off-heap memory. + * * @throws RuntimeException if the size is negative or too large * for the native size_t type * @@ -458,8 +677,10 @@ public void putAddress(long address, long x) { * @see #getByte(long) * @see #putByte(long, byte) */ + @Deprecated(since="23", forRemoval=true) @ForceInline public long allocateMemory(long bytes) { + beforeMemoryAccess(); return theInternalUnsafe.allocateMemory(bytes); } @@ -482,6 +703,8 @@ public long allocateMemory(long bytes) { * caller must not rely on the checks and corresponding * exceptions! * + * @deprecated Use {@link java.lang.foreign} to allocate off-heap memory. + * * @throws RuntimeException if the size is negative or too large * for the native size_t type * @@ -489,8 +712,10 @@ public long allocateMemory(long bytes) { * * @see #allocateMemory */ + @Deprecated(since="23", forRemoval=true) @ForceInline public long reallocateMemory(long address, long bytes) { + beforeMemoryAccess(); return theInternalUnsafe.reallocateMemory(address, bytes); } @@ -518,12 +743,17 @@ public long reallocateMemory(long address, long bytes) { * caller must not rely on the checks and corresponding * exceptions! * + * @deprecated {@link MemorySegment#fill(byte)} fills the contents of a memory + * segment with a given value. + * * @throws RuntimeException if any of the arguments is invalid * * @since 1.7 */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void setMemory(Object o, long offset, long bytes, byte value) { + beforeMemoryAccess(); theInternalUnsafe.setMemory(o, offset, bytes, value); } @@ -533,9 +763,16 @@ public void setMemory(Object o, long offset, long bytes, byte value) { * as discussed in {@link #getInt(Object,long)}. * *

    Equivalent to {@code setMemory(null, address, bytes, value)}. + * + * @deprecated {@link MemorySegment#fill(byte)} fills the contents of a memory + * segment with a given value. + * + * Use {@link MemorySegment} and its bulk copy methods instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void setMemory(long address, long bytes, byte value) { + beforeMemoryAccess(); theInternalUnsafe.setMemory(address, bytes, value); } @@ -563,14 +800,18 @@ public void setMemory(long address, long bytes, byte value) { * caller must not rely on the checks and corresponding * exceptions! * + * @deprecated Use {@link MemorySegment} and its bulk copy methods instead. + * * @throws RuntimeException if any of the arguments is invalid * * @since 1.7 */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) { + beforeMemoryAccess(); theInternalUnsafe.copyMemory(srcBase, srcOffset, destBase, destOffset, bytes); } @@ -580,9 +821,13 @@ public void copyMemory(Object srcBase, long srcOffset, * as discussed in {@link #getInt(Object,long)}. * * Equivalent to {@code copyMemory(null, srcAddress, null, destAddress, bytes)}. + * + * @deprecated Use {@link MemorySegment} and its bulk copy methods instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void copyMemory(long srcAddress, long destAddress, long bytes) { + beforeMemoryAccess(); theInternalUnsafe.copyMemory(srcAddress, destAddress, bytes); } @@ -600,12 +845,16 @@ public void copyMemory(long srcAddress, long destAddress, long bytes) { * caller must not rely on the checks and corresponding * exceptions! * + * @deprecated Use {@link java.lang.foreign} to allocate and free off-heap memory. + * * @throws RuntimeException if any of the arguments is invalid * * @see #allocateMemory */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void freeMemory(long address) { + beforeMemoryAccess(); theInternalUnsafe.freeMemory(address); } @@ -615,7 +864,9 @@ public void freeMemory(long address) { * This constant differs from all results that will ever be returned from * {@link #staticFieldOffset}, {@link #objectFieldOffset}, * or {@link #arrayBaseOffset}. + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. */ + @Deprecated(since="23", forRemoval=true) public static final int INVALID_FIELD_OFFSET = jdk.internal.misc.Unsafe.INVALID_FIELD_OFFSET; /** @@ -638,11 +889,11 @@ public void freeMemory(long address) { * @deprecated The guarantee that a field will always have the same offset * and base may not be true in a future release. The ability to provide an * offset and object reference to a heap memory accessor will be removed - * in a future release. Use {@link java.lang.invoke.VarHandle} instead. + * in a future release. Use {@link VarHandle} instead. * * @see #getInt(Object, long) */ - @Deprecated(since="18") + @Deprecated(since="18", forRemoval=true) @ForceInline public long objectFieldOffset(Field f) { if (f == null) { @@ -655,6 +906,7 @@ public long objectFieldOffset(Field f) { if (declaringClass.isRecord()) { throw new UnsupportedOperationException("can't get field offset on a record class: " + f); } + beforeMemoryAccess(); return theInternalUnsafe.objectFieldOffset(f); } @@ -677,11 +929,11 @@ public long objectFieldOffset(Field f) { * @deprecated The guarantee that a field will always have the same offset * and base may not be true in a future release. The ability to provide an * offset and object reference to a heap memory accessor will be removed - * in a future release. Use {@link java.lang.invoke.VarHandle} instead. + * in a future release. Use {@link VarHandle} instead. * * @see #getInt(Object, long) */ - @Deprecated(since="18") + @Deprecated(since="18", forRemoval=true) @ForceInline public long staticFieldOffset(Field f) { if (f == null) { @@ -694,6 +946,7 @@ public long staticFieldOffset(Field f) { if (declaringClass.isRecord()) { throw new UnsupportedOperationException("can't get field offset on a record class: " + f); } + beforeMemoryAccess(); return theInternalUnsafe.staticFieldOffset(f); } @@ -710,9 +963,9 @@ public long staticFieldOffset(Field f) { * @deprecated The guarantee that a field will always have the same offset * and base may not be true in a future release. The ability to provide an * offset and object reference to a heap memory accessor will be removed - * in a future release. Use {@link java.lang.invoke.VarHandle} instead. + * in a future release. Use {@link VarHandle} instead. */ - @Deprecated(since="18") + @Deprecated(since="18", forRemoval=true) @ForceInline public Object staticFieldBase(Field f) { if (f == null) { @@ -725,6 +978,7 @@ public Object staticFieldBase(Field f) { if (declaringClass.isRecord()) { throw new UnsupportedOperationException("can't get base address on a record class: " + f); } + beforeMemoryAccess(); return theInternalUnsafe.staticFieldBase(f); } @@ -735,39 +989,79 @@ public Object staticFieldBase(Field f) { * base offset, to form new offsets to access elements of arrays of the * given class. * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + * * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ + @Deprecated(since="23", forRemoval=true) @ForceInline public int arrayBaseOffset(Class arrayClass) { + beforeMemoryAccess(); return theInternalUnsafe.arrayBaseOffset(arrayClass); } - /** The value of {@code arrayBaseOffset(boolean[].class)} */ + /** The value of {@code arrayBaseOffset(boolean[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_BOOLEAN_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_BOOLEAN_BASE_OFFSET; - /** The value of {@code arrayBaseOffset(byte[].class)} */ + /** The value of {@code arrayBaseOffset(byte[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_BYTE_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; - /** The value of {@code arrayBaseOffset(short[].class)} */ + /** The value of {@code arrayBaseOffset(short[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_SHORT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_SHORT_BASE_OFFSET; - /** The value of {@code arrayBaseOffset(char[].class)} */ + /** The value of {@code arrayBaseOffset(char[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_CHAR_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_CHAR_BASE_OFFSET; - /** The value of {@code arrayBaseOffset(int[].class)} */ + /** The value of {@code arrayBaseOffset(int[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_INT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_INT_BASE_OFFSET; - /** The value of {@code arrayBaseOffset(long[].class)} */ + /** The value of {@code arrayBaseOffset(long[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_LONG_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_LONG_BASE_OFFSET; - /** The value of {@code arrayBaseOffset(float[].class)} */ + /** The value of {@code arrayBaseOffset(float[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_FLOAT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_FLOAT_BASE_OFFSET; - /** The value of {@code arrayBaseOffset(double[].class)} */ + /** The value of {@code arrayBaseOffset(double[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_DOUBLE_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_DOUBLE_BASE_OFFSET; - /** The value of {@code arrayBaseOffset(Object[].class)} */ + /** The value of {@code arrayBaseOffset(Object[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_OBJECT_BASE_OFFSET = jdk.internal.misc.Unsafe.ARRAY_OBJECT_BASE_OFFSET; /** @@ -777,40 +1071,79 @@ public int arrayBaseOffset(Class arrayClass) { * #getByte(Object, long)}, so the scale factor for such classes is reported * as zero. * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + * * @see #arrayBaseOffset * @see #getInt(Object, long) * @see #putInt(Object, long, int) */ + @Deprecated(since="23", forRemoval=true) @ForceInline public int arrayIndexScale(Class arrayClass) { return theInternalUnsafe.arrayIndexScale(arrayClass); } - /** The value of {@code arrayIndexScale(boolean[].class)} */ + /** The value of {@code arrayIndexScale(boolean[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_BOOLEAN_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_BOOLEAN_INDEX_SCALE; - /** The value of {@code arrayIndexScale(byte[].class)} */ + /** The value of {@code arrayIndexScale(byte[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_BYTE_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_BYTE_INDEX_SCALE; - /** The value of {@code arrayIndexScale(short[].class)} */ + /** The value of {@code arrayIndexScale(short[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_SHORT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_SHORT_INDEX_SCALE; - /** The value of {@code arrayIndexScale(char[].class)} */ + /** The value of {@code arrayIndexScale(char[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_CHAR_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_CHAR_INDEX_SCALE; - /** The value of {@code arrayIndexScale(int[].class)} */ + /** The value of {@code arrayIndexScale(int[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_INT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_INT_INDEX_SCALE; - /** The value of {@code arrayIndexScale(long[].class)} */ + /** The value of {@code arrayIndexScale(long[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_LONG_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_LONG_INDEX_SCALE; - /** The value of {@code arrayIndexScale(float[].class)} */ + /** The value of {@code arrayIndexScale(float[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_FLOAT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_FLOAT_INDEX_SCALE; - /** The value of {@code arrayIndexScale(double[].class)} */ + /** The value of {@code arrayIndexScale(double[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_DOUBLE_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_DOUBLE_INDEX_SCALE; - /** The value of {@code arrayIndexScale(Object[].class)} */ + /** The value of {@code arrayIndexScale(Object[].class)}. + * + * @deprecated Not needed when using {@link VarHandle} or {@link java.lang.foreign}. + */ + @Deprecated(since="23", forRemoval=true) public static final int ARRAY_OBJECT_INDEX_SCALE = jdk.internal.misc.Unsafe.ARRAY_OBJECT_INDEX_SCALE; /** @@ -818,13 +1151,20 @@ public int arrayIndexScale(Class arrayClass) { * #putAddress}. This value will be either 4 or 8. Note that the sizes of * other primitive types (as stored in native memory blocks) is determined * fully by their information content. + * + * @deprecated Use {@link ValueLayout#ADDRESS}.{@link MemoryLayout#byteSize()} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public int addressSize() { return theInternalUnsafe.addressSize(); } - /** The value of {@code addressSize()} */ + /** The value of {@code addressSize()}. + * + * @deprecated Use {@link ValueLayout#ADDRESS}.{@link MemoryLayout#byteSize()} instead. + */ + @Deprecated(since="23", forRemoval=true) public static final int ADDRESS_SIZE = theInternalUnsafe.addressSize(); /** @@ -863,11 +1203,15 @@ public void throwException(Throwable ee) { * and write. Corresponds to C11 atomic_compare_exchange_strong. * * @return {@code true} if successful + * + * @deprecated Use {@link VarHandle#compareAndExchange(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public final boolean compareAndSwapObject(Object o, long offset, Object expected, Object x) { + beforeMemoryAccess(); return theInternalUnsafe.compareAndSetReference(o, offset, expected, x); } @@ -879,11 +1223,15 @@ public final boolean compareAndSwapObject(Object o, long offset, * and write. Corresponds to C11 atomic_compare_exchange_strong. * * @return {@code true} if successful + * + * @deprecated Use {@link VarHandle#compareAndExchange(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public final boolean compareAndSwapInt(Object o, long offset, int expected, int x) { + beforeMemoryAccess(); return theInternalUnsafe.compareAndSetInt(o, offset, expected, x); } @@ -895,125 +1243,218 @@ public final boolean compareAndSwapInt(Object o, long offset, * and write. Corresponds to C11 atomic_compare_exchange_strong. * * @return {@code true} if successful + * + * @deprecated Use {@link VarHandle#compareAndExchange(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public final boolean compareAndSwapLong(Object o, long offset, long expected, long x) { + beforeMemoryAccess(); return theInternalUnsafe.compareAndSetLong(o, offset, expected, x); } /** * Fetches a reference value from a given Java variable, with volatile * load semantics. Otherwise identical to {@link #getObject(Object, long)} + * + * @deprecated Use {@link VarHandle#getVolatile(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public Object getObjectVolatile(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getReferenceVolatile(o, offset); } /** * Stores a reference value into a given Java variable, with * volatile store semantics. Otherwise identical to {@link #putObject(Object, long, Object)} + * + * @deprecated Use {@link VarHandle#setVolatile(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putObjectVolatile(Object o, long offset, Object x) { + beforeMemoryAccess(); theInternalUnsafe.putReferenceVolatile(o, offset, x); } - /** Volatile version of {@link #getInt(Object, long)} */ + /** Volatile version of {@link #getInt(Object, long)}. + * + * @deprecated Use {@link VarHandle#getVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public int getIntVolatile(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getIntVolatile(o, offset); } - /** Volatile version of {@link #putInt(Object, long, int)} */ + /** Volatile version of {@link #putInt(Object, long, int)}. + * + * @deprecated Use {@link VarHandle#setVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putIntVolatile(Object o, long offset, int x) { + beforeMemoryAccess(); theInternalUnsafe.putIntVolatile(o, offset, x); } - /** Volatile version of {@link #getBoolean(Object, long)} */ + /** Volatile version of {@link #getBoolean(Object, long)}. + * + * @deprecated Use {@link VarHandle#getVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public boolean getBooleanVolatile(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getBooleanVolatile(o, offset); } - /** Volatile version of {@link #putBoolean(Object, long, boolean)} */ + /** Volatile version of {@link #putBoolean(Object, long, boolean)}. + * + * @deprecated Use {@link VarHandle#setVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putBooleanVolatile(Object o, long offset, boolean x) { + beforeMemoryAccess(); theInternalUnsafe.putBooleanVolatile(o, offset, x); } - /** Volatile version of {@link #getByte(Object, long)} */ + /** Volatile version of {@link #getByte(Object, long)}. + * + * @deprecated Use {@link VarHandle#getVolatile(Object...)} + * instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public byte getByteVolatile(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getByteVolatile(o, offset); } - /** Volatile version of {@link #putByte(Object, long, byte)} */ + /** Volatile version of {@link #putByte(Object, long, byte)}. + * + * @deprecated Use {@link VarHandle#setVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putByteVolatile(Object o, long offset, byte x) { + beforeMemoryAccess(); theInternalUnsafe.putByteVolatile(o, offset, x); } - /** Volatile version of {@link #getShort(Object, long)} */ + /** Volatile version of {@link #getShort(Object, long)}. + * + * @deprecated Use {@link VarHandle#getVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public short getShortVolatile(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getShortVolatile(o, offset); } - /** Volatile version of {@link #putShort(Object, long, short)} */ + /** Volatile version of {@link #putShort(Object, long, short)}. + * + * @deprecated Use {@link VarHandle#setVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putShortVolatile(Object o, long offset, short x) { + beforeMemoryAccess(); theInternalUnsafe.putShortVolatile(o, offset, x); } - /** Volatile version of {@link #getChar(Object, long)} */ + /** Volatile version of {@link #getChar(Object, long)}. + * + * @deprecated Use {@link VarHandle#getVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public char getCharVolatile(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getCharVolatile(o, offset); } - /** Volatile version of {@link #putChar(Object, long, char)} */ + /** Volatile version of {@link #putChar(Object, long, char)}. + * + * @deprecated Use {@link VarHandle#setVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putCharVolatile(Object o, long offset, char x) { + beforeMemoryAccess(); theInternalUnsafe.putCharVolatile(o, offset, x); } - /** Volatile version of {@link #getLong(Object, long)} */ + /** Volatile version of {@link #getLong(Object, long)}. + * + * @deprecated Use {@link VarHandle#getVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public long getLongVolatile(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getLongVolatile(o, offset); } - /** Volatile version of {@link #putLong(Object, long, long)} */ + /** Volatile version of {@link #putLong(Object, long, long)}. + * + * @deprecated Use {@link VarHandle#setVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putLongVolatile(Object o, long offset, long x) { + beforeMemoryAccess(); theInternalUnsafe.putLongVolatile(o, offset, x); } - /** Volatile version of {@link #getFloat(Object, long)} */ + /** Volatile version of {@link #getFloat(Object, long)}. + * + * @deprecated Use {@link VarHandle#getVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public float getFloatVolatile(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getFloatVolatile(o, offset); } - /** Volatile version of {@link #putFloat(Object, long, float)} */ + /** Volatile version of {@link #putFloat(Object, long, float)}. + * + * @deprecated Use {@link VarHandle#setVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putFloatVolatile(Object o, long offset, float x) { + beforeMemoryAccess(); theInternalUnsafe.putFloatVolatile(o, offset, x); } - /** Volatile version of {@link #getDouble(Object, long)} */ + /** Volatile version of {@link #getDouble(Object, long)}. + * + * @deprecated Use {@link VarHandle#getVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public double getDoubleVolatile(Object o, long offset) { + beforeMemoryAccess(); return theInternalUnsafe.getDoubleVolatile(o, offset); } - /** Volatile version of {@link #putDouble(Object, long, double)} */ + /** Volatile version of {@link #putDouble(Object, long, double)}. + * + * @deprecated Use {@link VarHandle#setVolatile(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putDoubleVolatile(Object o, long offset, double x) { + beforeMemoryAccess(); theInternalUnsafe.putDoubleVolatile(o, offset, x); } @@ -1025,21 +1466,35 @@ public void putDoubleVolatile(Object o, long offset, double x) { * that is otherwise only accessed using volatile accesses). * * Corresponds to C11 atomic_store_explicit(..., memory_order_release). + * + * @deprecated Use {@link VarHandle#setRelease(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putOrderedObject(Object o, long offset, Object x) { + beforeMemoryAccess(); theInternalUnsafe.putReferenceRelease(o, offset, x); } - /** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */ + /** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)}. + * + * @deprecated Use {@link VarHandle#setRelease(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putOrderedInt(Object o, long offset, int x) { + beforeMemoryAccess(); theInternalUnsafe.putIntRelease(o, offset, x); } - /** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */ + /** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)}. + * + * @deprecated Use {@link VarHandle#setRelease(Object...)} instead. + */ + @Deprecated(since="23", forRemoval=true) @ForceInline public void putOrderedLong(Object o, long offset, long x) { + beforeMemoryAccess(); theInternalUnsafe.putLongRelease(o, offset, x); } @@ -1098,9 +1553,10 @@ public void park(boolean isAbsolute, long time) { * @return the number of samples actually retrieved; or -1 * if the load average is unobtainable. * - * @deprecated Use {@link java.lang.management.OperatingSystemMXBean#getSystemLoadAverage()} + * @deprecated Use {@link java.management/java.lang.management.OperatingSystemMXBean#getSystemLoadAverage()} * instead. */ + @SuppressWarnings("doclint:reference") // cross-module links @Deprecated(since="22", forRemoval=true) @ForceInline public int getLoadAverage(double[] loadavg, int nelems) { @@ -1120,9 +1576,13 @@ public int getLoadAverage(double[] loadavg, int nelems) { * @param delta the value to add * @return the previous value * @since 1.8 + * + * @deprecated Use {@link VarHandle#getAndAdd(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public final int getAndAddInt(Object o, long offset, int delta) { + beforeMemoryAccess(); return theInternalUnsafe.getAndAddInt(o, offset, delta); } @@ -1136,9 +1596,13 @@ public final int getAndAddInt(Object o, long offset, int delta) { * @param delta the value to add * @return the previous value * @since 1.8 + * + * @deprecated Use {@link VarHandle#getAndAdd(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public final long getAndAddLong(Object o, long offset, long delta) { + beforeMemoryAccess(); return theInternalUnsafe.getAndAddLong(o, offset, delta); } @@ -1152,9 +1616,13 @@ public final long getAndAddLong(Object o, long offset, long delta) { * @param newValue new value * @return the previous value * @since 1.8 + * + * @deprecated Use {@link VarHandle#getAndAdd(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public final int getAndSetInt(Object o, long offset, int newValue) { + beforeMemoryAccess(); return theInternalUnsafe.getAndSetInt(o, offset, newValue); } @@ -1168,9 +1636,13 @@ public final int getAndSetInt(Object o, long offset, int newValue) { * @param newValue new value * @return the previous value * @since 1.8 + * + * @deprecated Use {@link VarHandle#getAndAdd(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public final long getAndSetLong(Object o, long offset, long newValue) { + beforeMemoryAccess(); return theInternalUnsafe.getAndSetLong(o, offset, newValue); } @@ -1184,9 +1656,13 @@ public final long getAndSetLong(Object o, long offset, long newValue) { * @param newValue new value * @return the previous value * @since 1.8 + * + * @deprecated Use {@link VarHandle#getAndAdd(Object...)} instead. */ + @Deprecated(since="23", forRemoval=true) @ForceInline public final Object getAndSetObject(Object o, long offset, Object newValue) { + beforeMemoryAccess(); return theInternalUnsafe.getAndSetReference(o, offset, newValue); } @@ -1201,7 +1677,7 @@ public final Object getAndSetObject(Object o, long offset, Object newValue) { * is almost always desired, and most current hardware instructions that * provide a LoadLoad barrier also provide a LoadStore barrier for free. * - * @deprecated Use {@link java.lang.invoke.VarHandle#acquireFence()} instead. + * @deprecated Use {@link VarHandle#acquireFence()} instead. * @since 1.8 */ @Deprecated(since="22", forRemoval=true) @@ -1221,7 +1697,7 @@ public void loadFence() { * is almost always desired, and most current hardware instructions that * provide a StoreStore barrier also provide a LoadStore barrier for free. * - * @deprecated Use {@link java.lang.invoke.VarHandle#releaseFence()} instead. + * @deprecated Use {@link VarHandle#releaseFence()} instead. * @since 1.8 */ @Deprecated(since="22", forRemoval=true) @@ -1238,7 +1714,7 @@ public void storeFence() { * * Corresponds to C11 atomic_thread_fence(memory_order_seq_cst). * - * @deprecated Use {@link java.lang.invoke.VarHandle#fullFence()} instead. + * @deprecated Use {@link VarHandle#fullFence()} instead. * @since 1.8 */ @Deprecated(since="22", forRemoval=true) @@ -1255,12 +1731,207 @@ public void fullFence() { * @throws IllegalArgumentException if {@code directBuffer} is non-direct, * or is a {@link java.nio.Buffer#slice slice}, or is a * {@link java.nio.Buffer#duplicate duplicate} + * + * @deprecated Use a {@link MemorySegment} allocated in an {@link Arena} with the + * appropriate temporal bounds. The {@link MemorySegment#asByteBuffer()} method + * wraps a memory segment as a {@code ByteBuffer} to allow interop with existing + * code. + * * @since 9 */ + @Deprecated(since="23", forRemoval=true) public void invokeCleaner(java.nio.ByteBuffer directBuffer) { if (!directBuffer.isDirect()) - throw new IllegalArgumentException("buffer is non-direct"); - + throw new IllegalArgumentException("Not a direct buffer"); + beforeMemoryAccess(); theInternalUnsafe.invokeCleaner(directBuffer); } + + // Infrastructure for --sun-misc-unsafe-memory-access= command line option. + + private static final Object MEMORY_ACCESS_WARNED_BASE; + private static final long MEMORY_ACCESS_WARNED_OFFSET; + static { + try { + Field field = Unsafe.class.getDeclaredField("memoryAccessWarned"); + MEMORY_ACCESS_WARNED_BASE = theInternalUnsafe.staticFieldBase(field); + MEMORY_ACCESS_WARNED_OFFSET = theInternalUnsafe.staticFieldOffset(field); + } catch (Exception e) { + throw new ExceptionInInitializerError(e); + } + } + // set to true by first usage of memory-access method + private static @Stable boolean memoryAccessWarned; + + private static boolean isMemoryAccessWarned() { + return theInternalUnsafe.getBooleanVolatile(MEMORY_ACCESS_WARNED_BASE, MEMORY_ACCESS_WARNED_OFFSET); + } + + private static boolean trySetMemoryAccessWarned() { + return theInternalUnsafe.compareAndSetBoolean(MEMORY_ACCESS_WARNED_BASE, MEMORY_ACCESS_WARNED_OFFSET, false, true); + } + + private static final MemoryAccessOption MEMORY_ACCESS_OPTION = MemoryAccessOption.value(); + + /** + * Invoked by all memory-access methods. + */ + @ForceInline + private static void beforeMemoryAccess() { + if (MEMORY_ACCESS_OPTION == MemoryAccessOption.ALLOW) { + return; + } + + if (MEMORY_ACCESS_OPTION == MemoryAccessOption.WARN && isMemoryAccessWarned()) { + // nothing to do if this is not the first usage + return; + } + + // warn && first usage, debug, or deny + beforeMemoryAccessSlow(); + } + + private static void beforeMemoryAccessSlow() { + assert MEMORY_ACCESS_OPTION != MemoryAccessOption.ALLOW; + + // stack trace without the frames for the beforeMemoryAccess methods + List stack = StackWalkerHolder.INSTANCE.walk(s -> + s.dropWhile(f -> (f.getDeclaringClass() == Unsafe.class) + && f.getMethodName().startsWith("beforeMemoryAccess")) + .limit(32) + .toList() + ); + + // callerClass -> Unsafe.methodName + String methodName = stack.get(0).getMethodName(); + Class callerClass = stack.get(1).getDeclaringClass(); + + switch (MEMORY_ACCESS_OPTION) { + case WARN -> { + if (trySetMemoryAccessWarned()) { + log(multiLineWarning(callerClass, methodName)); + } + } + case DEBUG -> { + String warning = singleLineWarning(callerClass, methodName); + StringBuilder sb = new StringBuilder(warning); + stack.stream() + .skip(1) + .forEach(f -> + sb.append(System.lineSeparator()).append("\tat " + f) + ); + log(sb.toString()); + } + case DENY -> { + throw new UnsupportedOperationException(methodName); + } + } + } + + /** + * Represents the options for the depreacted method-access methods. + */ + private enum MemoryAccessOption { + /** + * Allow use of the memory-access methods with no warnings. + */ + ALLOW, + /** + * Warning on the first use of a memory-access method. + */ + WARN, + /** + * One-line warning and a stack trace on every use of a memory-access method. + */ + DEBUG, + /** + * Deny use of the memory-access methods. + */ + DENY; + + private static MemoryAccessOption defaultValue() { + return ALLOW; + } + + /** + * Return the value. + */ + static MemoryAccessOption value() { + String value = VM.getSavedProperty("sun.misc.unsafe.memory.access"); + if (value != null) { + return switch (value) { + case "allow" -> MemoryAccessOption.ALLOW; + case "warn" -> MemoryAccessOption.WARN; + case "debug" -> MemoryAccessOption.DEBUG; + case "deny" -> MemoryAccessOption.DENY; + default -> { + // should not happen + log("sun.misc.unsafe.memory.access ignored, value '" + value + + "' is not a recognized value"); + yield defaultValue(); + } + }; + } else { + return defaultValue(); + } + } + } + + /** + * Holder for StackWalker that retains class references. + */ + private static class StackWalkerHolder { + static final StackWalker INSTANCE; + static { + PrivilegedAction pa = () -> + StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); + @SuppressWarnings("removal") + StackWalker walker = AccessController.doPrivileged(pa); + INSTANCE = walker; + } + } + + /** + * Return the multi-line warning message for when the given class invokes the + * given the Unsafe method. + */ + private static String multiLineWarning(Class callerClass, String methodName) { + return String.format( + """ + WARNING: A terminally deprecated method in sun.misc.Unsafe has been called + WARNING: sun.misc.Unsafe::%s has been called by %s + WARNING: Please consider reporting this to the maintainers of %s + WARNING: sun.misc.Unsafe::%s will be removed in a future release""", + methodName, callerAndLocation(callerClass), callerClass, methodName); + } + + /** + * Return the single-line warning message for when the given class invokes the + * given the Unsafe method. + */ + private static String singleLineWarning(Class callerClass, String methodName) { + return String.format("WARNING: sun.misc.Unsafe::%s called by %s", + methodName, callerAndLocation(callerClass)); + } + + /** + * Returns a string with the caller class and the location URL from the CodeSource. + */ + private static String callerAndLocation(Class callerClass) { + PrivilegedAction pa = callerClass::getProtectionDomain; + @SuppressWarnings("removal") + CodeSource cs = AccessController.doPrivileged(pa).getCodeSource(); + String who = callerClass.getName(); + if (cs != null && cs.getLocation() != null) { + who += " (" + cs.getLocation() + ")"; + } + return who; + } + + /** + * Prints the given message to the standard error. + */ + private static void log(String message) { + VM.initialErr().println(message); + } } diff --git a/test/jdk/sun/misc/TryUnsafeMemoryAccess.java b/test/jdk/sun/misc/TryUnsafeMemoryAccess.java new file mode 100644 index 00000000000..497940eca9a --- /dev/null +++ b/test/jdk/sun/misc/TryUnsafeMemoryAccess.java @@ -0,0 +1,136 @@ +/* + * 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.reflect.Field; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import sun.misc.Unsafe; + +/** + * Launched by UnsafeMemoryAccessWarnings with a '+' delimited list of methods to invoke. + */ +@SuppressWarnings("removal") +public class TryUnsafeMemoryAccess { + private static final Unsafe UNSAFE; + static { + try { + Field f = Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (Unsafe) f.get(null); + } catch (Exception e) { + throw new ExceptionInInitializerError(e); + } + } + private static long address; + private static long offset; + + static class TestClass { + long value; + TestClass(long value) { + this.value = value; + } + } + + /** + * The argument is a list of names of no-arg static methods in this class to invoke. + * The names are separated with a '+'. + */ + public static void main(String[] args) throws Exception { + String[] methodNames = args[0].split("\\+"); + for (String methodName : methodNames) { + Method m = TryUnsafeMemoryAccess.class.getDeclaredMethod(methodName); + try { + m.invoke(null); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + // a selection of Unsafe memory access methods to test + + static void allocateMemory() { + address = UNSAFE.allocateMemory(100); + } + + static void freeMemory() { + if (address == 0) + throw new RuntimeException("allocateMemory not called"); + UNSAFE.freeMemory(address); + } + + static void objectFieldOffset() throws Exception { + Field f = TestClass.class.getDeclaredField("value"); + offset = UNSAFE.objectFieldOffset(f); + } + + static void getLong() { + if (offset == 0) + throw new RuntimeException("objectFieldOffset not called"); + var obj = new TestClass(99); + long value = UNSAFE.getLong(obj, offset); + if (value != 99) { + throw new RuntimeException(); + } + } + + static void putLong() { + if (offset == 0) + throw new RuntimeException("objectFieldOffset not called"); + var obj = new TestClass(0); + UNSAFE.putLong(obj, offset, 99); + if (obj.value != 99) { + throw new RuntimeException(); + } + } + + static void invokeCleaner() { + var dbb = ByteBuffer.allocateDirect(1000); + UNSAFE.invokeCleaner(dbb); + } + + /** + * Invoke Unsafe.allocateMemory reflectively. + */ + static void reflectivelyAllocateMemory() throws Exception { + Method allocateMemory = Unsafe.class.getMethod("allocateMemory", long.class); + address = (long) allocateMemory.invoke(UNSAFE, 100); + } + + /** + * Invoke Unsafe.freeMemory reflectively. + */ + static void reflectivelyFreeMemory() throws Exception { + if (address == 0) + throw new RuntimeException("allocateMemory not called"); + Method freeMemory = Unsafe.class.getMethod("freeMemory", long.class); + freeMemory.invoke(UNSAFE, address); + } + + /** + * Used to test that the property value from startup is used. + */ + static void setSystemPropertyToAllow() { + System.setProperty("sun.misc.unsafe.memory.access", "allow"); + } +} diff --git a/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java b/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java new file mode 100644 index 00000000000..3d4b6965828 --- /dev/null +++ b/test/jdk/sun/misc/UnsafeMemoryAccessWarnings.java @@ -0,0 +1,212 @@ +/* + * 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 8331670 + * @summary Basic test for --sun-misc-unsafe-memory-access= + * @library /test/lib + * @compile TryUnsafeMemoryAccess.java + * @run junit UnsafeMemoryAccessWarnings + */ + +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import static org.junit.jupiter.api.Assertions.*; + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +class UnsafeMemoryAccessWarnings { + + /** + * Test default is "allow" + */ + @Test + void testDefault() throws Exception { + test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner") + .shouldHaveExitValue(0) + .shouldNotContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") + .shouldNotContain("WARNING: sun.misc.Unsafe::allocateMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::freeMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::objectFieldOffset") + .shouldNotContain("WARNING: sun.misc.Unsafe::putLong") + .shouldNotContain("WARNING: sun.misc.Unsafe::getLong") + .shouldNotContain("WARNING: sun.misc.Unsafe::invokeCleaner"); + } + + /** + * Test --sun-misc-unsafe-memory-access=allow + */ + @Test + void testAllow() throws Exception { + test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", + "--sun-misc-unsafe-memory-access=allow") + .shouldHaveExitValue(0) + .shouldNotContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") + .shouldNotContain("WARNING: sun.misc.Unsafe::allocateMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::freeMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::objectFieldOffset") + .shouldNotContain("WARNING: sun.misc.Unsafe::putLong") + .shouldNotContain("WARNING: sun.misc.Unsafe::getLong") + .shouldNotContain("WARNING: sun.misc.Unsafe::invokeCleaner"); + } + + /** + * Test --sun-misc-unsafe-memory-access=warn + */ + @ParameterizedTest + @ValueSource(strings = { + "allocateMemory+freeMemory", + "objectFieldOffset+putLong+getLong", + "invokeCleaner" + }) + void testWarn(String input) throws Exception { + var output = test(input, "--sun-misc-unsafe-memory-access=warn").shouldHaveExitValue(0); + + // should be warning printed for the first memory access method + String[] methodNames = input.split("\\+"); + String firstMethodName = methodNames[0]; + output.shouldContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") + .shouldContain("WARNING: sun.misc.Unsafe::" + firstMethodName + " has been called by") + .shouldContain("WARNING: Please consider reporting this to the maintainers of") + .shouldContain("WARNING: sun.misc.Unsafe::" + firstMethodName + " will be removed in a future release"); + + // should be no warning for the second/subsequent memory access methods + int index = 1; + while (index < methodNames.length) { + String methodName = methodNames[index++]; + output.shouldNotContain("WARNING: sun.misc.Unsafe::" + methodName); + } + } + + /** + * Test --sun-misc-unsafe-memory-access=debug + */ + @Test + void testDebug() throws Exception { + test("allocateMemory+freeMemory+objectFieldOffset+putLong+getLong+invokeCleaner", + "--sun-misc-unsafe-memory-access=debug") + .shouldHaveExitValue(0) + .shouldContain("WARNING: sun.misc.Unsafe::allocateMemory called") + .shouldContain("WARNING: sun.misc.Unsafe::freeMemory called") + .shouldContain("WARNING: sun.misc.Unsafe::objectFieldOffset called") + .shouldContain("WARNING: sun.misc.Unsafe::putLong called") + .shouldContain("WARNING: sun.misc.Unsafe::getLong called") + .shouldContain("WARNING: sun.misc.Unsafe::invokeCleaner called"); + } + + /** + * Test --sun-misc-unsafe-memory-access=deny + */ + @Test + void testDeny() throws Exception { + test("allocateMemory+objectFieldOffset+invokeCleaner", "--sun-misc-unsafe-memory-access=deny") + .shouldHaveExitValue(0) + .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") + .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") + .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); + } + + /** + * Test invoking Unsafe methods with core reflection. + */ + @Test + void testInvokeReflectively() throws Exception { + test("reflectivelyAllocateMemory+reflectivelyFreeMemory", "--sun-misc-unsafe-memory-access=allow") + .shouldHaveExitValue(0) + .shouldNotContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") + .shouldNotContain("WARNING: sun.misc.Unsafe::allocateMemory") + .shouldNotContain("WARNING: sun.misc.Unsafe::freeMemory"); + + test("reflectivelyAllocateMemory+reflectivelyFreeMemory", "--sun-misc-unsafe-memory-access=warn") + .shouldHaveExitValue(0) + .shouldContain("WARNING: A terminally deprecated method in sun.misc.Unsafe has been called") + .shouldContain("WARNING: sun.misc.Unsafe::allocateMemory has been called by") + .shouldContain("WARNING: Please consider reporting this to the maintainers of") + .shouldContain("WARNING: sun.misc.Unsafe::allocateMemory will be removed in a future release") + .shouldNotContain("WARNING: sun.misc.Unsafe::freeMemory"); + + test("reflectivelyAllocateMemory+reflectivelyFreeMemory", "--sun-misc-unsafe-memory-access=debug") + .shouldHaveExitValue(0) + .shouldContain("WARNING: sun.misc.Unsafe::allocateMemory called") + .shouldContain("WARNING: sun.misc.Unsafe::freeMemory called"); + + test("reflectivelyAllocateMemory", "--sun-misc-unsafe-memory-access=deny") + .shouldHaveExitValue(0) + .shouldContain("java.lang.UnsupportedOperationException: allocateMemory"); + } + + /** + * If --sun-misc-unsafe-memory-access specified more than once then last one wins. + */ + @Test + void testLastOneWins() throws Exception { + test("allocateMemory+objectFieldOffset+invokeCleaner", + "--sun-misc-unsafe-memory-access=allow", + "--sun-misc-unsafe-memory-access=deny") + .shouldHaveExitValue(0) + .shouldContain("java.lang.UnsupportedOperationException: allocateMemory") + .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset") + .shouldContain("java.lang.UnsupportedOperationException: invokeCleaner"); + } + + /** + * Test --sun-misc-unsafe-memory-access with invalid values. + */ + @ParameterizedTest + @ValueSource(strings = { "", "bad" }) + void testInvalidValues(String value) throws Exception { + test("allocateMemory", "--sun-misc-unsafe-memory-access=" + value) + .shouldNotHaveExitValue(0) + .shouldContain("Value specified to --sun-misc-unsafe-memory-access not recognized: '" + value); + } + + /** + * Test System.setProperty("sun.misc.unsafe.memory.access", "allow") + * The saved value from startup should be used, not the system property set at run-time. + */ + @Test + void testSetPropertyToAllow() throws Exception { + test("setSystemPropertyToAllow+objectFieldOffset", "--sun-misc-unsafe-memory-access=deny") + .shouldHaveExitValue(0) + .shouldContain("java.lang.UnsupportedOperationException: objectFieldOffset"); + } + + /** + * Launch TryUnsafeMemoryAccess with the given arguments and VM options. + */ + private OutputAnalyzer test(String action, String... vmopts) throws Exception { + Stream s1 = Stream.of(vmopts); + Stream s2 = Stream.of("TryUnsafeMemoryAccess", action); + String[] opts = Stream.concat(s1, s2).toArray(String[]::new); + var outputAnalyzer = ProcessTools + .executeTestJava(opts) + .outputTo(System.err) + .errorTo(System.err); + return outputAnalyzer; + } +} diff --git a/test/micro/org/openjdk/bench/sun/misc/UnsafeOps.java b/test/micro/org/openjdk/bench/sun/misc/UnsafeOps.java new file mode 100644 index 00000000000..1d4a80e43dd --- /dev/null +++ b/test/micro/org/openjdk/bench/sun/misc/UnsafeOps.java @@ -0,0 +1,89 @@ +/* + * 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.sun.misc; + +import java.lang.reflect.Field; +import java.util.concurrent.TimeUnit; +import sun.misc.Unsafe; +import org.openjdk.jmh.annotations.*; + +@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.NANOSECONDS) +@SuppressWarnings("removal") +public class UnsafeOps { + static final Unsafe U; + static { + try { + Field f = Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + U = (Unsafe) f.get(null); + } catch (ReflectiveOperationException ex) { + throw new IllegalStateException(); + } + } + + private static class TestClass { + long value; + } + + private Object object; + private long valueOffset; + private long address; + + @Setup + public void setup() throws Exception { + object = new TestClass(); + Field f = TestClass.class.getDeclaredField("value"); + valueOffset = U.objectFieldOffset(f); + + address = U.allocateMemory(1000); + } + + @TearDown + public void finish() { + U.freeMemory(address); + } + + @Benchmark + public void putLongOnHeap() { + U.putLong(object, 0, 99); + } + + @Benchmark + public long getLongOnHeap() { + return U.getLong(object, 0); + } + + @Benchmark + public void putLongOffHeap() { + U.putLong(null, address, 99); + } + + @Benchmark + public long getLongOffHeap() { + return U.getLong(null, address); + } +} From b8f2ec9091f9f7e5f4611991d04dd8aa113b94fd Mon Sep 17 00:00:00 2001 From: Steven Loomis Date: Tue, 28 May 2024 16:44:44 +0000 Subject: [PATCH 77/99] 8195675: Call to insertText with single character from custom Input Method ignored Reviewed-by: prr --- src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m index c349df39dcc..e881c5cc38f 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m @@ -38,6 +38,9 @@ // keyboard layout static NSString *kbdLayout; +// Constant for keyman layouts +#define KEYMAN_LAYOUT "keyman" + @interface AWTView() @property (retain) CDropTarget *_dropTarget; @property (retain) CDragSource *_dragSource; @@ -259,7 +262,7 @@ - (void) scrollWheel: (NSEvent*) event { - (void) keyDown: (NSEvent *)event { fProcessingKeystroke = YES; - fKeyEventsNeeded = YES; + fKeyEventsNeeded = ![(NSString *)kbdLayout containsString:@KEYMAN_LAYOUT]; // Allow TSM to look at the event and potentially send back NSTextInputClient messages. [self interpretKeyEvents:[NSArray arrayWithObject:event]]; @@ -965,7 +968,7 @@ - (void) insertText:(id)aString replacementRange:(NSRange)replacementRange if ((utf16Length > 2) || ((utf8Length > 1) && [self isCodePointInUnicodeBlockNeedingIMEvent:codePoint]) || - ((codePoint == 0x5c) && ([(NSString *)kbdLayout containsString:@"Kotoeri"]))) { + [(NSString *)kbdLayout containsString:@KEYMAN_LAYOUT]) { #ifdef IM_DEBUG NSLog(@"string complex "); #endif From da6aa2a86c86ba5fce747b36dcb2d6001cfcc44e Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Tue, 28 May 2024 17:07:27 +0000 Subject: [PATCH 78/99] 8332849: Update doc/testing.{md,html} (spelling and stale information) Reviewed-by: iris, ihse, erikj, djelinski --- doc/testing.html | 28 ++++++++-------------------- doc/testing.md | 30 +++++++----------------------- 2 files changed, 15 insertions(+), 43 deletions(-) diff --git a/doc/testing.html b/doc/testing.html index f907ef3a838..c56dfa31188 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -177,10 +177,10 @@

    Test selection

    more tab-completion friendly. For more complex test runs, the test TEST="x" solution needs to be used.

    The test specifications given in TEST is parsed into -fully qualified test descriptors, which clearly and unambigously show +fully qualified test descriptors, which clearly and unambiguously show which tests will be run. As an example, :tier1 will expand -to include all subcomponent test directories that define `tier1`, -for example: +to include all subcomponent test directories that define +tier1, for example: jtreg:$(TOPDIR)/test/hotspot/jtreg:tier1 jtreg:$(TOPDIR)/test/jdk:tier1 jtreg:$(TOPDIR)/test/langtools:tier1 .... You can always submit a list of fully qualified test descriptors in the TEST variable if you want to shortcut the parser.

    @@ -228,7 +228,7 @@

    Common Test Groups

    These contain, among other things, tests that either run for too long to be at tier1, or may require special configuration, or tests that are less stable, or cover the broader range of non-core JVM and JDK -features/components(for example, XML).

    +features/components (for example, XML).

  • tier3: This test group includes more stressful tests, the tests for corner cases not covered by previous tiers, plus the tests that require GUIs. As such, this suite should either be run @@ -368,7 +368,7 @@

    Test suite control

    just pass unnoticed.

    To separate multiple keyword=value pairs, use ; (semicolon). Since the shell normally eats ;, the -recommended usage is to write the assignment inside qoutes, e.g. +recommended usage is to write the assignment inside quotes, e.g. JTREG="...;...". This will also make sure spaces are preserved, as in JTREG="JAVA_OPTIONS=-XshowSettings -Xlog:gc+ref=debug".

    @@ -397,10 +397,8 @@

    JAVA_OPTIONS

    Applies to JTReg, GTest and Micro.

    VM_OPTIONS

    Applies to JTReg, GTest and Micro.

    -

    AOT_MODULES

    -

    Applies to JTReg and GTest.

    JCOV

    -

    This keywords applies globally to the test runner system. If set to +

    This keyword applies globally to the test runner system. If set to true, it enables JCov coverage reporting for all tests run. To be useful, the JDK under test must be run with a JDK built with JCov instrumentation @@ -500,11 +498,6 @@

    VM_OPTIONS

    LAUNCHER_OPTIONS

    Additional Java options that are sent to the java launcher that starts the JTReg harness.

    -

    AOT_MODULES

    -

    Generate AOT modules before testing for the specified module, or set -of modules. If multiple modules are specified, they should be separated -by space (or, to help avoid quoting issues, the special value -%20).

    RETRY_COUNT

    Retry failed tests up to a set number of times, until they pass. This allows to pass the tests with intermittent failures. Defaults to 0.

    @@ -527,11 +520,6 @@

    OPTIONS

    Additional options to the Gtest test framework.

    Use GTEST="OPTIONS=--help" to see all available Gtest options.

    -

    AOT_MODULES

    -

    Generate AOT modules before testing for the specified module, or set -of modules. If multiple modules are specified, they should be separated -by space (or, to help avoid quoting issues, the special value -%20).

    Microbenchmark keywords

    FORK

    Override the number of benchmark forks to spawn. Same as specifying @@ -575,7 +563,7 @@

    Non-US locale

    If your locale is non-US, some tests are likely to fail. To work around this you can set the locale to US. On Unix platforms simply setting LANG="en_US" in the environment before running -tests should work. On Windows or MacOS, setting +tests should work. On Windows or macOS, setting JTREG="VM_OPTIONS=-Duser.language=en -Duser.country=US" helps for most, but not all test cases.

    For example:

    @@ -610,7 +598,7 @@
    macOS
    Shortcuts; select or deselect desired shortcut.

    For example, test/jdk/javax/swing/TooltipManager/JMenuItemToolTipKeyBindingsTest/JMenuItemToolTipKeyBindingsTest.java -fails on MacOS because it uses CTRL + F1 key sequence to +fails on macOS because it uses CTRL + F1 key sequence to show or hide tooltip message but the key combination is reserved by the operating system. To run the test correctly the default global key shortcut should be disabled using the steps described above, and then diff --git a/doc/testing.md b/doc/testing.md index 9a45283a98b..351745c9293 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -102,8 +102,8 @@ TEST="tier1"`, but the latter is more tab-completion friendly. For more complex test runs, the `test TEST="x"` solution needs to be used. The test specifications given in `TEST` is parsed into fully qualified test -descriptors, which clearly and unambigously show which tests will be run. As an -example, `:tier1` will expand to include all subcomponent test directories +descriptors, which clearly and unambiguously show which tests will be run. As +an example, `:tier1` will expand to include all subcomponent test directories that define `tier1`, for example: `jtreg:$(TOPDIR)/test/hotspot/jtreg:tier1 jtreg:$(TOPDIR)/test/jdk:tier1 jtreg:$(TOPDIR)/test/langtools:tier1 ...`. You can always submit a list of fully qualified test descriptors in the `TEST` @@ -151,7 +151,7 @@ A brief description of the tiered test groups: - `tier2`: This test group covers even more ground. These contain, among other things, tests that either run for too long to be at `tier1`, or may require special configuration, or tests that are less stable, or cover the broader - range of non-core JVM and JDK features/components(for example, XML). + range of non-core JVM and JDK features/components (for example, XML). - `tier3`: This test group includes more stressful tests, the tests for corner cases not covered by previous tiers, plus the tests that require GUIs. As @@ -294,7 +294,7 @@ would just pass unnoticed. To separate multiple keyword=value pairs, use `;` (semicolon). Since the shell normally eats `;`, the recommended usage is to write the assignment inside -qoutes, e.g. `JTREG="...;..."`. This will also make sure spaces are preserved, +quotes, e.g. `JTREG="...;..."`. This will also make sure spaces are preserved, as in `JTREG="JAVA_OPTIONS=-XshowSettings -Xlog:gc+ref=debug"`. (Other ways are possible, e.g. using backslash: @@ -334,13 +334,9 @@ Applies to JTReg, GTest and Micro. Applies to JTReg, GTest and Micro. -#### AOT_MODULES - -Applies to JTReg and GTest. - #### JCOV -This keywords applies globally to the test runner system. If set to `true`, it +This keyword applies globally to the test runner system. If set to `true`, it enables JCov coverage reporting for all tests run. To be useful, the JDK under test must be run with a JDK built with JCov instrumentation (`configure --with-jcov=`, `make jcov-image`). @@ -480,12 +476,6 @@ your test classes, use `JAVA_OPTIONS`. Additional Java options that are sent to the java launcher that starts the JTReg harness. -#### AOT_MODULES - -Generate AOT modules before testing for the specified module, or set of -modules. If multiple modules are specified, they should be separated by space -(or, to help avoid quoting issues, the special value `%20`). - #### RETRY_COUNT Retry failed tests up to a set number of times, until they pass. This allows to @@ -517,12 +507,6 @@ Additional options to the Gtest test framework. Use `GTEST="OPTIONS=--help"` to see all available Gtest options. -#### AOT_MODULES - -Generate AOT modules before testing for the specified module, or set of -modules. If multiple modules are specified, they should be separated by space -(or, to help avoid quoting issues, the special value `%20`). - ### Microbenchmark keywords #### FORK @@ -587,7 +571,7 @@ $ make test TEST="jtreg:test/hotspot/jtreg/containers/docker" \ If your locale is non-US, some tests are likely to fail. To work around this you can set the locale to US. On Unix platforms simply setting `LANG="en_US"` -in the environment before running tests should work. On Windows or MacOS, +in the environment before running tests should work. On Windows or macOS, setting `JTREG="VM_OPTIONS=-Duser.language=en -Duser.country=US"` helps for most, but not all test cases. @@ -635,7 +619,7 @@ select or deselect desired shortcut. For example, test/jdk/javax/swing/TooltipManager/JMenuItemToolTipKeyBindingsTest/JMenuItemToolTipKeyBindingsTest.java -fails on MacOS because it uses `CTRL + F1` key sequence to show or hide tooltip +fails on macOS because it uses `CTRL + F1` key sequence to show or hide tooltip message but the key combination is reserved by the operating system. To run the test correctly the default global key shortcut should be disabled using the steps described above, and then deselect "Turn keyboard access on or off" From 91caec07cb2e4d98d4366f5627f55834282caa94 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Tue, 28 May 2024 19:26:17 +0000 Subject: [PATCH 79/99] 8330542: Template for Creating Strict JAXP Configuration File Reviewed-by: lancea, erikj, alanb, ihse, mullan, naoto --- make/modules/java.xml/Copy.gmk | 19 +-- .../conf/jaxp-strict.properties.template | 123 ++++++++++++++++++ src/java.xml/share/conf/jaxp.properties | 31 +++-- .../common/config/ConfigFileTest.java | 114 ++++++++++++++++ .../jaxp/unittest/common/util/TestBase.java | 17 ++- 5 files changed, 280 insertions(+), 24 deletions(-) create mode 100644 src/java.xml/share/conf/jaxp-strict.properties.template create mode 100644 test/jaxp/javax/xml/jaxp/unittest/common/config/ConfigFileTest.java diff --git a/make/modules/java.xml/Copy.gmk b/make/modules/java.xml/Copy.gmk index 3b6c66e42c5..f242cb2ac76 100644 --- a/make/modules/java.xml/Copy.gmk +++ b/make/modules/java.xml/Copy.gmk @@ -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 @@ -24,14 +24,17 @@ # include CopyCommon.gmk +include Modules.gmk ################################################################################ +# +# Copy property and template files from share/conf to CONF_DST_DIR +# +$(eval $(call SetupCopyFiles, COPY_XML_MODULE_CONF, \ + DEST := $(CONF_DST_DIR), \ + SRC := $(TOPDIR)/src/java.xml/share/conf, \ + FILES := jaxp.properties jaxp-strict.properties.template, \ +)) -XML_LIB_SRC := $(TOPDIR)/src/java.xml/share/conf - -$(CONF_DST_DIR)/jaxp.properties: $(XML_LIB_SRC)/jaxp.properties - $(call install-file) - -TARGETS := $(CONF_DST_DIR)/jaxp.properties - +TARGETS += $(COPY_XML_MODULE_CONF) ################################################################################ diff --git a/src/java.xml/share/conf/jaxp-strict.properties.template b/src/java.xml/share/conf/jaxp-strict.properties.template new file mode 100644 index 00000000000..2d6cbc951e2 --- /dev/null +++ b/src/java.xml/share/conf/jaxp-strict.properties.template @@ -0,0 +1,123 @@ +################################################################################ +# JAXP Strict Configuration Template +# +# This file, jaxp-strict.properties.template, provides a template for creating +# custom configuration files. The settings in this file are more restrictive than +# those in the default configuration, jaxp.properties. In particular: +# - JDKCatalog Resolve is on "strict" setting +# - Extension Functions are disabled +# - JAXP Limits are set to smaller numbers +# +# To create a configuration file, copy the template to a new file with +# the .properties extension, that is: +# +# cp $JAVA_HOME/conf/jaxp-strict.properties.template /path/to/jaxp-strict.properties +# +# The configuration file can then be set up using the system property +# java.xml.config.file to override the default configuration jaxp.properties +# and used to assess the impact of a stricter configuration, for example: +# +# java -Djava.xml.config.file=/path/to/jaxp-strict.properties +# +# The system property java.xml.config.file is defined in the java.xml module +# description. +# +################################################################################ + +# +# ---- Implementation Specific Properties ---- +# For a complete list of properties, refer to the Implementation Specific Properties +# table in the java.xml/module-summary. +# +# Extension Functions: +# +# This property determines whether XSLT and XPath extension functions are allowed. +# The value type is boolean and the default value is true (allowing +# extension functions). The following entry overrides the default value and +# disallows extension functions: +# +jdk.xml.enableExtensionFunctions=false +# +# +# Overriding the default parser: +# +# This property allows a third party implementation to override the default +# parser provided by the JDK. The value type is boolean and the default value is +# false, disallowing overriding the default parser. The setting below reflects +# the default property setting: +# +jdk.xml.overrideDefaultParser=false +# +# Implementation Specific Properties - jdkcatalog.resolve +# +# This property instructs the JDK default CatalogResolver to act in accordance with +# the setting when unable to resolve an external reference with the built-in Catalog. +# The options are: +# continue -- indicates that the processing should continue +# ignore -- indicates that the reference is skipped +# strict -- indicates that the resolver should throw a CatalogException +# +# The following setting causes the default CatalogResolver to throw a CatalogException +# when external references are not resolved by a user-defined resolver or catalog, +# or the built-in Catalog: +jdk.xml.jdkcatalog.resolve=strict +# +# Implementation Specific Properties - DTD +# +# This property instructs the parsers to deny, ignore or allow DTD processing. +# The following setting causes the parser to reject DTDs by throwing an exception. +# jdk.xml.dtd.support=deny +# +# The following setting permits the processor to continue processing DTDs. Note +# that while DTDs are allowed in this configuration, external references are +# restricted, and limits on DTD entities are tightened: +jdk.xml.dtd.support=allow +# +# Implementation Specific Properties - Limits +# +# Limits have a value type Integer. The values must be positive integers. Zero +# means no limit. +# +# Limits the number of entity expansions +jdk.xml.entityExpansionLimit=2500 +# +# Limits the total size of all entities that include general and parameter entities. +# The size is calculated as an aggregation of all entities. +jdk.xml.totalEntitySizeLimit=100000 +# +# Limits the maximum size of any general entities. +jdk.xml.maxGeneralEntitySizeLimit=100000 +# +# Limits the maximum size of any parameter entities, including the result of +# nesting multiple parameter entities. +jdk.xml.maxParameterEntitySizeLimit=15000 +# +# Limits the total number of nodes in all entity references. +jdk.xml.entityReplacementLimit=100000 +# +# Limits the number of attributes an element can have. The default value is 10000. +jdk.xml.elementAttributeLimit=10000 +# +# Limits the number of content model nodes that may be created when building a +# grammar for a W3C XML Schema that contains maxOccurs attributes with values +# other than "unbounded". The default value is 5000. +jdk.xml.maxOccurLimit=5000 +# +# Limits the maximum element depth. The default value is 0. +jdk.xml.maxElementDepth=0 +# +# Limits the maximum size of XML names, including element name, attribute name +# and namespace prefix and URI. The default value is 1000. +jdk.xml.maxXMLNameLimit=1000 +# +# +# XPath Limits +# +# Limits the number of groups an XPath expression can contain. The default value is 10. +jdk.xml.xpathExprGrpLimit=10 +# +# Limits the number of operators an XPath expression can contain. The default value is 100. +jdk.xml.xpathExprOpLimit=100 +# +# Limits the total number of XPath operators in an XSL Stylesheet. The default value is 10000. +jdk.xml.xpathTotalOpLimit=10000 diff --git a/src/java.xml/share/conf/jaxp.properties b/src/java.xml/share/conf/jaxp.properties index 53074816cb9..53835f63743 100644 --- a/src/java.xml/share/conf/jaxp.properties +++ b/src/java.xml/share/conf/jaxp.properties @@ -31,7 +31,7 @@ # # The format of an entry is key=value where the key is the fully qualified name # of the factory and value that of the implementation class. The following entry -# set a DocumentBuilderFactory implementation class: +# sets a DocumentBuilderFactory implementation class: # # javax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl # @@ -49,7 +49,7 @@ # # For example, the RESOLVE property in CatalogFeatures has an associated system # property called javax.xml.catalog.resolve. An entry for the RESOLVE property in the -# configuration file would therefore use javax.xml.catalog.resolve as the key, that +# configuration file therefore uses javax.xml.catalog.resolve as the key, that # is: # javax.xml.catalog.resolve=strict # @@ -58,15 +58,15 @@ # # This property determines whether XSLT and XPath extension functions are allowed. # The value type is boolean and the default value is true (allowing -# extension functions). The following entry would override the default value and -# disallow extension functions: +# extension functions). The following entry overrides the default value and +# disallows extension functions: # # jdk.xml.enableExtensionFunctions=false # # # Overriding the default parser: # -# This property allows using a third party implementation to override the default +# This property allows a third party implementation to override the default # parser provided by the JDK. The value type is boolean and the default value is # false, disallowing overriding the default parser. The setting below reflects # the default property setting: @@ -137,16 +137,20 @@ jdk.xml.overrideDefaultParser=false # ignore -- indicates that the reference is skipped # strict -- indicates that the resolver should throw a CatalogException # -# The following setting would cause the resolve to throw a CatalogException when -# unable to resolve an external reference: -# jdk.xml.jdkcatalog.resolve=strict +# The following setting allows the resolution to continue in cases where +# external references are not resolved by a user-defined resolver or catalog if +# any, and the built-in Catalog: +jdk.xml.jdkcatalog.resolve=continue # # Implementation Specific Properties - DTD # -# This property instructs the parsers to: deny, ignore or allow DTD processing. -# The following setting would cause the parser to reject DTD by throwing an exception. +# This property instructs the parsers to deny, ignore or allow DTD processing. +# The following setting causes the parser to reject DTDs by throwing an exception. # jdk.xml.dtd.support=deny # +# The following setting permits the processor to continue processing DTDs +jdk.xml.dtd.support=allow +# # Implementation Specific Properties - Limits # # Limits have a value type Integer. The values must be positive integers. Zero @@ -157,17 +161,17 @@ jdk.xml.overrideDefaultParser=false # # Limits the total size of all entities that include general and parameter entities. # The size is calculated as an aggregation of all entities. The default value is 5x10^7. -# jdk.xml.totalEntitySizeLimit=5E7 +# jdk.xml.totalEntitySizeLimit=50000000 # # Limits the maximum size of any general entities. The default value is 0. # jdk.xml.maxGeneralEntitySizeLimit=0 # # Limits the maximum size of any parameter entities, including the result of # nesting multiple parameter entities. The default value is 10^6. -# jdk.xml.maxParameterEntitySizeLimit=1E6 +# jdk.xml.maxParameterEntitySizeLimit=1000000 # # Limits the total number of nodes in all entity references. The default value is 3x10^6. -# jdk.xml.entityReplacementLimit=3E6 +# jdk.xml.entityReplacementLimit=3000000 # # Limits the number of attributes an element can have. The default value is 10000. # jdk.xml.elementAttributeLimit=10000 @@ -195,4 +199,3 @@ jdk.xml.xpathExprOpLimit=100 # # Limits the total number of XPath operators in an XSL Stylesheet. The default value is 10000. jdk.xml.xpathTotalOpLimit=10000 - diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/config/ConfigFileTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/config/ConfigFileTest.java new file mode 100644 index 00000000000..fd5b8b36fa3 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/config/ConfigFileTest.java @@ -0,0 +1,114 @@ +/* + * 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 common.config; + +import common.util.TestBase; +import static common.util.TestBase.CONFIG_DEFAULT; +import static common.util.TestBase.CONFIG_STRICT; +import static common.util.TestBase.CONFIG_TEMPLATE_STRICT; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.IntStream; +import javax.xml.transform.TransformerFactory; + +/** + * @test @bug 8330542 + * @summary verifies the default JAXP configuration file jaxp.properties and + * strict template jaxp-strict.properties.template. + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @modules java.xml/jdk.xml.internal + * @run driver common.config.ConfigFileTest 0 // verifies jaxp.properties + * @run driver common.config.ConfigFileTest 1 // verifies jaxp-strict.properties.template + */ +public class ConfigFileTest { + // system property for custom configuration file + static final String SP_CONFIG = "java.xml.config.file"; + // target directory + static String TEST_DIR = System.getProperty("test.classes"); + + // properties in the configuration file + String[] keys = { + "jdk.xml.enableExtensionFunctions", + "jdk.xml.overrideDefaultParser", + "jdk.xml.jdkcatalog.resolve", + "jdk.xml.dtd.support", + "jdk.xml.entityExpansionLimit", + "jdk.xml.totalEntitySizeLimit", + "jdk.xml.maxGeneralEntitySizeLimit", + "jdk.xml.maxParameterEntitySizeLimit", + "jdk.xml.entityReplacementLimit", + "jdk.xml.elementAttributeLimit", + "jdk.xml.maxOccurLimit", + "jdk.xml.maxElementDepth", + "jdk.xml.maxXMLNameLimit", + "jdk.xml.xpathExprGrpLimit", + "jdk.xml.xpathExprOpLimit", + "jdk.xml.xpathTotalOpLimit"}; + + // type of properties + boolean[] propertyIsFeature ={true, true, false, false, false, false, + false, false, false, false, false, false, false, false, false, false}; + + // values from jaxp-strict.properties.template + String[] strictValues ={"false", "false", "strict", "allow", "2500", "100000", + "100000", "15000", "100000", "10000", "5000", "0", "1000", "10", "100", "10000"}; + + // values from jaxp.properties, as of JDK 23 + String[] defaultValues ={"true", "false", "continue", "allow", "64000", "50000000", + "0", "1000000", "3000000", "10000", "5000", "0", "1000", "10", "100", "10000"}; + + public static void main(String args[]) throws Exception { + new ConfigFileTest().run(args[0]); + } + + public void run(String index) throws Exception { + String conf = System.getProperty("java.home") + "/conf/"; + if (index.equals("0")) { + verifyConfig(conf + CONFIG_DEFAULT, defaultValues); + } else { + Path config = Paths.get(TEST_DIR, CONFIG_STRICT); + Files.copy(Paths.get(conf, CONFIG_TEMPLATE_STRICT), config); + verifyConfig(config.toString(), strictValues); + } + } + + /** + * Verifies a configuration file by iterating through its property settings. + * @param filename the configuration file + * @param values expected values in the configuration file + */ + private void verifyConfig(String filename, String[] values) { + System.setProperty(SP_CONFIG, filename); + + TransformerFactory tf = TransformerFactory.newInstance(); + IntStream.range(0, keys.length).forEach(i -> { + if (propertyIsFeature[i]) { + TestBase.Assert.assertEquals(tf.getFeature(keys[i]), Boolean.parseBoolean(values[i])); + } else { + TestBase.Assert.assertEquals(tf.getAttribute(keys[i]), values[i]); + } + }); + System.clearProperty(SP_CONFIG); + } +} diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java b/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java index 6be967d8dd5..77672609147 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.java +++ b/test/jaxp/javax/xml/jaxp/unittest/common/util/TestBase.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 @@ -28,6 +28,7 @@ import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; +import java.util.Objects; import java.util.regex.Pattern; import javax.xml.XMLConstants; import javax.xml.catalog.CatalogFeatures; @@ -121,6 +122,11 @@ public class TestBase { // CATALOG=strict public static final String CONFIG_CATALOG_STRICT = "catalog2.properties"; + // JAXP Configuration Files to be added to $JAVA_HOME/conf/ + public static final String CONFIG_DEFAULT = "jaxp.properties"; + public static final String CONFIG_STRICT = "jaxp-strict.properties"; + public static final String CONFIG_TEMPLATE_STRICT = "jaxp-strict.properties.template"; + public static final String UNKNOWN_HOST = "invalid.site.com"; String xmlExternalEntity, xmlExternalEntityId; @@ -133,6 +139,7 @@ public static enum Properties { // config file: CATALOG = strict CONFIG_FILE_CATALOG_STRICT(null, CONFIG_FILE, Type.FEATURE, getPath(CONFIG_FILE_PATH, CONFIG_CATALOG_STRICT)), CONFIG_FILE_DTD2(null, CONFIG_FILE, Type.FEATURE, getPath(CONFIG_FILE_PATH, JCF_DTD2)), + FSP(XMLConstants.FEATURE_SECURE_PROCESSING, null, Type.FEATURE, "true"), FSP_FALSE(XMLConstants.FEATURE_SECURE_PROCESSING, null, Type.FEATURE, "false"), @@ -715,7 +722,7 @@ static String getPath(String base, String file) { return temp; } - static class Assert { + public static class Assert { public static void assertTrue(boolean condition) { assertTrue(condition, null); } @@ -733,5 +740,11 @@ public static void assertTrue(boolean condition, String message) { public static void fail(String message) { throw new RuntimeException("Test failed. " + message); } + + public static void assertEquals(Object actual, Object expected) { + if (!Objects.equals(actual, expected)) { + throw new RuntimeException("Expected: " + expected + " but actual result was " + actual); + } + } } } From 9ac8d05a2567fbf65b944660739e5f8ad1fc2020 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 28 May 2024 20:00:14 +0000 Subject: [PATCH 80/99] 8332228: TypePollution.java: Unrecognized VM option 'UseSecondarySuperCache' Reviewed-by: chagedorn, kvn --- .../org/openjdk/bench/vm/lang/TypePollution.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/micro/org/openjdk/bench/vm/lang/TypePollution.java b/test/micro/org/openjdk/bench/vm/lang/TypePollution.java index 8109e205d15..aa1a0207587 100644 --- a/test/micro/org/openjdk/bench/vm/lang/TypePollution.java +++ b/test/micro/org/openjdk/bench/vm/lang/TypePollution.java @@ -105,28 +105,28 @@ public void setup() { int probe = 99; @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:-UseSecondarySuperCache"}) + @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) public long parallelInstanceOfInterfaceSwitchLinearNoSCC() { return parallelInstanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:+UseSecondarySuperCache"}) + @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) public long parallelInstanceOfInterfaceSwitchLinearSCC() { return parallelInstanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:-UseSecondarySuperCache"}) + @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) public long parallelInstanceOfInterfaceSwitchTableNoSCC() { return parallelInstanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:+UseSecondarySuperCache"}) + @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) @OutputTimeUnit(TimeUnit.MILLISECONDS) public long parallelInstanceOfInterfaceSwitchTableSCC() { return parallelInstanceOfInterfaceSwitch(); @@ -149,25 +149,25 @@ long parallelInstanceOfInterfaceSwitch() { } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:-UseSecondarySuperCache"}) + @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) public int instanceOfInterfaceSwitchLinearNoSCC() { return instanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:+UseSecondarySuperCache"}) + @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:-UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) public int instanceOfInterfaceSwitchLinearSCC() { return instanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:-UseSecondarySuperCache"}) + @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:-UseSecondarySupersCache"}) public int instanceOfInterfaceSwitchTableNoSCC() { return instanceOfInterfaceSwitch(); } @Benchmark - @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:+UseSecondarySuperCache"}) + @Fork(jvmArgsAppend={"-XX:+UnlockDiagnosticVMOptions", "-XX:+UseSecondarySupersTable", "-XX:+UseSecondarySupersCache"}) public int instanceOfInterfaceSwitchTableSCC() { return instanceOfInterfaceSwitch(); } From 91ab088d5e64e068bafcda8d08f1769c39ba10d6 Mon Sep 17 00:00:00 2001 From: Alexey Semenyuk Date: Tue, 28 May 2024 21:39:38 +0000 Subject: [PATCH 81/99] 8333116: test/jdk/tools/jpackage/share/ServiceTest.java test fails Reviewed-by: almatvee --- test/jdk/tools/jpackage/share/ServiceTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/jdk/tools/jpackage/share/ServiceTest.java b/test/jdk/tools/jpackage/share/ServiceTest.java index 5142ada2742..4cf96b62cd2 100644 --- a/test/jdk/tools/jpackage/share/ServiceTest.java +++ b/test/jdk/tools/jpackage/share/ServiceTest.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 @@ -49,7 +49,9 @@ * @build jdk.jpackage.test.* * @modules jdk.jpackage/jdk.jpackage.internal * @compile ServiceTest.java - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=360 -Xmx512m + * --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED + * jdk.jpackage.test.Main * --jpt-run=ServiceTest */ public class ServiceTest { From 673f767dadc8f3a784b9c31c406422846df3279b Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 28 May 2024 22:43:35 +0000 Subject: [PATCH 82/99] 8285506: Unify os::vsnprintf implementations Reviewed-by: jwaters, kbarrett, jsjolen --- src/hotspot/os/posix/os_posix.cpp | 11 ----------- src/hotspot/os/windows/os_windows.cpp | 11 ----------- src/hotspot/share/runtime/os.cpp | 10 ++++++++++ src/hotspot/share/runtime/os.hpp | 4 ++-- 4 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index a18a633002c..1e7473eea1d 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -425,17 +425,6 @@ char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int file_des return aligned_base; } -int os::vsnprintf(char* buf, size_t len, const char* fmt, va_list args) { - // All supported POSIX platforms provide C99 semantics. - ALLOW_C_FUNCTION(::vsnprintf, int result = ::vsnprintf(buf, len, fmt, args);) - // If an encoding error occurred (result < 0) then it's not clear - // whether the buffer is NUL terminated, so ensure it is. - if ((result < 0) && (len > 0)) { - buf[len - 1] = '\0'; - } - return result; -} - int os::get_fileno(FILE* fp) { return NOT_AIX(::)fileno(fp); } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 20422e83cb7..b95209b3f9b 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1739,17 +1739,6 @@ void os::get_summary_os_info(char* buf, size_t buflen) { if (nl != nullptr) *nl = '\0'; } -int os::vsnprintf(char* buf, size_t len, const char* fmt, va_list args) { - // Starting with Visual Studio 2015, vsnprint is C99 compliant. - ALLOW_C_FUNCTION(::vsnprintf, int result = ::vsnprintf(buf, len, fmt, args);) - // If an encoding error occurred (result < 0) then it's not clear - // whether the buffer is NUL terminated, so ensure it is. - if ((result < 0) && (len > 0)) { - buf[len - 1] = '\0'; - } - return result; -} - static inline time_t get_mtime(const char* filename) { struct stat st; int ret = os::stat(filename, &st); diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 53c438cd208..e7fed633c45 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -111,6 +111,16 @@ int os::snprintf_checked(char* buf, size_t len, const char* fmt, ...) { return result; } +int os::vsnprintf(char* buf, size_t len, const char* fmt, va_list args) { + ALLOW_C_FUNCTION(::vsnprintf, int result = ::vsnprintf(buf, len, fmt, args);) + // If an encoding error occurred (result < 0) then it's not clear + // whether the buffer is NUL terminated, so ensure it is. + if ((result < 0) && (len > 0)) { + buf[len - 1] = '\0'; + } + return result; +} + // Fill in buffer with current local time as an ISO-8601 string. // E.g., YYYY-MM-DDThh:mm:ss.mmm+zzzz. // Returns buffer, or null if it failed. diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 971c3c884c4..a6626c1389f 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -771,8 +771,8 @@ class os: AllStatic { static void *find_agent_function(JvmtiAgent *agent_lib, bool check_lib, const char *syms[], size_t syms_len); - // Provide C99 compliant versions of these functions, since some versions - // of some platforms don't. + // Provide wrapper versions of these functions to guarantee NUL-termination + // in all cases. static int vsnprintf(char* buf, size_t len, const char* fmt, va_list args) ATTRIBUTE_PRINTF(3, 0); static int snprintf(char* buf, size_t len, const char* fmt, ...) ATTRIBUTE_PRINTF(3, 4); From 01060ad4ab18581aa46bc16e64c7f12a591a682b Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Wed, 29 May 2024 02:18:20 +0000 Subject: [PATCH 83/99] 8325083: jdk/incubator/vector/Double512VectorTests.java crashes in Assembler::vex_prefix_and_encode Reviewed-by: kvn, sviswanathan --- src/hotspot/cpu/x86/x86.ad | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 8c9bbfc3592..af134065692 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -7235,11 +7235,10 @@ instruct vxor_mem(vec dst, vec src, memory mem) %{ // --------------------------------- VectorCast -------------------------------------- instruct vcastBtoX(vec dst, vec src) %{ + predicate(VM_Version::supports_avx512vl() || Matcher::vector_element_basic_type(n) != T_DOUBLE); match(Set dst (VectorCastB2X src)); format %{ "vector_cast_b2x $dst,$src\t!" %} ins_encode %{ - assert(UseAVX > 0, "required"); - BasicType to_elem_bt = Matcher::vector_element_basic_type(this); int vlen_enc = vector_length_encoding(this); __ vconvert_b2x(to_elem_bt, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); @@ -7247,6 +7246,17 @@ instruct vcastBtoX(vec dst, vec src) %{ ins_pipe( pipe_slow ); %} +instruct vcastBtoD(legVec dst, legVec src) %{ + predicate(!VM_Version::supports_avx512vl() && Matcher::vector_element_basic_type(n) == T_DOUBLE); + match(Set dst (VectorCastB2X src)); + format %{ "vector_cast_b2x $dst,$src\t!" %} + ins_encode %{ + int vlen_enc = vector_length_encoding(this); + __ vconvert_b2x(T_DOUBLE, $dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} + instruct castStoX(vec dst, vec src) %{ predicate((UseAVX <= 2 || !VM_Version::supports_avx512vlbw()) && Matcher::vector_length(n->in(1)) <= 8 && // src From 9a83dfee14f4cd9cda476d11a027294a810953cb Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 29 May 2024 05:09:39 +0000 Subject: [PATCH 84/99] 8332431: NullPointerException in JTable of SwingSet2 Reviewed-by: abhiscxk, kizune --- .../classes/javax/swing/ToolTipManager.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/ToolTipManager.java b/src/java.desktop/share/classes/javax/swing/ToolTipManager.java index 6b3619e8a7b..84d62e67c54 100644 --- a/src/java.desktop/share/classes/javax/swing/ToolTipManager.java +++ b/src/java.desktop/share/classes/javax/swing/ToolTipManager.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 @@ -265,13 +265,19 @@ void showTipWindow() { toFind = new Point(screenLocation.x + preferredLocation.x, screenLocation.y + preferredLocation.y); } else { - toFind = mouseEvent.getLocationOnScreen(); + if (mouseEvent != null) { + toFind = mouseEvent.getLocationOnScreen(); + } else { + toFind = screenLocation; + } } GraphicsConfiguration gc = getDrawingGC(toFind); if (gc == null) { - toFind = mouseEvent.getLocationOnScreen(); - gc = getDrawingGC(toFind); + if (mouseEvent != null) { + toFind = mouseEvent.getLocationOnScreen(); + gc = getDrawingGC(toFind); + } if (gc == null) { gc = insideComponent.getGraphicsConfiguration(); } @@ -301,8 +307,12 @@ void showTipWindow() { location.x -= size.width; } } else { - location = new Point(screenLocation.x + mouseEvent.getX(), - screenLocation.y + mouseEvent.getY() + 20); + if (mouseEvent != null) { + location = new Point(screenLocation.x + mouseEvent.getX(), + screenLocation.y + mouseEvent.getY() + 20); + } else { + location = screenLocation; + } if (!leftToRight) { if(location.x - size.width>=0) { location.x -= size.width; From b8ae11e99b99866888ad090c98c96e6d0c33a3c9 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 29 May 2024 06:41:53 +0000 Subject: [PATCH 85/99] 8332960: ubsan: classListParser.hpp:159:12: runtime error: load of value 2101478704, which is not a valid value for type 'ParseMode' Reviewed-by: dholmes, mdoerr --- src/hotspot/share/cds/classListParser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/cds/classListParser.cpp b/src/hotspot/share/cds/classListParser.cpp index 79119a997de..4455dd7db1b 100644 --- a/src/hotspot/share/cds/classListParser.cpp +++ b/src/hotspot/share/cds/classListParser.cpp @@ -59,7 +59,8 @@ ClassListParser::ClassListParser(const char* file, ParseMode parse_mode) : _classlist_file(file), _id2klass_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE), _file_input(do_open(file), /* need_close=*/true), - _input_stream(&_file_input) { + _input_stream(&_file_input), + _parse_mode(parse_mode) { log_info(cds)("Parsing %s%s", file, parse_lambda_forms_invokers_only() ? " (lambda form invokers only)" : ""); if (!_file_input.is_open()) { @@ -70,7 +71,6 @@ ClassListParser::ClassListParser(const char* file, ParseMode parse_mode) : _token = _line = nullptr; _interfaces = new (mtClass) GrowableArray(10, mtClass); _indy_items = new (mtClass) GrowableArray(9, mtClass); - _parse_mode = parse_mode; // _instance should only be accessed by the thread that created _instance. assert(_instance == nullptr, "must be singleton"); From 2cca83bc82eb6b090ae96b8c072b986b93d9244a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 29 May 2024 07:55:01 +0000 Subject: [PATCH 86/99] 8332880: JFR GCHelper class recognizes "Archive" regions as valid Reviewed-by: ayang, iwalulya --- test/lib/jdk/test/lib/jfr/GCHelper.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/lib/jdk/test/lib/jfr/GCHelper.java b/test/lib/jdk/test/lib/jfr/GCHelper.java index dc004096f0c..6d1c424e092 100644 --- a/test/lib/jdk/test/lib/jfr/GCHelper.java +++ b/test/lib/jdk/test/lib/jfr/GCHelper.java @@ -195,8 +195,7 @@ public static List removeFirstAndLastGC(List event "Survivor", "Starts Humongous", "Continues Humongous", - "Old", - "Archive" + "Old" }; g1HeapRegionTypes = Collections.unmodifiableList(Arrays.asList(g1HeapRegionTypeLiterals)); From 3d4eb159e6d597f37081faf21b7e3f0f1af299e5 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Wed, 29 May 2024 08:46:27 +0000 Subject: [PATCH 87/99] 8302744: Refactor Hotspot container detection code Reviewed-by: jsjolen, stuefe --- .../os/linux/cgroupSubsystem_linux.cpp | 149 +++++- .../os/linux/cgroupSubsystem_linux.hpp | 216 +++----- .../os/linux/cgroupV1Subsystem_linux.cpp | 166 ++++--- .../os/linux/cgroupV1Subsystem_linux.hpp | 2 - .../os/linux/cgroupV2Subsystem_linux.cpp | 153 +++--- .../os/linux/cgroupV2Subsystem_linux.hpp | 8 +- .../os/linux/test_cgroupSubsystem_linux.cpp | 204 -------- .../runtime/test_cgroupSubsystem_linux.cpp | 464 ++++++++++++++++++ .../gtest/runtime/test_os_linux_cgroups.cpp | 86 ---- .../docker/TestMemoryAwareness.java | 4 +- 10 files changed, 862 insertions(+), 590 deletions(-) delete mode 100644 test/hotspot/gtest/os/linux/test_cgroupSubsystem_linux.cpp create mode 100644 test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp delete mode 100644 test/hotspot/gtest/runtime/test_os_linux_cgroups.cpp diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 9053e8eac30..be9ff1440c0 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -556,21 +556,162 @@ jlong CgroupSubsystem::memory_limit_in_bytes() { return mem_limit; } -jlong CgroupSubsystem::limit_from_str(char* limit_str) { +bool CgroupController::read_string(const char* filename, char* buf, size_t buf_size) { + assert(buf != nullptr, "buffer must not be null"); + assert(filename != nullptr, "filename must be given"); + char* s_path = subsystem_path(); + if (s_path == nullptr) { + log_debug(os, container)("read_string: subsystem path is null"); + return false; + } + + stringStream file_path; + file_path.print_raw(s_path); + file_path.print_raw(filename); + + if (file_path.size() > MAXPATHLEN) { + log_debug(os, container)("File path too long %s, %s", file_path.base(), filename); + return false; + } + const char* absolute_path = file_path.freeze(); + log_trace(os, container)("Path to %s is %s", filename, absolute_path); + + FILE* fp = os::fopen(absolute_path, "r"); + if (fp == nullptr) { + log_debug(os, container)("Open of file %s failed, %s", absolute_path, os::strerror(errno)); + return false; + } + + // Read a single line into the provided buffer. + // At most buf_size - 1 characters. + char* line = fgets(buf, buf_size, fp); + fclose(fp); + if (line == nullptr) { + log_debug(os, container)("Empty file %s", absolute_path); + return false; + } + size_t len = strlen(line); + assert(len <= buf_size - 1, "At most buf_size - 1 bytes can be read"); + if (line[len - 1] == '\n') { + line[len - 1] = '\0'; // trim trailing new line + } + return true; +} + +bool CgroupController::read_number(const char* filename, julong* result) { + char buf[1024]; + bool is_ok = read_string(filename, buf, 1024); + if (!is_ok) { + return false; + } + int matched = sscanf(buf, JULONG_FORMAT, result); + if (matched == 1) { + return true; + } + return false; +} + +bool CgroupController::read_number_handle_max(const char* filename, jlong* result) { + char buf[1024]; + bool is_ok = read_string(filename, buf, 1024); + if (!is_ok) { + return false; + } + jlong val = limit_from_str(buf); + if (val == OSCONTAINER_ERROR) { + return false; + } + *result = val; + return true; +} + +bool CgroupController::read_numerical_key_value(const char* filename, const char* key, julong* result) { + assert(key != nullptr, "key must be given"); + assert(result != nullptr, "result pointer must not be null"); + assert(filename != nullptr, "file to search in must be given"); + char* s_path = subsystem_path(); + if (s_path == nullptr) { + log_debug(os, container)("read_numerical_key_value: subsystem path is null"); + return false; + } + + stringStream file_path; + file_path.print_raw(s_path); + file_path.print_raw(filename); + + if (file_path.size() > MAXPATHLEN) { + log_debug(os, container)("File path too long %s, %s", file_path.base(), filename); + return false; + } + const char* absolute_path = file_path.freeze(); + log_trace(os, container)("Path to %s is %s", filename, absolute_path); + FILE* fp = os::fopen(absolute_path, "r"); + if (fp == nullptr) { + log_debug(os, container)("Open of file %s failed, %s", absolute_path, os::strerror(errno)); + return false; + } + + const int buf_len = MAXPATHLEN+1; + char buf[buf_len]; + char* line = fgets(buf, buf_len, fp); + bool found_match = false; + // File consists of multiple lines in a "key value" + // fashion, we have to find the key. + const size_t key_len = strlen(key); + for (; line != nullptr; line = fgets(buf, buf_len, fp)) { + char after_key = line[key_len]; + if (strncmp(line, key, key_len) == 0 + && isspace(after_key) != 0 + && after_key != '\n') { + // Skip key, skip space + const char* value_substr = line + key_len + 1; + int matched = sscanf(value_substr, JULONG_FORMAT, result); + found_match = matched == 1; + if (found_match) { + break; + } + } + } + fclose(fp); + if (found_match) { + return true; + } + log_debug(os, container)("Type %s (key == %s) not found in file %s", JULONG_FORMAT, + key, absolute_path); + return false; +} + +bool CgroupController::read_numerical_tuple_value(const char* filename, bool use_first, jlong* result) { + char buf[1024]; + bool is_ok = read_string(filename, buf, 1024); + if (!is_ok) { + return false; + } + char token[1024]; + const int matched = sscanf(buf, (use_first ? "%1023s %*s" : "%*s %1023s"), token); + if (matched != 1) { + return false; + } + jlong val = limit_from_str(token); + if (val == OSCONTAINER_ERROR) { + return false; + } + *result = val; + return true; +} + +jlong CgroupController::limit_from_str(char* limit_str) { if (limit_str == nullptr) { return OSCONTAINER_ERROR; } // Unlimited memory in cgroups is the literal string 'max' for // some controllers, for example the pids controller. if (strcmp("max", limit_str) == 0) { - os::free(limit_str); return (jlong)-1; } julong limit; if (sscanf(limit_str, JULONG_FORMAT, &limit) != 1) { - os::free(limit_str); return OSCONTAINER_ERROR; } - os::free(limit_str); return (jlong)limit; } diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp index 7943d2fe9de..6c17ff4508d 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp @@ -69,148 +69,91 @@ #define MEMORY_IDX 3 #define PIDS_IDX 4 -typedef char * cptr; - -class CgroupController: public CHeapObj { - public: - virtual char *subsystem_path() = 0; -}; - -PRAGMA_DIAG_PUSH -PRAGMA_FORMAT_NONLITERAL_IGNORED -// Parses a subsystem's file, looking for a matching line. -// If key is null, then the first line will be matched with scan_fmt. -// If key isn't null, then each line will be matched, looking for something that matches "$key $scan_fmt". -// The matching value will be assigned to returnval. -// scan_fmt uses scanf() syntax. -// Return value: 0 on match, OSCONTAINER_ERROR on error. -template int subsystem_file_line_contents(CgroupController* c, - const char *filename, - const char *key, - const char *scan_fmt, - T returnval) { - if (c == nullptr) { - log_debug(os, container)("subsystem_file_line_contents: CgroupController* is null"); - return OSCONTAINER_ERROR; - } - if (c->subsystem_path() == nullptr) { - log_debug(os, container)("subsystem_file_line_contents: subsystem path is null"); - return OSCONTAINER_ERROR; - } - - stringStream file_path; - file_path.print_raw(c->subsystem_path()); - file_path.print_raw(filename); - - if (file_path.size() > (MAXPATHLEN-1)) { - log_debug(os, container)("File path too long %s, %s", file_path.base(), filename); - return OSCONTAINER_ERROR; - } - const char* absolute_path = file_path.freeze(); - log_trace(os, container)("Path to %s is %s", filename, absolute_path); - - FILE* fp = os::fopen(absolute_path, "r"); - if (fp == nullptr) { - log_debug(os, container)("Open of file %s failed, %s", absolute_path, os::strerror(errno)); - return OSCONTAINER_ERROR; - } - - const int buf_len = MAXPATHLEN+1; - char buf[buf_len]; - char* line = fgets(buf, buf_len, fp); - if (line == nullptr) { - log_debug(os, container)("Empty file %s", absolute_path); - fclose(fp); - return OSCONTAINER_ERROR; - } - - bool found_match = false; - if (key == nullptr) { - // File consists of a single line according to caller, with only a value - int matched = sscanf(line, scan_fmt, returnval); - found_match = matched == 1; - } else { - // File consists of multiple lines in a "key value" - // fashion, we have to find the key. - const int key_len = (int)strlen(key); - for (; line != nullptr; line = fgets(buf, buf_len, fp)) { - char* key_substr = strstr(line, key); - char after_key = line[key_len]; - if (key_substr == line - && isspace(after_key) != 0 - && after_key != '\n') { - // Skip key, skip space - const char* value_substr = line + key_len + 1; - int matched = sscanf(value_substr, scan_fmt, returnval); - found_match = matched == 1; - if (found_match) { - break; - } - } - } - } - fclose(fp); - if (found_match) { - return 0; - } - log_debug(os, container)("Type %s (key == %s) not found in file %s", scan_fmt, - (key == nullptr ? "null" : key), absolute_path); - return OSCONTAINER_ERROR; -} -PRAGMA_DIAG_POP - -// log_fmt can be different than scan_fmt. For example -// cpu_period() for cgv2 uses log_fmt='%d' and scan_fmt='%*s %d' -#define GET_CONTAINER_INFO(return_type, subsystem, filename, \ - logstring, log_fmt, scan_fmt, variable) \ - return_type variable; \ -{ \ - int err; \ - err = subsystem_file_line_contents(subsystem, \ - filename, \ - nullptr, \ - scan_fmt, \ - &variable); \ - if (err != 0) { \ - log_trace(os, container)(logstring "%d", OSCONTAINER_ERROR); \ - return (return_type) OSCONTAINER_ERROR; \ - } \ - \ - log_trace(os, container)(logstring log_fmt, variable); \ +#define CONTAINER_READ_NUMBER_CHECKED(controller, filename, log_string, retval) \ +{ \ + bool is_ok; \ + is_ok = controller->read_number(filename, &retval); \ + if (!is_ok) { \ + log_trace(os, container)(log_string " failed: %d", OSCONTAINER_ERROR); \ + return OSCONTAINER_ERROR; \ + } \ + log_trace(os, container)(log_string " is: " JULONG_FORMAT, retval); \ } -#define GET_CONTAINER_INFO_CPTR(return_type, subsystem, filename, \ - logstring, scan_fmt, variable, bufsize) \ - char variable[bufsize]; \ -{ \ - int err; \ - err = subsystem_file_line_contents(subsystem, \ - filename, \ - nullptr, \ - scan_fmt, \ - variable); \ - if (err != 0) \ - return (return_type) nullptr; \ - \ - log_trace(os, container)(logstring, variable); \ +#define CONTAINER_READ_NUMBER_CHECKED_MAX(controller, filename, log_string, retval) \ +{ \ + bool is_ok; \ + is_ok = controller->read_number_handle_max(filename, &retval); \ + if (!is_ok) { \ + log_trace(os, container)(log_string " failed: %d", OSCONTAINER_ERROR); \ + return OSCONTAINER_ERROR; \ + } \ + log_trace(os, container)(log_string " is: " JLONG_FORMAT, retval); \ } -#define GET_CONTAINER_INFO_LINE(return_type, controller, filename, \ - matchline, logstring, scan_fmt, variable) \ - return_type variable; \ -{ \ - int err; \ - err = subsystem_file_line_contents(controller, \ - filename, \ - matchline, \ - scan_fmt, \ - &variable); \ - if (err != 0) \ - return (return_type) OSCONTAINER_ERROR; \ - \ - log_trace(os, container)(logstring, variable); \ +#define CONTAINER_READ_STRING_CHECKED(controller, filename, log_string, retval, buf_size) \ +{ \ + bool is_ok; \ + is_ok = controller->read_string(filename, retval, buf_size); \ + if (!is_ok) { \ + log_trace(os, container)(log_string " failed: %d", OSCONTAINER_ERROR); \ + return nullptr; \ + } \ + log_trace(os, container)(log_string " is: %s", retval); \ } +class CgroupController: public CHeapObj { + public: + virtual char* subsystem_path() = 0; + + /* Read a numerical value as unsigned long + * + * returns: false if any error occurred. true otherwise and + * the parsed value is set in the provided julong pointer. + */ + bool read_number(const char* filename, julong* result); + + /* Convenience method to deal with numbers as well as the string 'max' + * in interface files. Otherwise same as read_number(). + * + * returns: false if any error occurred. true otherwise and + * the parsed value (which might be negative) is being set in + * the provided jlong pointer. + */ + bool read_number_handle_max(const char* filename, jlong* result); + + /* Read a string of at most buf_size - 1 characters from the interface file. + * The provided buffer must be at least buf_size in size so as to account + * for the null terminating character. Callers must ensure that the buffer + * is appropriately in-scope and of sufficient size. + * + * returns: false if any error occured. true otherwise and the passed + * in buffer will contain the first buf_size - 1 characters of the string + * or up to the first new line character ('\n') whichever comes first. + */ + bool read_string(const char* filename, char* buf, size_t buf_size); + + /* Read a tuple value as a number. Tuple is: ' '. + * Handles 'max' (for unlimited) for any tuple value. This is handy for + * parsing interface files like cpu.max which contain such tuples. + * + * returns: false if any error occurred. true otherwise and the parsed + * value of the appropriate tuple entry set in the provided jlong pointer. + */ + bool read_numerical_tuple_value(const char* filename, bool use_first, jlong* result); + + /* Read a numerical value from a multi-line interface file. The matched line is + * determined by the provided 'key'. The associated numerical value is being set + * via the passed in julong pointer. Example interface file 'memory.stat' + * + * returns: false if any error occurred. true otherwise and the parsed value is + * being set in the provided julong pointer. + */ + bool read_numerical_key_value(const char* filename, const char* key, julong* result); + + private: + static jlong limit_from_str(char* limit_str); +}; class CachedMetric : public CHeapObj{ private: @@ -255,7 +198,6 @@ class CgroupSubsystem: public CHeapObj { public: jlong memory_limit_in_bytes(); int active_processor_count(); - jlong limit_from_str(char* limit_str); virtual int cpu_quota() = 0; virtual int cpu_period() = 0; diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index b83da9099f8..72adaa23b81 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -75,9 +75,9 @@ void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { * OSCONTAINER_ERROR for not supported */ jlong CgroupV1MemoryController::uses_mem_hierarchy() { - GET_CONTAINER_INFO(jlong, this, "/memory.use_hierarchy", - "Use Hierarchy is: ", JLONG_FORMAT, JLONG_FORMAT, use_hierarchy); - return use_hierarchy; + julong use_hierarchy; + CONTAINER_READ_NUMBER_CHECKED(this, "/memory.use_hierarchy", "Use Hierarchy", use_hierarchy); + return (jlong)use_hierarchy; } void CgroupV1MemoryController::set_subsystem_path(char *cgroup_path) { @@ -89,15 +89,20 @@ void CgroupV1MemoryController::set_subsystem_path(char *cgroup_path) { } jlong CgroupV1Subsystem::read_memory_limit_in_bytes() { - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.limit_in_bytes", - "Memory Limit is: ", JULONG_FORMAT, JULONG_FORMAT, memlimit); - + julong memlimit; + CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.limit_in_bytes", "Memory Limit", memlimit); if (memlimit >= os::Linux::physical_memory()) { log_trace(os, container)("Non-Hierarchical Memory Limit is: Unlimited"); CgroupV1MemoryController* mem_controller = reinterpret_cast(_memory->controller()); if (mem_controller->is_hierarchical()) { - GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", "hierarchical_memory_limit", - "Hierarchical Memory Limit is: " JULONG_FORMAT, JULONG_FORMAT, hier_memlimit) + julong hier_memlimit; + bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", + "hierarchical_memory_limit", + &hier_memlimit); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + log_trace(os, container)("Hierarchical Memory Limit is: " JULONG_FORMAT, hier_memlimit); if (hier_memlimit >= os::Linux::physical_memory()) { log_trace(os, container)("Hierarchical Memory Limit is: Unlimited"); } else { @@ -125,16 +130,22 @@ jlong CgroupV1Subsystem::read_memory_limit_in_bytes() { */ jlong CgroupV1Subsystem::read_mem_swap() { julong host_total_memsw; - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.memsw.limit_in_bytes", - "Memory and Swap Limit is: ", JULONG_FORMAT, JULONG_FORMAT, memswlimit); + julong hier_memswlimit; + julong memswlimit; + CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.memsw.limit_in_bytes", "Memory and Swap Limit", memswlimit); host_total_memsw = os::Linux::host_swap() + os::Linux::physical_memory(); if (memswlimit >= host_total_memsw) { log_trace(os, container)("Non-Hierarchical Memory and Swap Limit is: Unlimited"); CgroupV1MemoryController* mem_controller = reinterpret_cast(_memory->controller()); if (mem_controller->is_hierarchical()) { const char* matchline = "hierarchical_memsw_limit"; - GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", matchline, - "Hierarchical Memory and Swap Limit is : " JULONG_FORMAT, JULONG_FORMAT, hier_memswlimit) + bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", + matchline, + &hier_memswlimit); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + log_trace(os, container)("Hierarchical Memory and Swap Limit is: " JULONG_FORMAT, hier_memswlimit); if (hier_memswlimit >= host_total_memsw) { log_trace(os, container)("Hierarchical Memory and Swap Limit is: Unlimited"); } else { @@ -168,29 +179,34 @@ jlong CgroupV1Subsystem::memory_and_swap_limit_in_bytes() { return memory_swap; } +static inline +jlong memory_swap_usage_impl(CgroupController* ctrl) { + julong memory_swap_usage; + CONTAINER_READ_NUMBER_CHECKED(ctrl, "/memory.memsw.usage_in_bytes", "mem swap usage", memory_swap_usage); + return (jlong)memory_swap_usage; +} + jlong CgroupV1Subsystem::memory_and_swap_usage_in_bytes() { jlong memory_sw_limit = memory_and_swap_limit_in_bytes(); jlong memory_limit = CgroupSubsystem::memory_limit_in_bytes(); if (memory_sw_limit > 0 && memory_limit > 0) { jlong delta_swap = memory_sw_limit - memory_limit; if (delta_swap > 0) { - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.memsw.usage_in_bytes", - "mem swap usage is: ", JULONG_FORMAT, JULONG_FORMAT, memory_swap_usage); - return (jlong)memory_swap_usage; + return memory_swap_usage_impl(_memory->controller()); } } return memory_usage_in_bytes(); } jlong CgroupV1Subsystem::read_mem_swappiness() { - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.swappiness", - "Swappiness is: ", JULONG_FORMAT, JULONG_FORMAT, swappiness); - return swappiness; + julong swappiness; + CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.swappiness", "Swappiness", swappiness); + return (jlong)swappiness; } jlong CgroupV1Subsystem::memory_soft_limit_in_bytes() { - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.soft_limit_in_bytes", - "Memory Soft Limit is: ", JULONG_FORMAT, JULONG_FORMAT, memsoftlimit); + julong memsoftlimit; + CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.soft_limit_in_bytes", "Memory Soft Limit", memsoftlimit); if (memsoftlimit >= os::Linux::physical_memory()) { log_trace(os, container)("Memory Soft Limit is: Unlimited"); return (jlong)-1; @@ -209,9 +225,9 @@ jlong CgroupV1Subsystem::memory_soft_limit_in_bytes() { * OSCONTAINER_ERROR for not supported */ jlong CgroupV1Subsystem::memory_usage_in_bytes() { - GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.usage_in_bytes", - "Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, memusage); - return memusage; + julong memusage; + CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.usage_in_bytes", "Memory Usage", memusage); + return (jlong)memusage; } /* memory_max_usage_in_bytes @@ -223,32 +239,44 @@ jlong CgroupV1Subsystem::memory_usage_in_bytes() { * OSCONTAINER_ERROR for not supported */ jlong CgroupV1Subsystem::memory_max_usage_in_bytes() { - GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.max_usage_in_bytes", - "Maximum Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, memmaxusage); - return memmaxusage; + julong memmaxusage; + CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.max_usage_in_bytes", "Maximum Memory Usage", memmaxusage); + return (jlong)memmaxusage; } jlong CgroupV1Subsystem::rss_usage_in_bytes() { - GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", - "rss", JULONG_FORMAT, JULONG_FORMAT, rss); - return rss; + julong rss; + bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", + "rss", + &rss); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + log_trace(os, container)("RSS usage is: " JULONG_FORMAT, rss); + return (jlong)rss; } jlong CgroupV1Subsystem::cache_usage_in_bytes() { - GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", - "cache", JULONG_FORMAT, JULONG_FORMAT, cache); + julong cache; + bool is_ok = _memory->controller()->read_numerical_key_value("/memory.stat", + "cache", + &cache); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + log_trace(os, container)("Cache usage is: " JULONG_FORMAT, cache); return cache; } jlong CgroupV1Subsystem::kernel_memory_usage_in_bytes() { - GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.kmem.usage_in_bytes", - "Kernel Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, kmem_usage); - return kmem_usage; + julong kmem_usage; + CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.kmem.usage_in_bytes", "Kernel Memory Usage", kmem_usage); + return (jlong)kmem_usage; } jlong CgroupV1Subsystem::kernel_memory_limit_in_bytes() { - GET_CONTAINER_INFO(julong, _memory->controller(), "/memory.kmem.limit_in_bytes", - "Kernel Memory Limit is: ", JULONG_FORMAT, JULONG_FORMAT, kmem_limit); + julong kmem_limit; + CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.kmem.limit_in_bytes", "Kernel Memory Limit", kmem_limit); if (kmem_limit >= os::Linux::physical_memory()) { return (jlong)-1; } @@ -256,9 +284,9 @@ jlong CgroupV1Subsystem::kernel_memory_limit_in_bytes() { } jlong CgroupV1Subsystem::kernel_memory_max_usage_in_bytes() { - GET_CONTAINER_INFO(jlong, _memory->controller(), "/memory.kmem.max_usage_in_bytes", - "Maximum Kernel Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, kmem_max_usage); - return kmem_max_usage; + julong kmem_max_usage; + CONTAINER_READ_NUMBER_CHECKED(_memory->controller(), "/memory.kmem.max_usage_in_bytes", "Maximum Kernel Memory Usage", kmem_max_usage); + return (jlong)kmem_max_usage; } void CgroupV1Subsystem::print_version_specific_info(outputStream* st) { @@ -271,15 +299,15 @@ void CgroupV1Subsystem::print_version_specific_info(outputStream* st) { OSContainer::print_container_helper(st, kmem_max_usage, "kernel_memory_limit_in_bytes"); } -char * CgroupV1Subsystem::cpu_cpuset_cpus() { - GET_CONTAINER_INFO_CPTR(cptr, _cpuset, "/cpuset.cpus", - "cpuset.cpus is: %s", "%1023s", cpus, 1024); +char* CgroupV1Subsystem::cpu_cpuset_cpus() { + char cpus[1024]; + CONTAINER_READ_STRING_CHECKED(_cpuset, "/cpuset.cpus", "cpuset.cpus", cpus, 1024); return os::strdup(cpus); } -char * CgroupV1Subsystem::cpu_cpuset_memory_nodes() { - GET_CONTAINER_INFO_CPTR(cptr, _cpuset, "/cpuset.mems", - "cpuset.mems is: %s", "%1023s", mems, 1024); +char* CgroupV1Subsystem::cpu_cpuset_memory_nodes() { + char mems[1024]; + CONTAINER_READ_STRING_CHECKED(_cpuset, "/cpuset.mems", "cpuset.mems", mems, 1024); return os::strdup(mems); } @@ -294,15 +322,24 @@ char * CgroupV1Subsystem::cpu_cpuset_memory_nodes() { * OSCONTAINER_ERROR for not supported */ int CgroupV1Subsystem::cpu_quota() { - GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.cfs_quota_us", - "CPU Quota is: ", "%d", "%d", quota); - return quota; + julong quota; + bool is_ok = _cpu->controller()-> + read_number("/cpu.cfs_quota_us", "a); + if (!is_ok) { + log_trace(os, container)("CPU Quota failed: %d", OSCONTAINER_ERROR); + return OSCONTAINER_ERROR; + } + // cast to int since the read value might be negative + // and we want to avoid logging -1 as a large unsigned value. + int quota_int = (int)quota; + log_trace(os, container)("CPU Quota is: %d", quota_int); + return quota_int; } int CgroupV1Subsystem::cpu_period() { - GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.cfs_period_us", - "CPU Period is: ", "%d", "%d", period); - return period; + julong period; + CONTAINER_READ_NUMBER_CHECKED(_cpu->controller(), "/cpu.cfs_period_us", "CPU Period", period); + return (int)period; } /* cpu_shares @@ -316,19 +353,13 @@ int CgroupV1Subsystem::cpu_period() { * OSCONTAINER_ERROR for not supported */ int CgroupV1Subsystem::cpu_shares() { - GET_CONTAINER_INFO(int, _cpu->controller(), "/cpu.shares", - "CPU Shares is: ", "%d", "%d", shares); + julong shares; + CONTAINER_READ_NUMBER_CHECKED(_cpu->controller(), "/cpu.shares", "CPU Shares", shares); + int shares_int = (int)shares; // Convert 1024 to no shares setup - if (shares == 1024) return -1; - - return shares; -} - + if (shares_int == 1024) return -1; -char* CgroupV1Subsystem::pids_max_val() { - GET_CONTAINER_INFO_CPTR(cptr, _pids, "/pids.max", - "Maximum number of tasks is: %s", "%1023s", pidsmax, 1024); - return os::strdup(pidsmax); + return shares_int; } /* pids_max @@ -342,8 +373,9 @@ char* CgroupV1Subsystem::pids_max_val() { */ jlong CgroupV1Subsystem::pids_max() { if (_pids == nullptr) return OSCONTAINER_ERROR; - char * pidsmax_str = pids_max_val(); - return limit_from_str(pidsmax_str); + jlong pids_max; + CONTAINER_READ_NUMBER_CHECKED_MAX(_pids, "/pids.max", "Maximum number of tasks", pids_max); + return pids_max; } /* pids_current @@ -356,7 +388,7 @@ jlong CgroupV1Subsystem::pids_max() { */ jlong CgroupV1Subsystem::pids_current() { if (_pids == nullptr) return OSCONTAINER_ERROR; - GET_CONTAINER_INFO(jlong, _pids, "/pids.current", - "Current number of tasks is: ", JLONG_FORMAT, JLONG_FORMAT, pids_current); - return pids_current; + julong pids_current; + CONTAINER_READ_NUMBER_CHECKED(_pids, "/pids.current", "Current number of tasks", pids_current); + return (jlong)pids_current; } diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp index 3205973961a..254b17de0ba 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp @@ -114,8 +114,6 @@ class CgroupV1Subsystem: public CgroupSubsystem { CgroupV1Controller* _cpuacct = nullptr; CgroupV1Controller* _pids = nullptr; - char * pids_max_val(); - jlong read_mem_swappiness(); jlong read_mem_swap(); diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index d7c6464caa0..1ba7c1e69d5 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -35,10 +35,11 @@ * OSCONTAINER_ERROR for not supported */ int CgroupV2Subsystem::cpu_shares() { - GET_CONTAINER_INFO(int, _unified, "/cpu.weight", - "Raw value for CPU Shares is: ", "%d", "%d", shares); + julong shares; + CONTAINER_READ_NUMBER_CHECKED(_unified, "/cpu.weight", "Raw value for CPU Shares", shares); + int shares_int = (int)shares; // Convert default value of 100 to no shares setup - if (shares == 100) { + if (shares_int == 100) { log_debug(os, container)("CPU Shares is: %d", -1); return -1; } @@ -50,7 +51,7 @@ int CgroupV2Subsystem::cpu_shares() { // Use the inverse of (x == OCI value, y == cgroupsv2 value): // ((262142 * y - 1)/9999) + 2 = x // - int x = 262142 * shares - 1; + int x = 262142 * shares_int - 1; double frac = x/9999.0; x = ((int)frac) + 2; log_trace(os, container)("Scaled CPU shares value is: %d", x); @@ -83,33 +84,37 @@ int CgroupV2Subsystem::cpu_shares() { * OSCONTAINER_ERROR for not supported */ int CgroupV2Subsystem::cpu_quota() { - char * cpu_quota_str = cpu_quota_val(); - int limit = (int)limit_from_str(cpu_quota_str); + jlong quota_val; + bool is_ok = _unified->read_numerical_tuple_value("/cpu.max", true /* use_first */, "a_val); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + int limit = (int)quota_val; log_trace(os, container)("CPU Quota is: %d", limit); return limit; } -char * CgroupV2Subsystem::cpu_cpuset_cpus() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpuset.cpus", - "cpuset.cpus is: %s", "%1023s", cpus, 1024); +char* CgroupV2Subsystem::cpu_cpuset_cpus() { + char cpus[1024]; + CONTAINER_READ_STRING_CHECKED(_unified, "/cpuset.cpus", "cpuset.cpus", cpus, 1024); return os::strdup(cpus); } -char* CgroupV2Subsystem::cpu_quota_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpu.max", - "Raw value for CPU quota is: %s", "%1023s %*d", quota, 1024); - return os::strdup(quota); -} - -char * CgroupV2Subsystem::cpu_cpuset_memory_nodes() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/cpuset.mems", - "cpuset.mems is: %s", "%1023s", mems, 1024); +char* CgroupV2Subsystem::cpu_cpuset_memory_nodes() { + char mems[1024]; + CONTAINER_READ_STRING_CHECKED(_unified, "/cpuset.mems", "cpuset.mems", mems, 1024); return os::strdup(mems); } int CgroupV2Subsystem::cpu_period() { - GET_CONTAINER_INFO(int, _unified, "/cpu.max", - "CPU Period is: ", "%d", "%*s %d", period); + jlong period_val; + bool is_ok = _unified->read_numerical_tuple_value("/cpu.max", false /* use_first */, &period_val); + if (!is_ok) { + log_trace(os, container)("CPU Period failed: %d", OSCONTAINER_ERROR); + return OSCONTAINER_ERROR; + } + int period = (int)period_val; + log_trace(os, container)("CPU Period is: %d", period); return period; } @@ -123,14 +128,15 @@ int CgroupV2Subsystem::cpu_period() { * OSCONTAINER_ERROR for not supported */ jlong CgroupV2Subsystem::memory_usage_in_bytes() { - GET_CONTAINER_INFO(jlong, _unified, "/memory.current", - "Memory Usage is: ", JLONG_FORMAT, JLONG_FORMAT, memusage); - return memusage; + julong memusage; + CONTAINER_READ_NUMBER_CHECKED(_unified, "/memory.current", "Memory Usage", memusage); + return (jlong)memusage; } jlong CgroupV2Subsystem::memory_soft_limit_in_bytes() { - char* mem_soft_limit_str = mem_soft_limit_val(); - return limit_from_str(mem_soft_limit_str); + jlong mem_soft_limit; + CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/memory.low", "Memory Soft Limit", mem_soft_limit); + return mem_soft_limit; } jlong CgroupV2Subsystem::memory_max_usage_in_bytes() { @@ -140,21 +146,25 @@ jlong CgroupV2Subsystem::memory_max_usage_in_bytes() { } jlong CgroupV2Subsystem::rss_usage_in_bytes() { - GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", - "anon", JULONG_FORMAT, JULONG_FORMAT, rss); - return rss; + julong rss; + bool is_ok = _memory->controller()-> + read_numerical_key_value("/memory.stat", "anon", &rss); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + log_trace(os, container)("RSS usage is: " JULONG_FORMAT, rss); + return (jlong)rss; } jlong CgroupV2Subsystem::cache_usage_in_bytes() { - GET_CONTAINER_INFO_LINE(julong, _memory->controller(), "/memory.stat", - "file", JULONG_FORMAT, JULONG_FORMAT, cache); - return cache; -} - -char* CgroupV2Subsystem::mem_soft_limit_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.low", - "Memory Soft Limit is: %s", "%1023s", mem_soft_limit_str, 1024); - return os::strdup(mem_soft_limit_str); + julong cache; + bool is_ok = _memory->controller()-> + read_numerical_key_value("/memory.stat", "file", &cache); + if (!is_ok) { + return OSCONTAINER_ERROR; + } + log_trace(os, container)("Cache usage is: " JULONG_FORMAT, cache); + return (jlong)cache; } // Note that for cgroups v2 the actual limits set for swap and @@ -163,14 +173,15 @@ char* CgroupV2Subsystem::mem_soft_limit_val() { // compound value we need to sum the two values. Setting a swap limit // without also setting a memory limit is not allowed. jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() { - char* mem_swp_limit_str = mem_swp_limit_val(); - if (mem_swp_limit_str == nullptr) { + jlong swap_limit; + bool is_ok = _memory->controller()->read_number_handle_max("/memory.swap.max", &swap_limit); + if (!is_ok) { // Some container tests rely on this trace logging to happen. - log_trace(os, container)("Memory and Swap Limit is: %d", OSCONTAINER_ERROR); + log_trace(os, container)("Swap Limit failed: %d", OSCONTAINER_ERROR); // swap disabled at kernel level, treat it as no swap return read_memory_limit_in_bytes(); } - jlong swap_limit = limit_from_str(mem_swp_limit_str); + log_trace(os, container)("Swap Limit is: " JLONG_FORMAT, swap_limit); if (swap_limit >= 0) { jlong memory_limit = read_memory_limit_in_bytes(); assert(memory_limit >= 0, "swap limit without memory limit?"); @@ -183,24 +194,23 @@ jlong CgroupV2Subsystem::memory_and_swap_limit_in_bytes() { jlong CgroupV2Subsystem::memory_and_swap_usage_in_bytes() { jlong memory_usage = memory_usage_in_bytes(); if (memory_usage >= 0) { - char* mem_swp_current_str = mem_swp_current_val(); - jlong swap_current = limit_from_str(mem_swp_current_str); + jlong swap_current = mem_swp_current_val(); return memory_usage + (swap_current >= 0 ? swap_current : 0); } return memory_usage; // not supported or unlimited case } -char* CgroupV2Subsystem::mem_swp_limit_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.swap.max", - "Memory and Swap Limit is: %s", "%1023s", mem_swp_limit_str, 1024); - return os::strdup(mem_swp_limit_str); +jlong CgroupV2Subsystem::mem_swp_limit_val() { + jlong swap_limit; + CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/memory.swap.max", "Swap Limit", swap_limit); + return swap_limit; } // memory.swap.current : total amount of swap currently used by the cgroup and its descendants -char* CgroupV2Subsystem::mem_swp_current_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.swap.current", - "Swap currently used is: %s", "%1023s", mem_swp_current_str, 1024); - return os::strdup(mem_swp_current_str); +jlong CgroupV2Subsystem::mem_swp_current_val() { + julong swap_current; + CONTAINER_READ_NUMBER_CHECKED(_unified, "/memory.swap.current", "Swap currently used", swap_current); + return (jlong)swap_current; } /* memory_limit_in_bytes @@ -212,30 +222,14 @@ char* CgroupV2Subsystem::mem_swp_current_val() { * -1 for unlimited, OSCONTAINER_ERROR for an error */ jlong CgroupV2Subsystem::read_memory_limit_in_bytes() { - char * mem_limit_str = mem_limit_val(); - jlong limit = limit_from_str(mem_limit_str); - if (log_is_enabled(Trace, os, container)) { - if (limit == -1) { - log_trace(os, container)("Memory Limit is: Unlimited"); - } else { - log_trace(os, container)("Memory Limit is: " JLONG_FORMAT, limit); - } - } - return limit; -} - -char* CgroupV2Subsystem::mem_limit_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/memory.max", - "Raw value for memory limit is: %s", "%1023s", mem_limit_str, 1024); - return os::strdup(mem_limit_str); + jlong memory_limit; + CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/memory.max", "Memory Limit", memory_limit); + return memory_limit; } void CgroupV2Subsystem::print_version_specific_info(outputStream* st) { - char* mem_swp_current_str = mem_swp_current_val(); - jlong swap_current = limit_from_str(mem_swp_current_str); - - char* mem_swp_limit_str = mem_swp_limit_val(); - jlong swap_limit = limit_from_str(mem_swp_limit_str); + jlong swap_current = mem_swp_current_val(); + jlong swap_limit = mem_swp_limit_val(); OSContainer::print_container_helper(st, swap_current, "memory_swap_current_in_bytes"); OSContainer::print_container_helper(st, swap_limit, "memory_swap_max_limit_in_bytes"); @@ -250,12 +244,6 @@ char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) { return os::strdup(ss.base()); } -char* CgroupV2Subsystem::pids_max_val() { - GET_CONTAINER_INFO_CPTR(cptr, _unified, "/pids.max", - "Maximum number of tasks is: %s", "%1023s", pidsmax, 1024); - return os::strdup(pidsmax); -} - /* pids_max * * Return the maximum number of tasks available to the process @@ -266,8 +254,9 @@ char* CgroupV2Subsystem::pids_max_val() { * OSCONTAINER_ERROR for not supported */ jlong CgroupV2Subsystem::pids_max() { - char * pidsmax_str = pids_max_val(); - return limit_from_str(pidsmax_str); + jlong pids_max; + CONTAINER_READ_NUMBER_CHECKED_MAX(_unified, "/pids.max", "Maximum number of tasks", pids_max); + return pids_max; } /* pids_current @@ -279,7 +268,7 @@ jlong CgroupV2Subsystem::pids_max() { * OSCONTAINER_ERROR for not supported */ jlong CgroupV2Subsystem::pids_current() { - GET_CONTAINER_INFO(jlong, _unified, "/pids.current", - "Current number of tasks is: ", JLONG_FORMAT, JLONG_FORMAT, pids_current); + julong pids_current; + CONTAINER_READ_NUMBER_CHECKED(_unified, "/pids.current", "Current number of tasks", pids_current); return pids_current; } diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp index 978c193c602..a004c8f75b9 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp @@ -56,12 +56,8 @@ class CgroupV2Subsystem: public CgroupSubsystem { CachingCgroupController* _memory = nullptr; CachingCgroupController* _cpu = nullptr; - char *mem_limit_val(); - char *mem_swp_limit_val(); - char *mem_swp_current_val(); - char *mem_soft_limit_val(); - char *cpu_quota_val(); - char *pids_max_val(); + jlong mem_swp_limit_val(); + jlong mem_swp_current_val(); public: CgroupV2Subsystem(CgroupController * unified) { diff --git a/test/hotspot/gtest/os/linux/test_cgroupSubsystem_linux.cpp b/test/hotspot/gtest/os/linux/test_cgroupSubsystem_linux.cpp deleted file mode 100644 index 463955fd401..00000000000 --- a/test/hotspot/gtest/os/linux/test_cgroupSubsystem_linux.cpp +++ /dev/null @@ -1,204 +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. - */ - -#include "precompiled.hpp" - -#ifdef LINUX - -#include "runtime/os.hpp" -#include "cgroupSubsystem_linux.hpp" -#include "unittest.hpp" -#include "utilities/globalDefinitions.hpp" - -#include - - -// Utilities -static bool file_exists(const char* filename) { - struct stat st; - return os::stat(filename, &st) == 0; -} - -static char* temp_file(const char* prefix) { - const testing::TestInfo* test_info = ::testing::UnitTest::GetInstance()->current_test_info(); - stringStream path; - path.print_raw(os::get_temp_directory()); - path.print_raw(os::file_separator()); - path.print("%s-test-jdk.pid%d.%s.%s", prefix, os::current_process_id(), - test_info->test_case_name(), test_info->name()); - return path.as_string(true); -} - -static void delete_file(const char* filename) { - if (!file_exists(filename)) { - return; - } - int ret = remove(filename); - EXPECT_TRUE(ret == 0 || errno == ENOENT) << "failed to remove file '" << filename << "': " - << os::strerror(errno) << " (" << errno << ")"; -} - -class TestController : public CgroupController { -public: - char* subsystem_path() override { - // The real subsystem is in /tmp/, generated by temp_file() - return (char*)"/"; - }; -}; - -static void fill_file(const char* path, const char* content) { - delete_file(path); - FILE* fp = os::fopen(path, "w"); - if (fp == nullptr) { - return; - } - if (content != nullptr) { - fprintf(fp, "%s", content); - } - fclose(fp); -} - -TEST(cgroupTest, SubSystemFileLineContentsMultipleLinesErrorCases) { - TestController my_controller{}; - const char* test_file = temp_file("cgroups"); - int x = 0; - char s[1024]; - int err = 0; - - s[0] = '\0'; - fill_file(test_file, "foo "); - err = subsystem_file_line_contents(&my_controller, test_file, "foo", "%s", &s); - EXPECT_NE(err, 0) << "Value must not be missing in key/value case"; - - s[0] = '\0'; - fill_file(test_file, "faulty_start foo bar"); - err = subsystem_file_line_contents(&my_controller, test_file, "foo", "%s", &s); - EXPECT_NE(err, 0) << "Key must be at start"; - - s[0] = '\0'; - fill_file(test_file, "foof bar"); - err = subsystem_file_line_contents(&my_controller, test_file, "foo", "%s", &s); - EXPECT_NE(err, 0) << "Key must be exact match"; - - // Cleanup - delete_file(test_file); -} - -TEST(cgroupTest, SubSystemFileLineContentsMultipleLinesSuccessCases) { - TestController my_controller{}; - const char* test_file = temp_file("cgroups"); - int x = 0; - char s[1024]; - int err = 0; - - s[0] = '\0'; - fill_file(test_file, "foo bar"); - err = subsystem_file_line_contents(&my_controller, test_file, "foo", "%s", &s); - EXPECT_EQ(err, 0); - EXPECT_STREQ(s, "bar") << "Incorrect!"; - - s[0] = '\0'; - fill_file(test_file, "foo\tbar"); - err = subsystem_file_line_contents(&my_controller, test_file, "foo", "%s", &s); - EXPECT_EQ(err, 0); - EXPECT_STREQ(s, "bar") << "Incorrect!"; - - s[0] = '\0'; - fill_file(test_file, "foof bar\nfoo car"); - err = subsystem_file_line_contents(&my_controller, test_file, "foo", "%s", &s); - EXPECT_EQ(err, 0); - EXPECT_STREQ(s, "car"); - - s[0] = '\0'; - fill_file(test_file, "foo\ttest\nfoot car"); - err = subsystem_file_line_contents(&my_controller, test_file, "foo", "%s", &s); - EXPECT_EQ(err, 0); - EXPECT_STREQ(s, "test"); - - s[0] = '\0'; - fill_file(test_file, "foo 1\nfoo car"); - err = subsystem_file_line_contents(&my_controller, test_file, "foo", "%s", &s); - EXPECT_EQ(err, 0); - EXPECT_STREQ(s, "1"); - - s[0] = '\0'; - fill_file(test_file, "max 10000"); - err = subsystem_file_line_contents(&my_controller, test_file, nullptr, "%s %*d", &s); - EXPECT_EQ(err, 0); - EXPECT_STREQ(s, "max"); - - x = -3; - fill_file(test_file, "max 10001"); - err = subsystem_file_line_contents(&my_controller, test_file, nullptr, "%*s %d", &x); - EXPECT_EQ(err, 0); - EXPECT_EQ(x, 10001); - - // Cleanup - delete_file(test_file); -} - -TEST(cgroupTest, SubSystemFileLineContentsSingleLine) { - TestController my_controller{}; - const char* test_file = temp_file("cgroups"); - int x = 0; - char s[1024]; - int err = 0; - - fill_file(test_file, "foo"); - err = subsystem_file_line_contents(&my_controller, test_file, nullptr, "%s", &s); - EXPECT_EQ(err, 0); - EXPECT_STREQ(s, "foo"); - - fill_file(test_file, "1337"); - err = subsystem_file_line_contents(&my_controller, test_file, nullptr, "%d", &x); - EXPECT_EQ(err, 0); - EXPECT_EQ(x, 1337) << "Wrong value for x"; - - s[0] = '\0'; - fill_file(test_file, "1337"); - err = subsystem_file_line_contents(&my_controller, test_file, nullptr, "%s", &s); - EXPECT_EQ(err, 0); - EXPECT_STREQ(s, "1337"); - - x = -1; - fill_file(test_file, nullptr); - err = subsystem_file_line_contents(&my_controller, test_file, nullptr, "%d", &x); - EXPECT_NE(err, 0) << "Empty file should've failed"; - EXPECT_EQ(x, -1) << "x was altered"; - - jlong y; - fill_file(test_file, "1337"); - err = subsystem_file_line_contents(&my_controller, test_file, nullptr, JLONG_FORMAT, &y); - EXPECT_EQ(err, 0); - EXPECT_EQ(y, 1337) << "Wrong value for y"; - julong z; - fill_file(test_file, "1337"); - err = subsystem_file_line_contents(&my_controller, test_file, nullptr, JULONG_FORMAT, &z); - EXPECT_EQ(err, 0); - EXPECT_EQ(z, (julong)1337) << "Wrong value for z"; - - // Cleanup - delete_file(test_file); -} - -#endif // LINUX diff --git a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp new file mode 100644 index 00000000000..cc326dbb502 --- /dev/null +++ b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp @@ -0,0 +1,464 @@ +/* + * 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. + */ + +#include "precompiled.hpp" + +#ifdef LINUX + +#include "runtime/os.hpp" +#include "cgroupSubsystem_linux.hpp" +#include "cgroupV1Subsystem_linux.hpp" +#include "cgroupV2Subsystem_linux.hpp" +#include "unittest.hpp" +#include "utilities/globalDefinitions.hpp" + +#include + +typedef struct { + const char* mount_path; + const char* root_path; + const char* cgroup_path; + const char* expected_path; +} TestCase; + +// Utilities +static bool file_exists(const char* filename) { + struct stat st; + return os::stat(filename, &st) == 0; +} + +static char* temp_file(const char* prefix) { + const testing::TestInfo* test_info = ::testing::UnitTest::GetInstance()->current_test_info(); + stringStream path; + path.print_raw(os::get_temp_directory()); + path.print_raw(os::file_separator()); + path.print("%s-test-jdk.pid%d.%s.%s", prefix, os::current_process_id(), + test_info->test_case_name(), test_info->name()); + return path.as_string(true); +} + +static void delete_file(const char* filename) { + if (!file_exists(filename)) { + return; + } + int ret = remove(filename); + EXPECT_TRUE(ret == 0 || errno == ENOENT) << "failed to remove file '" << filename << "': " + << os::strerror(errno) << " (" << errno << ")"; +} + +class TestController : public CgroupController { +private: + char* _path; +public: + TestController(char* p): _path(p) {} + char* subsystem_path() override { + return _path; + }; +}; + +static void fill_file(const char* path, const char* content) { + delete_file(path); + FILE* fp = os::fopen(path, "w"); + if (fp == nullptr) { + return; + } + if (content != nullptr) { + fprintf(fp, "%s", content); + } + fclose(fp); +} + +TEST(cgroupTest, read_numerical_key_value_failure_cases) { + const char* test_file = temp_file("cgroups"); + const char* b = basename(test_file); + EXPECT_TRUE(b != nullptr) << "basename was null"; + stringStream path; + path.print_raw(os::file_separator()); + path.print_raw(b); + const char* base_with_slash = path.as_string(true); + + TestController* controller = new TestController((char*)os::get_temp_directory()); + constexpr julong bad = 0xBAD; + julong x = bad; + + fill_file(test_file, "foo "); + bool is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_FALSE(is_ok) << "Value is missing in key/value case, expecting false"; + EXPECT_EQ(bad, x) << "x must be unchanged"; + + x = bad; + fill_file(test_file, "faulty_start foo 101"); + is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_FALSE(is_ok) << "key must be at the start"; + EXPECT_EQ(bad, x) << "x must be unchanged"; + + x = bad; + fill_file(test_file, nullptr); + is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_FALSE(is_ok) << "key not in empty file"; + EXPECT_EQ(bad, x) << "x must be unchanged"; + + x = bad; + fill_file(test_file, "foo\n"); + is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_FALSE(is_ok) << "key must have a value"; + EXPECT_EQ(bad, x) << "x must be unchanged"; + + x = bad; + fill_file(test_file, "foof 1002"); + is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_FALSE(is_ok) << "key must be exact match"; + EXPECT_EQ(bad, x) << "x must be unchanged"; + + // Cleanup + delete_file(test_file); +} + +TEST(cgroupTest, read_numerical_key_value_success_cases) { + const char* test_file = temp_file("cgroups"); + const char* b = basename(test_file); + EXPECT_TRUE(b != nullptr) << "basename was null"; + stringStream path; + path.print_raw(os::file_separator()); + path.print_raw(b); + const char* base_with_slash = path.as_string(true); + + TestController* controller = new TestController((char*)os::get_temp_directory()); + constexpr julong bad = 0xBAD; + julong x = bad; + + fill_file(test_file, "foo 100"); + bool is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_TRUE(is_ok); + EXPECT_EQ((julong)100, x); + + x = bad; + fill_file(test_file, "foo\t111"); + is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_TRUE(is_ok); + EXPECT_EQ((julong)111, x); + + x = bad; + fill_file(test_file, "foo\nbar 333\nfoo\t111"); + is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_TRUE(is_ok); + EXPECT_EQ((julong)111, x); + + x = bad; + fill_file(test_file, "foof 100\nfoo 133"); + is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_TRUE(is_ok); + EXPECT_EQ((julong)133, x); + + x = bad; + fill_file(test_file, "foo\t333\nfoot 999"); + is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_TRUE(is_ok); + EXPECT_EQ((julong)333, x); + + x = bad; + fill_file(test_file, "foo 1\nfoo car"); + is_ok = controller->read_numerical_key_value(base_with_slash, "foo", &x); + EXPECT_TRUE(is_ok); + EXPECT_EQ((julong)1, x); + + // Cleanup + delete_file(test_file); +} + +TEST(cgroupTest, read_number_null) { + TestController* null_path_controller = new TestController((char*)nullptr); + const char* test_file_path = "/not-used"; + constexpr julong bad = 0xBAD; + julong a = bad; + // null subsystem_path() case + bool is_ok = null_path_controller->read_number(test_file_path, &a); + EXPECT_FALSE(is_ok) << "Null subsystem path should be an error"; + EXPECT_EQ(bad, a) << "Expected untouched scan value"; +} + +TEST(cgroupTest, read_string_beyond_max_path) { + char larger_than_max[MAXPATHLEN + 1]; + for (int i = 0; i < (MAXPATHLEN); i++) { + larger_than_max[i] = 'A' + (i % 26); + } + larger_than_max[MAXPATHLEN] = '\0'; + TestController* too_large_path_controller = new TestController(larger_than_max); + const char* test_file_path = "/file-not-found"; + char foo[1024]; + foo[0] = '\0'; + bool is_ok = too_large_path_controller->read_string(test_file_path, foo, 1024); + EXPECT_FALSE(is_ok) << "Too long path should be an error"; + EXPECT_STREQ("", foo) << "Expected untouched scan value"; +} + +TEST(cgroupTest, read_number_file_not_exist) { + TestController* unknown_path_ctrl = new TestController((char*)"/do/not/exist"); + const char* test_file_path = "/file-not-found"; + constexpr julong bad = 0xBAD; + julong result = bad; + bool is_ok = unknown_path_ctrl->read_number(test_file_path, &result); + EXPECT_FALSE(is_ok) << "File not found should be an error"; + EXPECT_EQ(bad, result) << "Expected untouched scan value"; +} + +TEST(cgroupTest, read_numerical_key_value_null) { + TestController* null_path_controller = new TestController((char*)nullptr); + const char* test_file_path = "/not-used"; + const char* key = "something"; + constexpr julong bad = 0xBAD; + julong a = bad; + // null subsystem_path() case + bool is_ok = null_path_controller->read_numerical_key_value(test_file_path, key, &a); + EXPECT_FALSE(is_ok) << "Null subsystem path should be an error"; + EXPECT_EQ(bad, a) << "Expected untouched scan value"; +} + +TEST(cgroupTest, read_number_tests) { + const char* test_file = temp_file("cgroups"); + const char* b = basename(test_file); + constexpr julong bad = 0xBAD; + EXPECT_TRUE(b != nullptr) << "basename was null"; + stringStream path; + path.print_raw(os::file_separator()); + path.print_raw(b); + const char* base_with_slash = path.as_string(true); + fill_file(test_file, "8888"); + + TestController* controller = new TestController((char*)os::get_temp_directory()); + julong foo = bad; + bool ok = controller->read_number(base_with_slash, &foo); + EXPECT_TRUE(ok) << "Number parsing should have been successful"; + EXPECT_EQ((julong)8888, foo) << "Wrong value for 'foo' (NOTE: 0xBAD == " << 0xBAD << ")"; + + // Some interface files might have negative values, ensure we can read + // them and manually cast them as needed. + fill_file(test_file, "-1"); + foo = bad; + ok = controller->read_number(base_with_slash, &foo); + EXPECT_TRUE(ok) << "Number parsing should have been successful"; + EXPECT_EQ((jlong)-1, (jlong)foo) << "Wrong value for 'foo' (NOTE: 0xBAD == " << 0xBAD << ")"; + + foo = bad; + fill_file(test_file, nullptr); + ok = controller->read_number(base_with_slash, &foo); + EXPECT_FALSE(ok) << "Empty file should have failed"; + EXPECT_EQ(bad, foo) << "foo was altered"; + + // Some interface files have numbers as well as the string + // 'max', which means unlimited. + jlong result = -10; + fill_file(test_file, "max\n"); + ok = controller->read_number_handle_max(base_with_slash, &result); + EXPECT_TRUE(ok) << "Number parsing for 'max' string should have been successful"; + EXPECT_EQ((jlong)-1, result) << "'max' means unlimited (-1)"; + + result = -10; + fill_file(test_file, "11114\n"); + ok = controller->read_number_handle_max(base_with_slash, &result); + EXPECT_TRUE(ok) << "Number parsing for should have been successful"; + EXPECT_EQ((jlong)11114, result) << "Incorrect result"; + + result = -10; + fill_file(test_file, "-51114\n"); + ok = controller->read_number_handle_max(base_with_slash, &result); + EXPECT_TRUE(ok) << "Number parsing for should have been successful"; + EXPECT_EQ((jlong)-51114, result) << "Incorrect result"; + + delete_file(test_file); +} + +TEST(cgroupTest, read_string_tests) { + const char* test_file = temp_file("cgroups"); + const char* b = basename(test_file); + EXPECT_TRUE(b != nullptr) << "basename was null"; + stringStream path; + path.print_raw(os::file_separator()); + path.print_raw(b); + const char* base_with_slash = path.as_string(true); + fill_file(test_file, "foo-bar"); + + TestController* controller = new TestController((char*)os::get_temp_directory()); + char result[1024]; + bool ok = controller->read_string(base_with_slash, result, 1024); + EXPECT_TRUE(ok) << "String parsing should have been successful"; + EXPECT_STREQ("foo-bar", result); + + result[0] = '\0'; + fill_file(test_file, "1234"); + ok = controller->read_string(base_with_slash, result, 1024); + EXPECT_TRUE(ok) << "String parsing should have been successful"; + EXPECT_STREQ("1234", result); + + // values with a space + result[0] = '\0'; + fill_file(test_file, "abc def"); + ok = controller->read_string(base_with_slash, result, 1024); + EXPECT_TRUE(ok) << "String parsing should have been successful"; + EXPECT_STREQ("abc def", result); + + result[0] = '\0'; + fill_file(test_file, " \na"); + ok = controller->read_string(base_with_slash, result, 1024); + EXPECT_TRUE(ok) << "String parsing should have been successful"; + EXPECT_STREQ(" ", result); + + // only the first line are being returned + result[0] = '\0'; + fill_file(test_file, "test\nabc"); + ok = controller->read_string(base_with_slash, result, 1024); + EXPECT_TRUE(ok) << "String parsing should have been successful"; + EXPECT_STREQ("test", result); + + result[0] = '\0'; + fill_file(test_file, nullptr); + ok = controller->read_string(base_with_slash, result, 1024); + EXPECT_FALSE(ok) << "Empty file should have failed"; + EXPECT_STREQ("", result) << "Expected untouched result"; + delete_file(test_file); + + // File contents larger than 1K + // We only read in the first 1K - 1 bytes + const size_t large_len = 2 * 1024; + char too_large[large_len]; + for (size_t i = 0; i < large_len; i++) { + too_large[i] = 'A' + (i % 26); + } + too_large[large_len - 1] = '\0'; + result[0] = '\0'; + fill_file(test_file, too_large); + ok = controller->read_string(base_with_slash, result, 1024); + EXPECT_TRUE(ok) << "String parsing should have been successful"; + EXPECT_TRUE(1023 == strlen(result)) << "Expected only the first 1023 chars to be read in"; + EXPECT_EQ(0, strncmp(too_large, result, 1023)); + EXPECT_EQ(result[1023], '\0') << "The last character must be the null character"; +} + +TEST(cgroupTest, read_number_tuple_test) { + const char* test_file = temp_file("cgroups"); + const char* b = basename(test_file); + EXPECT_TRUE(b != nullptr) << "basename was null"; + stringStream path; + path.print_raw(os::file_separator()); + path.print_raw(b); + const char* base_with_slash = path.as_string(true); + fill_file(test_file, "max 10000"); + + TestController* controller = new TestController((char*)os::get_temp_directory()); + jlong result = -10; + bool ok = controller->read_numerical_tuple_value(base_with_slash, true /* use_first */, &result); + EXPECT_TRUE(ok) << "Should be OK to read value"; + EXPECT_EQ((jlong)-1, result) << "max should be unlimited (-1)"; + + result = -10; + ok = controller->read_numerical_tuple_value(base_with_slash, false /* use_first */, &result); + EXPECT_TRUE(ok) << "Should be OK to read the value"; + EXPECT_EQ((jlong)10000, result); + + // non-max strings + fill_file(test_file, "abc 10000"); + result = -10; + ok = controller->read_numerical_tuple_value(base_with_slash, true /* use_first */, &result); + EXPECT_FALSE(ok) << "abc should not be parsable"; + EXPECT_EQ((jlong)-10, result) << "result value should be unchanged"; + + fill_file(test_file, nullptr); + result = -10; + ok = controller->read_numerical_tuple_value(base_with_slash, true /* use_first */, &result); + EXPECT_FALSE(ok) << "Empty file should be an error"; + EXPECT_EQ((jlong)-10, result) << "result value should be unchanged"; +} + +TEST(cgroupTest, read_numerical_key_beyond_max_path) { + char larger_than_max[MAXPATHLEN + 1]; + for (int i = 0; i < (MAXPATHLEN); i++) { + larger_than_max[i] = 'A' + (i % 26); + } + larger_than_max[MAXPATHLEN] = '\0'; + TestController* too_large_path_controller = new TestController(larger_than_max); + const char* test_file_path = "/file-not-found"; + const char* key = "something"; + julong a = 0xBAD; + bool is_ok = too_large_path_controller->read_numerical_key_value(test_file_path, key, &a); + EXPECT_FALSE(is_ok) << "Too long path should be an error"; + EXPECT_EQ((julong)0xBAD, a) << "Expected untouched scan value"; +} + +TEST(cgroupTest, read_numerical_key_file_not_exist) { + TestController* unknown_path_ctrl = new TestController((char*)"/do/not/exist"); + const char* test_file_path = "/file-not-found"; + const char* key = "something"; + julong a = 0xBAD; + bool is_ok = unknown_path_ctrl->read_numerical_key_value(test_file_path, key, &a); + EXPECT_FALSE(is_ok) << "File not found should be an error"; + EXPECT_EQ((julong)0xBAD, a) << "Expected untouched scan value"; +} + +TEST(cgroupTest, set_cgroupv1_subsystem_path) { + TestCase host = { + "/sys/fs/cgroup/memory", // mount_path + "/", // root_path + "/user.slice/user-1000.slice/user@1000.service", // cgroup_path + "/sys/fs/cgroup/memory/user.slice/user-1000.slice/user@1000.service" // expected_path + }; + TestCase container_engine = { + "/sys/fs/cgroup/mem", // mount_path + "/user.slice/user-1000.slice/user@1000.service", // root_path + "/user.slice/user-1000.slice/user@1000.service", // cgroup_path + "/sys/fs/cgroup/mem" // expected_path + }; + int length = 2; + TestCase* testCases[] = { &host, + &container_engine }; + for (int i = 0; i < length; i++) { + CgroupV1Controller* ctrl = new CgroupV1Controller( (char*)testCases[i]->root_path, + (char*)testCases[i]->mount_path); + ctrl->set_subsystem_path((char*)testCases[i]->cgroup_path); + ASSERT_STREQ(testCases[i]->expected_path, ctrl->subsystem_path()); + } +} + +TEST(cgroupTest, set_cgroupv2_subsystem_path) { + TestCase at_mount_root = { + "/sys/fs/cgroup", // mount_path + nullptr, // root_path, ignored + "/", // cgroup_path + "/sys/fs/cgroup" // expected_path + }; + TestCase sub_path = { + "/sys/fs/cgroup", // mount_path + nullptr, // root_path, ignored + "/foobar", // cgroup_path + "/sys/fs/cgroup/foobar" // expected_path + }; + int length = 2; + TestCase* testCases[] = { &at_mount_root, + &sub_path }; + for (int i = 0; i < length; i++) { + CgroupV2Controller* ctrl = new CgroupV2Controller( (char*)testCases[i]->mount_path, + (char*)testCases[i]->cgroup_path); + ASSERT_STREQ(testCases[i]->expected_path, ctrl->subsystem_path()); + } +} + +#endif // LINUX diff --git a/test/hotspot/gtest/runtime/test_os_linux_cgroups.cpp b/test/hotspot/gtest/runtime/test_os_linux_cgroups.cpp deleted file mode 100644 index 21e0152a43d..00000000000 --- a/test/hotspot/gtest/runtime/test_os_linux_cgroups.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2022, Red Hat, Inc. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "precompiled.hpp" - -#ifdef LINUX - -#include "cgroupV1Subsystem_linux.hpp" -#include "cgroupV2Subsystem_linux.hpp" -#include "unittest.hpp" - -typedef struct { - const char* mount_path; - const char* root_path; - const char* cgroup_path; - const char* expected_path; -} TestCase; - -TEST(cgroupTest, set_cgroupv1_subsystem_path) { - TestCase host = { - "/sys/fs/cgroup/memory", // mount_path - "/", // root_path - "/user.slice/user-1000.slice/user@1000.service", // cgroup_path - "/sys/fs/cgroup/memory/user.slice/user-1000.slice/user@1000.service" // expected_path - }; - TestCase container_engine = { - "/sys/fs/cgroup/mem", // mount_path - "/user.slice/user-1000.slice/user@1000.service", // root_path - "/user.slice/user-1000.slice/user@1000.service", // cgroup_path - "/sys/fs/cgroup/mem" // expected_path - }; - int length = 2; - TestCase* testCases[] = { &host, - &container_engine }; - for (int i = 0; i < length; i++) { - CgroupV1Controller* ctrl = new CgroupV1Controller( (char*)testCases[i]->root_path, - (char*)testCases[i]->mount_path); - ctrl->set_subsystem_path((char*)testCases[i]->cgroup_path); - ASSERT_STREQ(testCases[i]->expected_path, ctrl->subsystem_path()); - } -} - -TEST(cgroupTest, set_cgroupv2_subsystem_path) { - TestCase at_mount_root = { - "/sys/fs/cgroup", // mount_path - nullptr, // root_path, ignored - "/", // cgroup_path - "/sys/fs/cgroup" // expected_path - }; - TestCase sub_path = { - "/sys/fs/cgroup", // mount_path - nullptr, // root_path, ignored - "/foobar", // cgroup_path - "/sys/fs/cgroup/foobar" // expected_path - }; - int length = 2; - TestCase* testCases[] = { &at_mount_root, - &sub_path }; - for (int i = 0; i < length; i++) { - CgroupV2Controller* ctrl = new CgroupV2Controller( (char*)testCases[i]->mount_path, - (char*)testCases[i]->cgroup_path); - ASSERT_STREQ(testCases[i]->expected_path, ctrl->subsystem_path()); - } -} - -#endif diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java index 553ba692ee7..20354cf934d 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryAwareness.java @@ -200,8 +200,8 @@ private static void testMemorySwapLimitSanity() throws Exception { .shouldMatch("Memory Limit is:.*" + expectedTraceValue) // Either for cgroup v1: a_1) same as memory limit, or b_1) -2 on systems with swapaccount=0 // Either for cgroup v2: a_2) 0, or b_2) -2 on systems with swapaccount=0 - .shouldMatch("Memory and Swap Limit is:.*(" + expectedTraceValue + "|-2|0)") - .shouldNotMatch("Memory and Swap Limit is:.*" + neg2InUnsignedLong); + .shouldMatch("(Memory and )?Swap Limit is:.*(" + expectedTraceValue + "|-2|0)") + .shouldNotMatch("(Memory and )?Swap Limit is:.*" + neg2InUnsignedLong); } From 9b64ece514cf941ebc727991d97c43453d8a488d Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 29 May 2024 09:11:04 +0000 Subject: [PATCH 88/99] 8332904: ubsan ppc64le: c1_LIRGenerator_ppc.cpp:581:21: runtime error: signed integer overflow: 9223372036854775807 + 1 cannot be represented in type 'long int' Reviewed-by: mdoerr, jkern --- src/hotspot/cpu/ppc/assembler_ppc.cpp | 8 ++++---- src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/cpu/ppc/assembler_ppc.cpp b/src/hotspot/cpu/ppc/assembler_ppc.cpp index 018b66310e2..26fc1aacad3 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2023 SAP SE. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -78,9 +78,9 @@ int Assembler::branch_destination(int inst, int pos) { // Low-level andi-one-instruction-macro. void Assembler::andi(Register a, Register s, const long ui16) { - if (is_power_of_2(((jlong) ui16)+1)) { + if (is_power_of_2(((unsigned long) ui16)+1)) { // pow2minus1 - clrldi(a, s, 64 - log2i_exact((((jlong) ui16)+1))); + clrldi(a, s, 64 - log2i_exact((((unsigned long) ui16)+1))); } else if (is_power_of_2((jlong) ui16)) { // pow2 rlwinm(a, s, 0, 31 - log2i_exact((jlong) ui16), 31 - log2i_exact((jlong) ui16)); diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index b58defc1847..2caca1dc556 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -578,7 +578,7 @@ inline bool can_handle_logic_op_as_uimm(ValueType *type, Bytecodes::Code bc) { is_power_of_2(int_or_long_const) || is_power_of_2(-int_or_long_const))) return true; if (bc == Bytecodes::_land && - (is_power_of_2(int_or_long_const+1) || + (is_power_of_2((unsigned long)int_or_long_const+1) || (Assembler::is_uimm(int_or_long_const, 32) && is_power_of_2(int_or_long_const)) || (int_or_long_const != min_jlong && is_power_of_2(-int_or_long_const)))) return true; From 6d718ae51aeb7143ebfa561501b87fe1ba48039a Mon Sep 17 00:00:00 2001 From: Cesar Soares Lucas Date: Wed, 29 May 2024 09:36:13 +0000 Subject: [PATCH 89/99] 8324341: Remove redundant preprocessor #if's checks Reviewed-by: kvn, ayang --- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 2 -- src/hotspot/share/c1/c1_LIR.cpp | 2 -- src/hotspot/share/classfile/modules.cpp | 2 -- src/hotspot/share/code/nmethod.cpp | 2 -- src/hotspot/share/opto/idealGraphPrinter.cpp | 2 -- src/hotspot/share/runtime/deoptimization.cpp | 6 ------ 6 files changed, 16 deletions(-) diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index d0eb103d81b..50f957aef99 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -5631,7 +5631,6 @@ void C2_MacroAssembler::vector_mask_compress(KRegister dst, KRegister src, Regis kmov(dst, rtmp2); } -#ifdef _LP64 void C2_MacroAssembler::vector_compress_expand_avx2(int opcode, XMMRegister dst, XMMRegister src, XMMRegister mask, Register rtmp, Register rscratch, XMMRegister permv, XMMRegister xtmp, BasicType bt, @@ -5665,7 +5664,6 @@ void C2_MacroAssembler::vector_compress_expand_avx2(int opcode, XMMRegister dst, // compressing/expanding the source vector lanes. vblendvps(dst, dst, xtmp, permv, vec_enc, false, permv); } -#endif void C2_MacroAssembler::vector_compress_expand(int opcode, XMMRegister dst, XMMRegister src, KRegister mask, bool merge, BasicType bt, int vec_enc) { diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp index bbf802aca13..a9975010a56 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -196,14 +196,12 @@ void LIR_Op2::verify() const { if (two_operand_lir_form) { -#ifdef ASSERT bool threeOperandForm = false; #ifdef S390 // There are 3 operand shifts on S390 (see LIR_Assembler::shift_op()). threeOperandForm = code() == lir_shl || ((code() == lir_shr || code() == lir_ushr) && (result_opr()->is_double_cpu() || in_opr1()->type() == T_OBJECT)); -#endif #endif switch (code()) { diff --git a/src/hotspot/share/classfile/modules.cpp b/src/hotspot/share/classfile/modules.cpp index d4f3cc29962..ddbb84db3be 100644 --- a/src/hotspot/share/classfile/modules.cpp +++ b/src/hotspot/share/classfile/modules.cpp @@ -560,9 +560,7 @@ void Modules::verify_archived_modules() { ModuleEntry::verify_archived_module_entries(); } -#if INCLUDE_CDS_JAVA_HEAP char* Modules::_archived_main_module_name = nullptr; -#endif void Modules::dump_main_module_name() { const char* module_name = Arguments::get_property("jdk.module.main"); diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 8cc36ba1b64..14c8795425c 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -3997,9 +3997,7 @@ void nmethod::print_statistics() { #endif unknown_java_nmethod_stats.print_nmethod_stats("Unknown"); DebugInformationRecorder::print_statistics(); -#ifndef PRODUCT pc_nmethod_stats.print_pc_stats(); -#endif Dependencies::print_statistics(); if (xtty != nullptr) xtty->tail("statistics"); } diff --git a/src/hotspot/share/opto/idealGraphPrinter.cpp b/src/hotspot/share/opto/idealGraphPrinter.cpp index 1f0fec8b58a..8a9da980893 100644 --- a/src/hotspot/share/opto/idealGraphPrinter.cpp +++ b/src/hotspot/share/opto/idealGraphPrinter.cpp @@ -371,7 +371,6 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) { head(PROPERTIES_ELEMENT); Node *node = n; -#ifndef PRODUCT Compile::current()->_in_dump_cnt++; print_prop(NODE_NAME_PROPERTY, (const char *)node->Name()); print_prop("idx", node->_idx); @@ -631,7 +630,6 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) { } Compile::current()->_in_dump_cnt--; -#endif tail(PROPERTIES_ELEMENT); tail(NODE_ELEMENT); diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 53a0f2e9c3b..17487688445 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1239,15 +1239,11 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* InstanceKlass* ik = InstanceKlass::cast(k); if (obj == nullptr && !cache_init_error) { InternalOOMEMark iom(THREAD); -#if COMPILER2_OR_JVMCI if (EnableVectorSupport && VectorSupport::is_vector(ik)) { obj = VectorSupport::allocate_vector(ik, fr, reg_map, sv, THREAD); } else { obj = ik->allocate_instance(THREAD); } -#else - obj = ik->allocate_instance(THREAD); -#endif // COMPILER2_OR_JVMCI } } else if (k->is_typeArray_klass()) { TypeArrayKlass* ak = TypeArrayKlass::cast(k); @@ -1577,7 +1573,6 @@ void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableAr continue; } #endif // INCLUDE_JVMCI -#if COMPILER2_OR_JVMCI if (EnableVectorSupport && VectorSupport::is_vector(k)) { assert(sv->field_size() == 1, "%s not a vector", k->name()->as_C_string()); ScopeValue* payload = sv->field_at(0); @@ -1597,7 +1592,6 @@ void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableAr // Else fall-through to do assignment for scalar-replaced boxed vector representation // which could be restored after vector object allocation. } -#endif /* !COMPILER2_OR_JVMCI */ if (k->is_instance_klass()) { InstanceKlass* ik = InstanceKlass::cast(k); reassign_fields_by_klass(ik, fr, reg_map, sv, 0, obj(), skip_internal); From c003c1207fae07bcfe5a6f642a9c05e6c591e7a6 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Wed, 29 May 2024 11:12:30 +0000 Subject: [PATCH 90/99] 8331865: Consolidate size and alignment checks in LayoutPath Reviewed-by: psandoz, jvernee --- .../java/lang/foreign/MemoryLayout.java | 36 +++---- .../lang/invoke/VarHandleSegmentViewBase.java | 14 +-- .../classes/java/lang/invoke/VarHandles.java | 20 ++-- .../X-VarHandleSegmentView.java.template | 99 +++++++++---------- .../foreign/AbstractMemorySegmentImpl.java | 9 +- .../jdk/internal/foreign/LayoutPath.java | 19 ++-- .../classes/jdk/internal/foreign/Utils.java | 28 +----- .../foreign/layout/AbstractLayout.java | 4 + .../internal/foreign/layout/ValueLayouts.java | 9 +- test/jdk/java/foreign/TestAccessModes.java | 5 +- test/jdk/java/foreign/TestHeapAlignment.java | 4 +- test/jdk/java/foreign/TestLayoutPaths.java | 52 ++++++++++ 12 files changed, 166 insertions(+), 133 deletions(-) diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java index 123c5897f26..372b10aab13 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -625,12 +625,12 @@ public sealed interface MemoryLayout * (this layout), or an {@link IllegalArgumentException} is thrown. Note * that the alignment constraint of the root layout can be more strict * (but not less) than the alignment constraint of the selected value layout.

  • - *
  • The offset of the access operation (computed as above) must fall inside - * the spatial bounds of the accessed memory segment, or an - * {@link IndexOutOfBoundsException} is thrown. This is the case when - * {@code O + A <= S}, where {@code O} is the accessed offset (computed as above), - * {@code A} is the size of the selected layout and {@code S} is the size of the - * accessed memory segment.
  • + *
  • The access operation must fall inside the spatial bounds of the accessed + * memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case + * when {@code B + A <= S}, where {@code B} is the base offset (defined above), + * {@code A} is the size of this layout and {@code S} is the size of the + * accessed memory segment. Note that the size of this layout might be bigger + * than the size of the accessed layout (e.g. when accessing a struct member).
  • *
  • If the provided layout path has an open path element whose size is {@code S}, * its corresponding trailing {@code long} coordinate value {@code I} must be * {@code 0 <= I < S}, or an {@link IndexOutOfBoundsException} is thrown.
  • @@ -753,12 +753,12 @@ public sealed interface MemoryLayout * (this layout), or an {@link IllegalArgumentException} is thrown. Note * that the alignment constraint of the root layout can be more strict * (but not less) than the alignment constraint of the selected value layout. - *
  • The offset of the access operation (computed as above) must fall inside - * the spatial bounds of the accessed memory segment, or an - * {@link IndexOutOfBoundsException} is thrown. This is the case when - * {@code O + A <= S}, where {@code O} is the accessed offset (computed as above), - * {@code A} is the size of the selected layout and {@code S} is the size of the - * accessed memory segment.
  • + *
  • The access operation must fall inside the spatial bounds of the accessed + * memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case + * when {@code B + A <= S}, where {@code B} is the base offset (defined above), + * {@code A} is the size of this layout and {@code S} is the size of the + * accessed memory segment. Note that the size of this layout might be bigger + * than the size of the accessed layout (e.g. when accessing a struct member).
  • *
  • If the provided layout path has an open path element whose size is {@code S}, * its corresponding trailing {@code long} coordinate value {@code I} must be * {@code 0 <= I < S}, or an {@link IndexOutOfBoundsException} is thrown.
  • @@ -822,12 +822,12 @@ public sealed interface MemoryLayout * (this layout), or an {@link IllegalArgumentException} will be issued. Note * that the alignment constraint of the root layout can be more strict * (but not less) than the alignment constraint of the selected layout. - *
  • The start offset of the slicing operation (computed as above) must fall - * inside the spatial bounds of the accessed memory segment, or an - * {@link IndexOutOfBoundsException} is thrown. This is the case when - * {@code O + A <= S}, where {@code O} is the start offset of - * the slicing operation (computed as above), {@code A} is the size of the - * selected layout and {@code S} is the size of the accessed memory segment.
  • + *
  • The slicing operation must fall inside the spatial bounds of the accessed + * memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case + * when {@code B + A <= S}, where {@code B} is the base offset (defined above), + * {@code A} is the size of this layout and {@code S} is the size of the + * accessed memory segment. Note that the size of this layout might be bigger + * than the size of the accessed layout (e.g. when accessing a struct member).
  • *
  • If the provided layout path has an open path element whose size is {@code S}, * its corresponding trailing {@code long} coordinate value {@code I} must be * {@code 0 <= I < S}, or an {@link IndexOutOfBoundsException} is thrown.
  • diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandleSegmentViewBase.java b/src/java.base/share/classes/java/lang/invoke/VarHandleSegmentViewBase.java index 5cb71cf0424..31ec02c3d7c 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandleSegmentViewBase.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandleSegmentViewBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, 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 @@ -25,8 +25,6 @@ package java.lang.invoke; -import jdk.internal.foreign.Utils; - /** * Base class for memory segment var handle view implementations. */ @@ -42,23 +40,15 @@ abstract sealed class VarHandleSegmentViewBase extends VarHandle permits /** endianness **/ final boolean be; - /** access size (in bytes, computed from var handle carrier type) **/ - final long length; - /** alignment constraint (in bytes, expressed as a bit mask) **/ final long alignmentMask; - VarHandleSegmentViewBase(VarForm form, boolean be, long length, long alignmentMask, boolean exact) { + VarHandleSegmentViewBase(VarForm form, boolean be, long alignmentMask, boolean exact) { super(form, exact); this.be = be; - this.length = length; this.alignmentMask = alignmentMask; } - static IllegalArgumentException newIllegalArgumentExceptionForMisalignedAccess(long address) { - return new IllegalArgumentException("Misaligned access at address: " + Utils.toHexString(address)); - } - static UnsupportedOperationException newUnsupportedAccessModeForAlignment(long alignment) { return new UnsupportedOperationException("Unsupported access mode for alignment: " + alignment); } diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandles.java b/src/java.base/share/classes/java/lang/invoke/VarHandles.java index 0a393200447..bd608619e58 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -306,6 +306,9 @@ else if (viewComponentType == float.class) { * The resulting var handle will take a memory segment as first argument (the segment to be dereferenced), * and a {@code long} as second argument (the offset into the segment). * + * Note: the returned var handle does not perform any size or alignment check. It is up to clients + * to adapt the returned var handle and insert the appropriate checks. + * * @param carrier the Java carrier type. * @param alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask. * @param byteOrder the byte order. @@ -316,24 +319,23 @@ static VarHandle memorySegmentViewHandle(Class carrier, long alignmentMask, if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) { throw new IllegalArgumentException("Invalid carrier: " + carrier.getName()); } - long size = Utils.byteWidthOfPrimitive(carrier); boolean be = byteOrder == ByteOrder.BIG_ENDIAN; boolean exact = VAR_HANDLE_SEGMENT_FORCE_EXACT; if (carrier == byte.class) { - return maybeAdapt(new VarHandleSegmentAsBytes(be, size, alignmentMask, exact)); + return maybeAdapt(new VarHandleSegmentAsBytes(be, alignmentMask, exact)); } else if (carrier == char.class) { - return maybeAdapt(new VarHandleSegmentAsChars(be, size, alignmentMask, exact)); + return maybeAdapt(new VarHandleSegmentAsChars(be, alignmentMask, exact)); } else if (carrier == short.class) { - return maybeAdapt(new VarHandleSegmentAsShorts(be, size, alignmentMask, exact)); + return maybeAdapt(new VarHandleSegmentAsShorts(be, alignmentMask, exact)); } else if (carrier == int.class) { - return maybeAdapt(new VarHandleSegmentAsInts(be, size, alignmentMask, exact)); + return maybeAdapt(new VarHandleSegmentAsInts(be, alignmentMask, exact)); } else if (carrier == float.class) { - return maybeAdapt(new VarHandleSegmentAsFloats(be, size, alignmentMask, exact)); + return maybeAdapt(new VarHandleSegmentAsFloats(be, alignmentMask, exact)); } else if (carrier == long.class) { - return maybeAdapt(new VarHandleSegmentAsLongs(be, size, alignmentMask, exact)); + return maybeAdapt(new VarHandleSegmentAsLongs(be, alignmentMask, exact)); } else if (carrier == double.class) { - return maybeAdapt(new VarHandleSegmentAsDoubles(be, size, alignmentMask, exact)); + return maybeAdapt(new VarHandleSegmentAsDoubles(be, alignmentMask, exact)); } else { throw new IllegalStateException("Cannot get here"); } diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template index aa1c232e5df..0c088cd5c4b 100644 --- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template +++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, 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 @@ -47,8 +47,8 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { static final VarForm FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, long.class); - VarHandleSegmentAs$Type$s(boolean be, long length, long alignmentMask, boolean exact) { - super(FORM, be, length, alignmentMask, exact); + VarHandleSegmentAs$Type$s(boolean be, long alignmentMask, boolean exact) { + super(FORM, be, alignmentMask, exact); } @Override @@ -60,14 +60,14 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { public VarHandleSegmentAs$Type$s withInvokeExactBehavior() { return hasInvokeExactBehavior() ? this : - new VarHandleSegmentAs$Type$s(be, length, alignmentMask, true); + new VarHandleSegmentAs$Type$s(be, alignmentMask, true); } @Override public VarHandleSegmentAs$Type$s withInvokeBehavior() { return !hasInvokeExactBehavior() ? this : - new VarHandleSegmentAs$Type$s(be, length, alignmentMask, false); + new VarHandleSegmentAs$Type$s(be, alignmentMask, false); } #if[floatingPoint] @@ -97,9 +97,9 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { #end[floatingPoint] @ForceInline - static AbstractMemorySegmentImpl checkAddress(Object obb, long offset, long length, boolean ro) { + static AbstractMemorySegmentImpl checkReadOnly(Object obb, boolean ro) { AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl)Objects.requireNonNull(obb); - oo.checkAccess(offset, length, ro); + oo.checkReadOnly(ro); return oo; } @@ -108,39 +108,34 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { if ((alignmentMask & NON_PLAIN_ACCESS_MIN_ALIGN_MASK) != NON_PLAIN_ACCESS_MIN_ALIGN_MASK) { throw VarHandleSegmentViewBase.newUnsupportedAccessModeForAlignment(alignmentMask + 1); } - return offsetPlain(bb, offset, alignmentMask); + return offsetPlain(bb, offset); } @ForceInline - static long offsetPlain(AbstractMemorySegmentImpl bb, long offset, long alignmentMask) { + static long offsetPlain(AbstractMemorySegmentImpl bb, long offset) { long base = bb.unsafeGetOffset(); - long address = base + offset; - long maxAlignMask = bb.maxAlignMask(); - if (((address | maxAlignMask) & alignmentMask) != 0) { - throw VarHandleSegmentViewBase.newIllegalArgumentExceptionForMisalignedAccess(address); - } - return address; + return base + offset; } @ForceInline static $type$ get(VarHandle ob, Object obb, long base) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, true); #if[floatingPoint] $rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base, handle.alignmentMask), + offsetPlain(bb, base), handle.be); return $Type$.$rawType$BitsTo$Type$(rawValue); #else[floatingPoint] #if[byte] return SCOPED_MEMORY_ACCESS.get$Type$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base, handle.alignmentMask)); + offsetPlain(bb, base)); #else[byte] return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base, handle.alignmentMask), + offsetPlain(bb, base), handle.be); #end[byte] #end[floatingPoint] @@ -149,23 +144,23 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static void set(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); #if[floatingPoint] SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base, handle.alignmentMask), + offsetPlain(bb, base), $Type$.$type$ToRaw$RawType$Bits(value), handle.be); #else[floatingPoint] #if[byte] SCOPED_MEMORY_ACCESS.put$Type$(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base, handle.alignmentMask), + offsetPlain(bb, base), value); #else[byte] SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.sessionImpl(), bb.unsafeGetBase(), - offsetPlain(bb, base, handle.alignmentMask), + offsetPlain(bb, base), value, handle.be); #end[byte] @@ -175,7 +170,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getVolatile(VarHandle ob, Object obb, long base) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, true); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(), bb.unsafeGetBase(), @@ -185,7 +180,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static void setVolatile(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); SCOPED_MEMORY_ACCESS.put$RawType$Volatile(bb.sessionImpl(), bb.unsafeGetBase(), offsetNonPlain(bb, base, handle.alignmentMask), @@ -195,7 +190,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAcquire(VarHandle ob, Object obb, long base) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, true); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.get$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), @@ -205,7 +200,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static void setRelease(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); SCOPED_MEMORY_ACCESS.put$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), offsetNonPlain(bb, base, handle.alignmentMask), @@ -215,7 +210,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getOpaque(VarHandle ob, Object obb, long base) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, true); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.sessionImpl(), bb.unsafeGetBase(), @@ -225,7 +220,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static void setOpaque(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); SCOPED_MEMORY_ACCESS.put$RawType$Opaque(bb.sessionImpl(), bb.unsafeGetBase(), offsetNonPlain(bb, base, handle.alignmentMask), @@ -236,7 +231,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static boolean compareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), offsetNonPlain(bb, base, handle.alignmentMask), @@ -246,7 +241,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ compareAndExchange(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), @@ -257,7 +252,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), @@ -268,7 +263,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), @@ -279,7 +274,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(bb.sessionImpl(), bb.unsafeGetBase(), offsetNonPlain(bb, base, handle.alignmentMask), @@ -289,7 +284,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static boolean weakCompareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), offsetNonPlain(bb, base, handle.alignmentMask), @@ -299,7 +294,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), offsetNonPlain(bb, base, handle.alignmentMask), @@ -309,7 +304,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), offsetNonPlain(bb, base, handle.alignmentMask), @@ -319,7 +314,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndSet(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.getAndSet$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), @@ -330,7 +325,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndSetAcquire(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), @@ -341,7 +336,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndSetRelease(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); return convEndian(handle.be, SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), @@ -354,7 +349,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndAdd(VarHandle ob, Object obb, long base, $type$ delta) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), @@ -368,7 +363,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndAddAcquire(VarHandle ob, Object obb, long base, $type$ delta) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), @@ -382,7 +377,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndAddRelease(VarHandle ob, Object obb, long base, $type$ delta) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), @@ -410,7 +405,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndBitwiseOr(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), @@ -424,7 +419,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), @@ -438,7 +433,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), @@ -464,7 +459,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), @@ -478,7 +473,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), @@ -492,7 +487,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), @@ -519,7 +514,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndBitwiseXor(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(bb.sessionImpl(), bb.unsafeGetBase(), @@ -533,7 +528,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(bb.sessionImpl(), bb.unsafeGetBase(), @@ -547,7 +542,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { @ForceInline static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, long base, $type$ value) { VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; - AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false); + AbstractMemorySegmentImpl bb = checkReadOnly(obb, false); if (handle.be == BE) { return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(bb.sessionImpl(), bb.unsafeGetBase(), 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 05e7f345b26..f9f6ac2022a 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -357,10 +357,15 @@ private Z toArray(Class arrayClass, ValueLayout elemLayout, IntFunction> coordinateTypes = handle.coordinateTypes(); - MethodHandle alignCheck = MethodHandles.insertArguments(MH_CHECK_ALIGN, 2, rootLayout()); + MethodHandle alignCheck = MethodHandles.insertArguments(MH_CHECK_ENCL_LAYOUT, 2, rootLayout()); handle = MethodHandles.collectCoordinates(handle, 0, alignCheck); int[] reorder = IntStream.concat(IntStream.of(0, 1), IntStream.range(0, coordinateTypes.size())).toArray(); handle = MethodHandles.permuteCoordinates(handle, coordinateTypes, reorder); @@ -275,7 +275,7 @@ public MethodHandle sliceHandle() { if (enclosing != null) { // insert align check for the root layout on the initial MS + offset MethodType oldType = sliceHandle.type(); - MethodHandle alignCheck = MethodHandles.insertArguments(MH_CHECK_ALIGN, 2, rootLayout()); + MethodHandle alignCheck = MethodHandles.insertArguments(MH_CHECK_ENCL_LAYOUT, 2, rootLayout()); sliceHandle = MethodHandles.collectArguments(sliceHandle, 0, alignCheck); // (MS, long, MS, long) -> MS int[] reorder = IntStream.concat(IntStream.of(0, 1), IntStream.range(0, oldType.parameterCount())).toArray(); sliceHandle = MethodHandles.permuteArguments(sliceHandle, oldType, reorder); // (MS, long, ...) -> MS @@ -284,11 +284,12 @@ public MethodHandle sliceHandle() { return sliceHandle; } - private static void checkAlign(MemorySegment segment, long offset, MemoryLayout constraint) { - if (!((AbstractMemorySegmentImpl) segment).isAlignedForElement(offset, constraint)) { + private static void checkEnclosingLayout(MemorySegment segment, long offset, MemoryLayout enclosing) { + ((AbstractMemorySegmentImpl)segment).checkAccess(offset, enclosing.byteSize(), true); + if (!((AbstractMemorySegmentImpl) segment).isAlignedForElement(offset, enclosing)) { throw new IllegalArgumentException(String.format( "Target offset %d is incompatible with alignment constraint %d (of %s) for segment %s" - , offset, constraint.byteAlignment(), constraint, segment)); + , offset, enclosing.byteAlignment(), enclosing, segment)); } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index 6a081e23eac..f05666b88b6 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, 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 @@ -37,8 +37,6 @@ import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; import jdk.internal.access.SharedSecrets; @@ -90,26 +88,6 @@ public static MemorySegment alignUp(MemorySegment ms, long alignment) { } public static VarHandle makeSegmentViewVarHandle(ValueLayout layout) { - final class VarHandleCache { - private static final Map HANDLE_MAP = new ConcurrentHashMap<>(); - - static VarHandle put(ValueLayout layout, VarHandle handle) { - VarHandle prev = HANDLE_MAP.putIfAbsent(layout, handle); - return prev != null ? prev : handle; - } - - static VarHandle get(ValueLayout layout) { - return HANDLE_MAP.get(layout); - } - } - layout = layout.withoutName(); // name doesn't matter - // keep the addressee layout as it's used below - - VarHandle handle = VarHandleCache.get(layout); - if (handle != null) { - return handle; - } - Class baseCarrier = layout.carrier(); if (layout.carrier() == MemorySegment.class) { baseCarrier = switch ((int) ValueLayout.ADDRESS.byteSize()) { @@ -121,7 +99,7 @@ static VarHandle get(ValueLayout layout) { baseCarrier = byte.class; } - handle = SharedSecrets.getJavaLangInvokeAccess().memorySegmentViewHandle(baseCarrier, + VarHandle handle = SharedSecrets.getJavaLangInvokeAccess().memorySegmentViewHandle(baseCarrier, layout.byteAlignment() - 1, layout.order()); if (layout.carrier() == boolean.class) { @@ -133,7 +111,7 @@ static VarHandle get(ValueLayout layout) { pointeeByteSize(addressLayout), pointeeByteAlign(addressLayout)), MethodType.methodType(MemorySegment.class, baseCarrier))); } - return VarHandleCache.put(layout, handle); + return handle; } public static boolean byteToBoolean(byte b) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java index f72009cf690..796f0027158 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java @@ -188,6 +188,10 @@ public VarHandle varHandle(PathElement... elements) { if (this instanceof ValueLayout vl && elements.length == 0) { return vl.varHandle(); // fast path } + return varHandleInternal(elements); + } + + public VarHandle varHandleInternal(PathElement... elements) { return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::dereferenceHandle, Set.of(), elements); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java b/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java index 4b41c80f2eb..4d19879b01a 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, 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 @@ -38,8 +38,10 @@ import java.lang.foreign.ValueLayout; import java.lang.invoke.VarHandle; import java.nio.ByteOrder; +import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; /** * A value layout. A value layout is used to model the memory layout associated with values of basic data types, such as integral types @@ -157,9 +159,12 @@ static boolean isValidCarrier(Class carrier) { @ForceInline public final VarHandle varHandle() { + final class VarHandleCache { + private static final Map HANDLE_MAP = new ConcurrentHashMap<>(); + } if (handle == null) { // this store to stable field is safe, because return value of 'makeMemoryAccessVarHandle' has stable identity - handle = Utils.makeSegmentViewVarHandle(self()); + handle = VarHandleCache.HANDLE_MAP.computeIfAbsent(self().withoutName(), _ -> varHandleInternal()); } return handle; } diff --git a/test/jdk/java/foreign/TestAccessModes.java b/test/jdk/java/foreign/TestAccessModes.java index 89662c95252..0cedcc9058e 100644 --- a/test/jdk/java/foreign/TestAccessModes.java +++ b/test/jdk/java/foreign/TestAccessModes.java @@ -58,9 +58,8 @@ public void testAccessModes(MemorySegment segment, MemoryLayout layout, AccessMo } catch (UnsupportedOperationException ex) { assertFalse(compatible); } catch (IllegalArgumentException ex) { - // access is unaligned, but access mode is supported - assertTrue(compatible || - (layout instanceof GroupLayout && segment.maxByteAlignment() < layout.byteAlignment())); + // access is unaligned + assertTrue(segment.maxByteAlignment() < layout.byteAlignment()); } } diff --git a/test/jdk/java/foreign/TestHeapAlignment.java b/test/jdk/java/foreign/TestHeapAlignment.java index 99f09611914..cc8a9546510 100644 --- a/test/jdk/java/foreign/TestHeapAlignment.java +++ b/test/jdk/java/foreign/TestHeapAlignment.java @@ -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 @@ -45,7 +45,7 @@ public class TestHeapAlignment { public void testHeapAlignment(MemorySegment segment, int align, Object val, Object arr, ValueLayout layout, Function segmentFactory) { assertAligned(align, layout, () -> layout.varHandle().get(segment, 0L)); assertAligned(align, layout, () -> layout.varHandle().set(segment, 0L, val)); - MemoryLayout seq = MemoryLayout.sequenceLayout(10, layout); + MemoryLayout seq = MemoryLayout.sequenceLayout(1, layout); assertAligned(align, layout, () -> seq.varHandle(MemoryLayout.PathElement.sequenceElement()).get(segment, 0L, 0L)); assertAligned(align, layout, () -> seq.varHandle(MemoryLayout.PathElement.sequenceElement()).set(segment, 0L, 0L, val)); assertAligned(align, layout, () -> segment.spliterator(layout)); diff --git a/test/jdk/java/foreign/TestLayoutPaths.java b/test/jdk/java/foreign/TestLayoutPaths.java index 484e8f86ab5..414eb4117ce 100644 --- a/test/jdk/java/foreign/TestLayoutPaths.java +++ b/test/jdk/java/foreign/TestLayoutPaths.java @@ -34,6 +34,7 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.VarHandle; +import java.lang.invoke.VarHandle.AccessMode; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; @@ -331,6 +332,57 @@ public void testOffsetHandleOOBIndex(MemoryLayout layout, PathElement[] pathElem } } + @Test(dataProvider = "testLayouts") + public void testVarHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes, + long expectedByteOffset) throws Throwable { + MemoryLayout seqLayout = MemoryLayout.sequenceLayout(10, layout); + PathElement[] seqPathElements = new PathElement[pathElements.length + 1]; + long[] seqIndexes = new long[indexes.length + 1]; + System.arraycopy(pathElements, 0, seqPathElements, 1, pathElements.length); + System.arraycopy(indexes, 0, seqIndexes, 1, indexes.length); + seqPathElements[0] = PathElement.sequenceElement(); + seqIndexes[0] = 0; + MethodHandle getter_handle = seqLayout.varHandle(seqPathElements) + .toMethodHandle(AccessMode.GET) + .asSpreader(long[].class, seqIndexes.length); + MemorySegment segment = Arena.ofAuto().allocate(layout); + assertThrows(IndexOutOfBoundsException.class, () -> getter_handle.invoke(segment, 0L, seqIndexes)); + } + + @Test(dataProvider = "testLayouts") + public void testSliceHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes, + long expectedByteOffset) throws Throwable { + MemoryLayout seqLayout = MemoryLayout.sequenceLayout(10, layout); + PathElement[] seqPathElements = new PathElement[pathElements.length + 1]; + long[] seqIndexes = new long[indexes.length + 1]; + System.arraycopy(pathElements, 0, seqPathElements, 1, pathElements.length); + System.arraycopy(indexes, 0, seqIndexes, 1, indexes.length); + seqPathElements[0] = PathElement.sequenceElement(); + seqIndexes[0] = 0; + MethodHandle getter_handle = seqLayout.sliceHandle(seqPathElements) + .asSpreader(long[].class, seqIndexes.length); + MemorySegment segment = Arena.ofAuto().allocate(layout); + assertThrows(IndexOutOfBoundsException.class, () -> getter_handle.invoke(segment, 0L, seqIndexes)); + } + + @Test(dataProvider = "testLayouts") + public void testArrayElementVarHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes, + long expectedByteOffset) throws Throwable { + MemoryLayout seqLayout = MemoryLayout.sequenceLayout(10, layout); + PathElement[] seqPathElements = new PathElement[pathElements.length + 1]; + long[] seqIndexes = new long[indexes.length + 2]; + System.arraycopy(pathElements, 0, seqPathElements, 1, pathElements.length); + System.arraycopy(indexes, 0, seqIndexes, 2, indexes.length); + seqPathElements[0] = PathElement.sequenceElement(); + seqIndexes[0] = 0; + seqIndexes[1] = 0; + MethodHandle getter_handle = seqLayout.arrayElementVarHandle(seqPathElements) + .toMethodHandle(AccessMode.GET) + .asSpreader(long[].class, seqIndexes.length); + MemorySegment segment = Arena.ofAuto().allocate(layout); + assertThrows(IndexOutOfBoundsException.class, () -> getter_handle.invoke(segment, 0L, seqIndexes)); + } + @Test public void testHashCodeCollision() { PathElement sequenceElement = PathElement.sequenceElement(); From 6cda4c59851d7a9bbe8bd39c93a8923b039a7184 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Wed, 29 May 2024 11:19:55 +0000 Subject: [PATCH 91/99] 8321543: Update NSS to version 3.96 Reviewed-by: rhalade --- test/jdk/sun/security/pkcs11/PKCS11Test.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index 2ae1730f6e9..ffd1c42fd88 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -82,7 +82,7 @@ public abstract class PKCS11Test { // Version of the NSS artifact. This coincides with the version of // the NSS version - private static final String NSS_BUNDLE_VERSION = "3.91"; + private static final String NSS_BUNDLE_VERSION = "3.96"; private static final String NSSLIB = "jpg.tests.jdk.nsslib"; static double nss_version = -1; From fed2b56017ae454082d320513b77518e624fb03c Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Wed, 29 May 2024 12:25:40 +0000 Subject: [PATCH 92/99] 8320999: RISC-V: C2 RotateLeftV 8321000: RISC-V: C2 RotateRightV Reviewed-by: luhenry, fyang --- src/hotspot/cpu/riscv/assembler_riscv.hpp | 44 +++- src/hotspot/cpu/riscv/matcher_riscv.hpp | 8 +- src/hotspot/cpu/riscv/riscv_v.ad | 198 +++++++++++++++++- .../runner/ArrayShiftOpTest.java | 6 + 4 files changed, 248 insertions(+), 8 deletions(-) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index b0249ac3344..616aee82b99 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -1863,14 +1863,52 @@ enum Nf { patch_VArith(op, Vd, funct3, Vs1->raw_encoding(), Vs2, vm, funct6); \ } - // Vector Bit-manipulation used in Cryptography (Zvkb) Extension + // Vector Bit-manipulation used in Cryptography (Zvbb) Extension INSN(vandn_vv, 0b1010111, 0b000, 0b000001); - INSN(vclmul_vv, 0b1010111, 0b010, 0b001100); - INSN(vclmulh_vv, 0b1010111, 0b010, 0b001101); INSN(vror_vv, 0b1010111, 0b000, 0b010100); INSN(vrol_vv, 0b1010111, 0b000, 0b010101); + // Vector Bit-manipulation used in Cryptography (Zvbc) Extension + INSN(vclmul_vv, 0b1010111, 0b010, 0b001100); + INSN(vclmulh_vv, 0b1010111, 0b010, 0b001101); + +#undef INSN + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs2, Register Rs1, VectorMask vm = unmasked) { \ + patch_VArith(op, Vd, funct3, Rs1->raw_encoding(), Vs2, vm, funct6); \ + } + + // Vector Bit-manipulation used in Cryptography (Zvbb) Extension + INSN(vrol_vx, 0b1010111, 0b100, 0b010101); + INSN(vror_vx, 0b1010111, 0b100, 0b010100); + +#undef INSN + +#define patch_VArith_imm6(op, Reg, funct3, Reg_or_Imm5, I5, Vs2, vm, funct6) \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 19, 15, Reg_or_Imm5); \ + patch((address)&insn, 25, vm); \ + patch((address)&insn, 26, I5); \ + patch((address)&insn, 31, 27, funct6); \ + patch_reg((address)&insn, 7, Reg); \ + patch_reg((address)&insn, 20, Vs2); \ + emit(insn) + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs2, uint32_t imm, VectorMask vm = unmasked) { \ + guarantee(is_uimm6(imm), "uimm is invalid"); \ + patch_VArith_imm6(op, Vd, funct3, (uint32_t)(imm & 0x1f), (uint32_t)((imm >> 5) & 0x1), Vs2, vm, funct6); \ + } + + // Vector Bit-manipulation used in Cryptography (Zvbb) Extension + // NOTE: there is no corresponding vrol.vi supplied by the extension, but it can be emulated with vror.vi easily. + INSN(vror_vi, 0b1010111, 0b011, 0b01010); + #undef INSN +#undef patch_VArith_imm6 #define INSN(NAME, op, funct3, Vs1, funct6) \ void NAME(VectorRegister Vd, VectorRegister Vs2, VectorMask vm = unmasked) { \ diff --git a/src/hotspot/cpu/riscv/matcher_riscv.hpp b/src/hotspot/cpu/riscv/matcher_riscv.hpp index d1e10c34939..6e2b97b8202 100644 --- a/src/hotspot/cpu/riscv/matcher_riscv.hpp +++ b/src/hotspot/cpu/riscv/matcher_riscv.hpp @@ -138,13 +138,13 @@ } // Does the CPU supports vector variable rotate instructions? - static constexpr bool supports_vector_variable_rotates(void) { - return false; + static bool supports_vector_variable_rotates(void) { + return UseZvbb; } // Does the CPU supports vector constant rotate instructions? - static constexpr bool supports_vector_constant_rotates(int shift) { - return false; + static bool supports_vector_constant_rotates(int shift) { + return UseZvbb; } // Does the CPU supports vector unsigned comparison instructions? diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 5c57ffabe56..ae25263ef5b 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -75,9 +75,11 @@ source %{ break; case Op_CountTrailingZerosV: case Op_CountLeadingZerosV: - case Op_ReverseBytesV: case Op_PopCountVL: case Op_PopCountVI: + case Op_ReverseBytesV: + case Op_RotateLeftV: + case Op_RotateRightV: return UseZvbb; case Op_LoadVectorGather: case Op_LoadVectorGatherMasked: @@ -3057,6 +3059,200 @@ instruct vshiftcnt(vReg dst, iRegIorL2I cnt) %{ ins_pipe(pipe_slow); %} +// --------------------------------- Vector Rotation ---------------------------------- +// +// Following rotate instruct's are shared by vectorization (in SLP, superword.cpp) and Vector API. +// +// Rotate behaviour in vectorization is defined by java API, which includes: +// 1. Integer.rorateRight, Integer.rorateLeft. +// `rotation by any multiple of 32 is a no-op, so all but the last five bits of the rotation distance can be ignored`. +// 2. Long.rorateRight, Long.rorateLeft. +// `rotation by any multiple of 64 is a no-op, so all but the last six bits of the rotation distance can be ignored`. +// +// Rotate behaviour in Vector API is defined as below, e.g. +// 1. For Byte ROR, `a ROR b` is: (byte)(((((byte)a) & 0xFF) >>> (b & 7)) | ((((byte)a) & 0xFF) << (8 - (b & 7)))) +// 2. For Short ROR, `a ROR b` is: (short)(((((short)a) & 0xFFFF) >>> (b & 15)) | ((((short)a) & 0xFFFF) << (16 - (b & 15)))) +// 3. For Integer ROR, `a ROR b` is: Integer.rotateRight(a, ((int)b)) +// 4. For Long ROR, `a ROR b` is: Long.rotateRight(a, ((int)b)) +// +// Basically, the behaviour between vectorization and Vector API is the same for Long and Integer, except that Vector API +// also supports Byte and Short rotation. But we can still share the intrinsics between vectorization and Vector API. +// +// NOTE: As vror.vi encodes 6-bits immediate rotate amount, which is different from other vector-immediate instructions, +// implementation of vector rotation for long and other types can be unified. + +// Rotate right + +instruct vrotate_right(vReg dst, vReg src, vReg shift) %{ + match(Set dst (RotateRightV src shift)); + format %{ "vrotate_right $dst, $src, $shift\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vror_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vrotate_right_reg(vReg dst, vReg src, iRegIorL2I shift) %{ + match(Set dst (RotateRightV src (Replicate shift))); + format %{ "vrotate_right_reg $dst, $src, $shift\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vror_vx(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_Register($shift$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vrotate_right_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (RotateRightV src shift)); + format %{ "vrotate_right_imm $dst, $src, $shift\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + uint32_t bits = type2aelembytes(bt) * 8; + uint32_t con = (unsigned)$shift$$constant & (bits - 1); + if (con == 0) { + return; + } + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vror_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +// Rotate right - masked + +instruct vrotate_right_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ + match(Set dst_src (RotateRightV (Binary dst_src shift) v0)); + format %{ "vrotate_right_masked $dst_src, $dst_src, $shift, v0.t\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vror_vv(as_VectorRegister($dst_src$$reg), as_VectorRegister($dst_src$$reg), + as_VectorRegister($shift$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vrotate_right_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ + match(Set dst_src (RotateRightV (Binary dst_src (Replicate shift)) v0)); + format %{ "vrotate_right_reg_masked $dst_src, $dst_src, $shift, v0.t\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vror_vx(as_VectorRegister($dst_src$$reg), as_VectorRegister($dst_src$$reg), + as_Register($shift$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vrotate_right_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ + match(Set dst_src (RotateRightV (Binary dst_src shift) v0)); + format %{ "vrotate_right_imm_masked $dst_src, $dst_src, $shift, v0.t\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + uint32_t bits = type2aelembytes(bt) * 8; + uint32_t con = (unsigned)$shift$$constant & (bits - 1); + if (con == 0) { + return; + } + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vror_vi(as_VectorRegister($dst_src$$reg), as_VectorRegister($dst_src$$reg), + con, Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +// Rotate left + +instruct vrotate_left(vReg dst, vReg src, vReg shift) %{ + match(Set dst (RotateLeftV src shift)); + format %{ "vrotate_left $dst, $src, $shift\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vrol_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vrotate_left_reg(vReg dst, vReg src, iRegIorL2I shift) %{ + match(Set dst (RotateLeftV src (Replicate shift))); + format %{ "vrotate_left_reg $dst, $src, $shift\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vrol_vx(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_Register($shift$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vrotate_left_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (RotateLeftV src shift)); + format %{ "vrotate_left_imm $dst, $src, $shift\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + uint32_t bits = type2aelembytes(bt) * 8; + uint32_t con = (unsigned)$shift$$constant & (bits - 1); + if (con == 0) { + return; + } + __ vsetvli_helper(bt, Matcher::vector_length(this)); + con = bits - con; + __ vror_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +// Rotate left - masked + +instruct vrotate_left_masked(vReg dst_src, vReg shift, vRegMask_V0 v0) %{ + match(Set dst_src (RotateLeftV (Binary dst_src shift) v0)); + format %{ "vrotate_left_masked $dst_src, $dst_src, $shift, v0.t\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vrol_vv(as_VectorRegister($dst_src$$reg), as_VectorRegister($dst_src$$reg), + as_VectorRegister($shift$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vrotate_left_reg_masked(vReg dst_src, iRegIorL2I shift, vRegMask_V0 v0) %{ + match(Set dst_src (RotateLeftV (Binary dst_src (Replicate shift)) v0)); + format %{ "vrotate_left_reg_masked $dst_src, $dst_src, $shift, v0.t\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + __ vsetvli_helper(bt, Matcher::vector_length(this)); + __ vrol_vx(as_VectorRegister($dst_src$$reg), as_VectorRegister($dst_src$$reg), + as_Register($shift$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vrotate_left_imm_masked(vReg dst_src, immI shift, vRegMask_V0 v0) %{ + match(Set dst_src (RotateLeftV (Binary dst_src shift) v0)); + format %{ "vrotate_left_imm_masked $dst_src, $dst_src, $shift, v0.t\t" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + uint32_t bits = type2aelembytes(bt) * 8; + uint32_t con = (unsigned)$shift$$constant & (bits - 1); + if (con == 0) { + return; + } + __ vsetvli_helper(bt, Matcher::vector_length(this)); + con = bits - con; + __ vror_vi(as_VectorRegister($dst_src$$reg), as_VectorRegister($dst_src$$reg), + con, Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + // vector sqrt instruct vsqrt_fp(vReg dst, vReg src) %{ diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java index b723b349c2d..40307ba7e1b 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/ArrayShiftOpTest.java @@ -75,6 +75,9 @@ public ArrayShiftOpTest() { counts = {IRNode.STORE_VECTOR, ">0"}) @IR(applyIfCPUFeature = {"avx512f", "true"}, counts = {IRNode.ROTATE_RIGHT_V, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"zvbb", "true"}, + counts = {IRNode.ROTATE_RIGHT_V, ">0"}) public int[] intCombinedRotateShift() { int[] res = new int[SIZE]; for (int i = 0; i < SIZE; i++) { @@ -88,6 +91,9 @@ public int[] intCombinedRotateShift() { counts = {IRNode.STORE_VECTOR, ">0"}) @IR(applyIfCPUFeature = {"avx512f", "true"}, counts = {IRNode.ROTATE_RIGHT_V, ">0"}) + @IR(applyIfPlatform = {"riscv64", "true"}, + applyIfCPUFeature = {"zvbb", "true"}, + counts = {IRNode.ROTATE_RIGHT_V, ">0"}) public long[] longCombinedRotateShift() { long[] res = new long[SIZE]; for (int i = 0; i < SIZE; i++) { From 43a2f17342af8f5bf1f5823df9fa0bf0bdfdfce2 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 29 May 2024 12:38:51 +0000 Subject: [PATCH 93/99] 8333149: ubsan : memset on nullptr target detected in jvmtiEnvBase.cpp get_object_monitor_usage Reviewed-by: sspitsyn, mdoerr --- src/hotspot/share/prims/jvmtiEnvBase.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 94472baf27c..9186c0e0e58 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -1557,8 +1557,12 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec // this object has a heavyweight monitor // null out memory for robustness - memset(ret.waiters, 0, ret.waiter_count * sizeof(jthread *)); - memset(ret.notify_waiters, 0, ret.notify_waiter_count * sizeof(jthread *)); + if (ret.waiters != nullptr) { + memset(ret.waiters, 0, ret.waiter_count * sizeof(jthread *)); + } + if (ret.notify_waiters != nullptr) { + memset(ret.notify_waiters, 0, ret.notify_waiter_count * sizeof(jthread *)); + } if (ret.waiter_count > 0) { // we have contending threads waiting to enter/re-enter the monitor // identify threads waiting to enter and re-enter the monitor From 03b7a8586a77983b1851ddd3f4555fe2fca57919 Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Wed, 29 May 2024 14:59:19 +0000 Subject: [PATCH 94/99] 8332259: JvmtiTrace::safe_get_thread_name fails if current thread is in native state Reviewed-by: dholmes, sspitsyn --- src/hotspot/share/prims/jvmtiEnter.xsl | 9 +++++++++ src/hotspot/share/prims/jvmtiTrace.cpp | 9 ++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/prims/jvmtiEnter.xsl b/src/hotspot/share/prims/jvmtiEnter.xsl index f275da0cc86..59b70a162eb 100644 --- a/src/hotspot/share/prims/jvmtiEnter.xsl +++ b/src/hotspot/share/prims/jvmtiEnter.xsl @@ -450,6 +450,15 @@ struct jvmtiInterface_1_ jvmti PreserveExceptionMark __em(this_thread); + + + if (trace_flags) { + + curr_thread_name = JvmtiTrace::safe_get_current_thread_name(); + + } + + diff --git a/src/hotspot/share/prims/jvmtiTrace.cpp b/src/hotspot/share/prims/jvmtiTrace.cpp index 9ed139bd882..002f59957ea 100644 --- a/src/hotspot/share/prims/jvmtiTrace.cpp +++ b/src/hotspot/share/prims/jvmtiTrace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ #include "memory/resourceArea.hpp" #include "prims/jvmtiTrace.hpp" #include "runtime/javaThread.hpp" +#include "runtime/javaThread.inline.hpp" // // class JvmtiTrace @@ -277,6 +278,12 @@ const char *JvmtiTrace::safe_get_thread_name(Thread *thread) { if (!thread->is_Java_thread()) { return thread->name(); } + if (Thread::current()->is_Java_thread()) { + JavaThreadState current_state = JavaThread::cast(Thread::current())->thread_state(); + if (current_state == _thread_in_native || current_state == _thread_blocked) { + return "not readable"; + } + } JavaThread* java_thread = JavaThread::cast(thread); oop threadObj = java_thread->jvmti_vthread(); if (threadObj == nullptr) { From bc7d9e3d0bc663bbbeb068889082da4a9f0fa8de Mon Sep 17 00:00:00 2001 From: Leonid Mesnik Date: Wed, 29 May 2024 15:01:07 +0000 Subject: [PATCH 95/99] 8333013: Update vmTestbase/nsk/share/LocalProcess.java to don't use finalization Reviewed-by: cjplummer, amenkov --- .../vmTestbase/nsk/share/jdb/JdbTest.java | 23 +++++++--------- .../nsk/share/{ => jdb}/LocalProcess.java | 26 +++---------------- 2 files changed, 13 insertions(+), 36 deletions(-) rename test/hotspot/jtreg/vmTestbase/nsk/share/{ => jdb}/LocalProcess.java (89%) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java index ce2eb8de68f..349216f4329 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/JdbTest.java @@ -204,27 +204,24 @@ protected int runTest(String argv[], PrintStream out) { } } - } catch (Exception e) { - failure("Caught unexpected exception: " + e); - e.printStackTrace(out); - + } catch (Throwable t) { + failure("Caught unexpected exception: " + t); + t.printStackTrace(out); + } finally { if (jdb != null) { + log.complain("jdb reference is not null, check for exception in the logs."); try { jdb.close(); } catch (Throwable ex) { failure("Caught exception/error while closing jdb streams:\n\t" + ex); ex.printStackTrace(log.getOutStream()); } - } else { - log.complain("jdb reference is null, cannot run jdb.close() method"); } - if (debuggee != null) { + if (debuggee != null && !debuggee.terminated()) { + log.complain("debuggee is still running, check for exception in the logs."); debuggee.killDebuggee(); - } else { - log.complain("debuggee reference is null, cannot run debuggee.killDebuggee() method"); } - } if (!success) { @@ -232,9 +229,9 @@ protected int runTest(String argv[], PrintStream out) { return FAILED; } - } catch (Exception e) { - out.println("Caught unexpected exception while starting the test: " + e); - e.printStackTrace(out); + } catch (Throwable t) { + out.println("Caught unexpected exception while starting the test: " + t); + t.printStackTrace(out); out.println("TEST FAILED"); return FAILED; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/LocalProcess.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/LocalProcess.java similarity index 89% rename from test/hotspot/jtreg/vmTestbase/nsk/share/LocalProcess.java rename to test/hotspot/jtreg/vmTestbase/nsk/share/jdb/LocalProcess.java index 6ff5c9a39a5..edb9f78ddc8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/LocalProcess.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdb/LocalProcess.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 @@ -21,9 +21,7 @@ * questions. */ -package nsk.share; - -import nsk.share.*; +package nsk.share.jdb; import java.io.*; @@ -33,14 +31,9 @@ * This class provides abilities to launch such process, * redirect standard output streams, wait for process terminates * or kill the process, and so on. - *

    - * This object is finalized with nsk.share.Finalizer. - * - * @see nsk.share.FinalizableObject - * @see nsk.share.Finalizer */ -public class LocalProcess extends FinalizableObject { +class LocalProcess { public final static int PROCESS_IS_ALIVE = 222; @@ -59,16 +52,11 @@ public void launch (String[] args) throws IOException { } process = Runtime.getRuntime().exec(args); - - registerCleanup(); } public void launch (String cmdLine) throws IOException { System.out.println("Launching process by command line: " + cmdLine); - process = Runtime.getRuntime().exec(cmdLine); - - registerCleanup(); } /** Return exit status. */ @@ -163,12 +151,4 @@ protected void kill() { process.destroy(); } - /** - * This method is called at finalization and calls kill(). - * - */ - @Override - public void cleanup() { - kill(); - } } From c8eea59f508158075382079316cf0990116ff98e Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 29 May 2024 18:23:23 +0000 Subject: [PATCH 96/99] 8332919: SA PointerLocation needs to print a newline after dumping java thread info for JNI Local Ref Reviewed-by: kevinw, dholmes --- .../classes/sun/jvm/hotspot/utilities/PointerLocation.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java index 393ad76a011..c3f09bd5e3d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PointerLocation.java @@ -359,7 +359,8 @@ public void printOn(PrintStream tty, boolean printAddress, boolean verbose) { tty.print(" JNI handle block (" + handleBlock.top() + " handle slots present)"); if (handleThread.isJavaThread()) { tty.print(" for JavaThread "); - ((JavaThread) handleThread).printThreadIDOn(tty); // includes "\n" + ((JavaThread) handleThread).printThreadIDOn(tty); + tty.println(); } else { tty.println(" for a non-Java Thread"); } From 789ac8b2768671ec83a7ed4a72c5fe27a1734c5e Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Wed, 29 May 2024 19:51:07 +0000 Subject: [PATCH 97/99] 8333189: Make sure clang on linux uses lld as linker Reviewed-by: jiangli, erikj --- make/autoconf/flags-ldflags.m4 | 2 +- make/data/hotspot-symbols/version-script-clang.txt | 8 ++++++++ .../{version-script.txt => version-script-gcc.txt} | 0 make/hotspot/lib/CompileJvm.gmk | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 make/data/hotspot-symbols/version-script-clang.txt rename make/data/hotspot-symbols/{version-script.txt => version-script-gcc.txt} (100%) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index c4a75fb89c3..a2d0d4e606a 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -71,7 +71,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], LDFLAGS_CXX_PARTIAL_LINKING="$MACHINE_FLAG -r" if test "x$OPENJDK_TARGET_OS" = xlinux; then - BASIC_LDFLAGS="-Wl,--exclude-libs,ALL" + BASIC_LDFLAGS="-fuse-ld=lld -Wl,--exclude-libs,ALL" fi if test "x$OPENJDK_TARGET_OS" = xaix; then BASIC_LDFLAGS="-Wl,-b64 -Wl,-brtl -Wl,-bnorwexec -Wl,-bnolibpath -Wl,-bnoexpall \ diff --git a/make/data/hotspot-symbols/version-script-clang.txt b/make/data/hotspot-symbols/version-script-clang.txt new file mode 100644 index 00000000000..351d64fdd1d --- /dev/null +++ b/make/data/hotspot-symbols/version-script-clang.txt @@ -0,0 +1,8 @@ +SUNWprivate_1.1 { + global: + *; + + local: + _fini; + _init; +}; diff --git a/make/data/hotspot-symbols/version-script.txt b/make/data/hotspot-symbols/version-script-gcc.txt similarity index 100% rename from make/data/hotspot-symbols/version-script.txt rename to make/data/hotspot-symbols/version-script-gcc.txt diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index ad374d57cee..dff7a159ae5 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -154,7 +154,7 @@ ifeq ($(call isTargetOs, windows), true) endif ifeq ($(call isTargetOs, linux), true) - HOTSPOT_VERSION_SCRIPT := $(TOPDIR)/make/data/hotspot-symbols/version-script.txt + HOTSPOT_VERSION_SCRIPT := $(TOPDIR)/make/data/hotspot-symbols/version-script-$(TOOLCHAIN_TYPE).txt JVM_LDFLAGS += -Wl,-version-script=$(HOTSPOT_VERSION_SCRIPT) endif From ded1e5af75c7de382ff209cc87b827c191d0e3ae Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Fri, 31 May 2024 17:53:35 +0000 Subject: [PATCH 98/99] 8333236: Test java/foreign/TestAccessModes.java is timing out after passing Reviewed-by: jvernee --- .../jdk/internal/foreign/LayoutPath.java | 2 +- .../classes/jdk/internal/foreign/Utils.java | 28 +++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java index 92b94fe612e..ebd83d1c5da 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java +++ b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java @@ -205,7 +205,7 @@ public VarHandle dereferenceHandle(boolean adapt) { String.format("Path does not select a value layout: %s", breadcrumbs())); } - VarHandle handle = Utils.makeSegmentViewVarHandle(valueLayout); + VarHandle handle = Utils.makeRawSegmentViewVarHandle(valueLayout); handle = MethodHandles.collectCoordinates(handle, 1, offsetHandle()); // we only have to check the alignment of the root layout for the first dereference we do, diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index f05666b88b6..2ed65e3dd04 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -28,6 +28,7 @@ import java.lang.foreign.AddressLayout; import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemoryLayout.PathElement; import java.lang.foreign.MemorySegment; import java.lang.foreign.StructLayout; import java.lang.foreign.ValueLayout; @@ -37,6 +38,8 @@ import java.lang.invoke.VarHandle; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; import jdk.internal.access.SharedSecrets; @@ -87,7 +90,28 @@ public static MemorySegment alignUp(MemorySegment ms, long alignment) { return ms.asSlice(alignUp(offset, alignment) - offset); } - public static VarHandle makeSegmentViewVarHandle(ValueLayout layout) { + /** + * This method returns a raw var handle, that is, a var handle that does not perform any size + * or alignment checks. Such checks are added (using adaptation) by {@link LayoutPath#dereferenceHandle()}. + *

    + * We provide two level of caching of the generated var handles. First, the var handle associated + * with a {@link ValueLayout#varHandle()} call is cached inside a stable field of the value layout implementation. + * This optimizes common code idioms like {@code JAVA_INT.varHandle().getInt(...)}. A second layer of caching + * is then provided by this method: after all, var handles constructed by {@link MemoryLayout#varHandle(PathElement...)} + * will be obtained by adapting some raw var handle generated by this method. + * + * @param layout the value layout for which a raw memory segment var handle is to be created. + * @return a raw memory segment var handle. + */ + public static VarHandle makeRawSegmentViewVarHandle(ValueLayout layout) { + final class VarHandleCache { + private static final Map HANDLE_MAP = new ConcurrentHashMap<>(); + } + return VarHandleCache.HANDLE_MAP + .computeIfAbsent(layout.withoutName(), Utils::makeRawSegmentViewVarHandleInternal); + } + + private static VarHandle makeRawSegmentViewVarHandleInternal(ValueLayout layout) { Class baseCarrier = layout.carrier(); if (layout.carrier() == MemorySegment.class) { baseCarrier = switch ((int) ValueLayout.ADDRESS.byteSize()) { @@ -108,7 +132,7 @@ public static VarHandle makeSegmentViewVarHandle(ValueLayout layout) { handle = MethodHandles.filterValue(handle, MethodHandles.explicitCastArguments(ADDRESS_TO_LONG, MethodType.methodType(baseCarrier, MemorySegment.class)), MethodHandles.explicitCastArguments(MethodHandles.insertArguments(LONG_TO_ADDRESS, 1, - pointeeByteSize(addressLayout), pointeeByteAlign(addressLayout)), + pointeeByteSize(addressLayout), pointeeByteAlign(addressLayout)), MethodType.methodType(MemorySegment.class, baseCarrier))); } return handle; From 59009b031468deb23e73c7dc92a31a97094eb188 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 5 Jun 2024 07:11:27 +0000 Subject: [PATCH 99/99] 8333326: Linux Alpine build fails after 8302744 Reviewed-by: sgehwolf, clanger, stuefe --- .../gtest/runtime/test_cgroupSubsystem_linux.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp index cc326dbb502..aa1d2a19b28 100644 --- a/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp +++ b/test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp @@ -34,6 +34,9 @@ #include +// for basename +#include + typedef struct { const char* mount_path; const char* root_path; @@ -47,6 +50,7 @@ static bool file_exists(const char* filename) { return os::stat(filename, &st) == 0; } +// we rely on temp_file returning modifiable memory in resource area. static char* temp_file(const char* prefix) { const testing::TestInfo* test_info = ::testing::UnitTest::GetInstance()->current_test_info(); stringStream path; @@ -89,7 +93,7 @@ static void fill_file(const char* path, const char* content) { } TEST(cgroupTest, read_numerical_key_value_failure_cases) { - const char* test_file = temp_file("cgroups"); + char* test_file = temp_file("cgroups"); const char* b = basename(test_file); EXPECT_TRUE(b != nullptr) << "basename was null"; stringStream path; @@ -135,7 +139,7 @@ TEST(cgroupTest, read_numerical_key_value_failure_cases) { } TEST(cgroupTest, read_numerical_key_value_success_cases) { - const char* test_file = temp_file("cgroups"); + char* test_file = temp_file("cgroups"); const char* b = basename(test_file); EXPECT_TRUE(b != nullptr) << "basename was null"; stringStream path; @@ -235,7 +239,7 @@ TEST(cgroupTest, read_numerical_key_value_null) { } TEST(cgroupTest, read_number_tests) { - const char* test_file = temp_file("cgroups"); + char* test_file = temp_file("cgroups"); const char* b = basename(test_file); constexpr julong bad = 0xBAD; EXPECT_TRUE(b != nullptr) << "basename was null"; @@ -289,7 +293,7 @@ TEST(cgroupTest, read_number_tests) { } TEST(cgroupTest, read_string_tests) { - const char* test_file = temp_file("cgroups"); + char* test_file = temp_file("cgroups"); const char* b = basename(test_file); EXPECT_TRUE(b != nullptr) << "basename was null"; stringStream path; @@ -355,7 +359,7 @@ TEST(cgroupTest, read_string_tests) { } TEST(cgroupTest, read_number_tuple_test) { - const char* test_file = temp_file("cgroups"); + char* test_file = temp_file("cgroups"); const char* b = basename(test_file); EXPECT_TRUE(b != nullptr) << "basename was null"; stringStream path;