diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index ab32349f495..86b242bf0d6 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -489,7 +489,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], CFLAGS_OS_DEF_JVM="-D_ALLBSD_SOURCE -D_DARWIN_C_SOURCE -D_XOPEN_SOURCE" CFLAGS_OS_DEF_JDK="-D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" elif test "x$OPENJDK_TARGET_OS" = xaix; then - CFLAGS_OS_DEF_JVM="-DAIX -Dalloca'(size)'=__builtin_alloca'(size)' -D_LARGE_FILES" + CFLAGS_OS_DEF_JVM="-DAIX -D_LARGE_FILES" CFLAGS_OS_DEF_JDK="-D_LARGE_FILES" elif test "x$OPENJDK_TARGET_OS" = xbsd; then CFLAGS_OS_DEF_JDK="-D_ALLBSD_SOURCE" diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index a944e8c77fb..bbf2e39eb48 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -406,7 +406,8 @@ private static Console instantiateConsole(boolean istty) { /* * The JdkConsole provider used for Console instantiation can be specified * with the system property "jdk.console", whose value designates the module - * name of the implementation, and which defaults to "java.base". If no + * name of the implementation, and which defaults to the value of + * {@code JdkConsoleProvider.DEFAULT_PROVIDER_MODULE_NAME}. If no * providers are available, or instantiation failed, java.base built-in * Console implementation is used. */ diff --git a/src/java.base/share/classes/java/lang/classfile/Signature.java b/src/java.base/share/classes/java/lang/classfile/Signature.java index ad2528fd713..22ca477f4e6 100644 --- a/src/java.base/share/classes/java/lang/classfile/Signature.java +++ b/src/java.base/share/classes/java/lang/classfile/Signature.java @@ -185,88 +185,107 @@ public static ClassTypeSig of(ClassTypeSig outerType, String className, TypeArg. /** * Models the type argument. * + * @sealedGraph * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - public sealed interface TypeArg - permits SignaturesImpl.TypeArgImpl { + public sealed interface TypeArg { /** - * Indicator for whether a wildcard has default bound, no bound, - * an upper bound, or a lower bound - * - * @since 22 + * Models an unbounded type argument {@code *}. + * @since 23 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) - public enum WildcardIndicator { - - /** - * default bound wildcard (empty) - */ - DEFAULT, - - /** - * unbounded indicator {@code *} - */ - UNBOUNDED, + public sealed interface Unbounded extends TypeArg permits SignaturesImpl.UnboundedTypeArgImpl { + } - /** - * upper-bounded indicator {@code +} - */ - EXTENDS, + /** + * Models a type argument with an explicit bound type. + * @since 23 + */ + @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) + public sealed interface Bounded extends TypeArg permits SignaturesImpl.TypeArgImpl { /** - * lower-bounded indicator {@code -} + * Models a type argument's wildcard indicator. + * @since 23 */ - SUPER; + @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) + public enum WildcardIndicator { + + /** + * No wildcard (empty), an exact type. Also known as + * {@index invariant}. + */ + NONE, + + /** + * Upper-bound indicator {@code +}. Also known as + * {@index covariant}. + */ + EXTENDS, + + /** + * Lower-bound indicator {@code -}. Also known as + * {@index contravariant}. + */ + SUPER; + } + + /** {@return the kind of wildcard} */ + WildcardIndicator wildcardIndicator(); + + /** {@return the signature of the type bound} */ + RefTypeSig boundType(); } - /** {@return the wildcard indicator} */ - WildcardIndicator wildcardIndicator(); - - /** {@return the signature of the type bound, if any} */ - Optional boundType(); - /** * {@return a bounded type arg} * @param boundType the bound + * @since 23 */ - public static TypeArg of(RefTypeSig boundType) { + public static TypeArg.Bounded of(RefTypeSig boundType) { requireNonNull(boundType); - return of(WildcardIndicator.DEFAULT, Optional.of(boundType)); + return bounded(Bounded.WildcardIndicator.NONE, boundType); } /** * {@return an unbounded type arg} + * @since 23 */ - public static TypeArg unbounded() { - return of(WildcardIndicator.UNBOUNDED, Optional.empty()); + public static TypeArg.Unbounded unbounded() { + return SignaturesImpl.UnboundedTypeArgImpl.INSTANCE; } /** * {@return an upper-bounded type arg} * @param boundType the upper bound + * @since 23 */ - public static TypeArg extendsOf(RefTypeSig boundType) { + public static TypeArg.Bounded extendsOf(RefTypeSig boundType) { requireNonNull(boundType); - return of(WildcardIndicator.EXTENDS, Optional.of(boundType)); + return bounded(Bounded.WildcardIndicator.EXTENDS, boundType); } /** * {@return a lower-bounded type arg} * @param boundType the lower bound + * @since 23 */ - public static TypeArg superOf(RefTypeSig boundType) { + public static TypeArg.Bounded superOf(RefTypeSig boundType) { requireNonNull(boundType); - return of(WildcardIndicator.SUPER, Optional.of(boundType)); + return bounded(Bounded.WildcardIndicator.SUPER, boundType); } /** * {@return a bounded type arg} * @param wildcard the wild card * @param boundType optional bound type + * @since 23 */ - public static TypeArg of(WildcardIndicator wildcard, Optional boundType) { + public static TypeArg.Bounded bounded(Bounded.WildcardIndicator wildcard, RefTypeSig boundType) { + requireNonNull(wildcard); + requireNonNull(boundType); return new SignaturesImpl.TypeArgImpl(wildcard, boundType); } } 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 2022f8f0154..4878ad56ae8 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 @@ -391,21 +391,10 @@ private PoolEntry entryByIndex(int index, int lowerBoundTag, int upperBoundTag) @Override public AbstractPoolEntry.Utf8EntryImpl utf8EntryByIndex(int index) { - if (index <= 0 || index >= constantPoolCount) { - throw new ConstantPoolException("Bad CP UTF8 index: " + index); - } - PoolEntry info = cp[index]; - if (info == null) { - int offset = cpOffset[index]; - int tag = readU1(offset); - final int q = offset + 1; - if (tag != TAG_UTF8) throw new ConstantPoolException("Not a UTF8 - index: " + index); - AbstractPoolEntry.Utf8EntryImpl uinfo - = new AbstractPoolEntry.Utf8EntryImpl(this, index, buffer, q + 2, readU2(q)); - cp[index] = uinfo; - return uinfo; + if (entryByIndex(index, TAG_UTF8, TAG_UTF8) instanceof AbstractPoolEntry.Utf8EntryImpl utf8) { + return utf8; } - return (AbstractPoolEntry.Utf8EntryImpl) info; + throw new ConstantPoolException("Not a UTF8 - index: " + index); } @Override 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 6e80e289064..de6128a9f7f 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 @@ -369,11 +369,11 @@ S mapSignature(S signature) { Signature.ClassTypeSig.of( cts.outerType().map(this::mapSignature).orElse(null), map(cts.classDesc()), - cts.typeArgs().stream() - .map(ta -> Signature.TypeArg.of( - ta.wildcardIndicator(), - ta.boundType().map(this::mapSignature))) - .toArray(Signature.TypeArg[]::new)); + cts.typeArgs().stream().map(ta -> switch (ta) { + case Signature.TypeArg.Unbounded u -> u; + case Signature.TypeArg.Bounded bta -> Signature.TypeArg.bounded( + bta.wildcardIndicator(), mapSignature(bta.boundType())); + }).toArray(Signature.TypeArg[]::new)); default -> signature; }; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java index 3447e40b258..77f6933a0c2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java @@ -280,24 +280,29 @@ public String signatureString() { if (!typeArgs.isEmpty()) { var sb = new StringBuilder(); sb.append('<'); - for (var ta : typeArgs) - sb.append(((TypeArgImpl)ta).signatureString()); + for (var ta : typeArgs) { + switch (ta) { + case TypeArg.Bounded b -> { + switch (b.wildcardIndicator()) { + case SUPER -> sb.append('-'); + case EXTENDS -> sb.append('+'); + } + sb.append(b.boundType().signatureString()); + } + case TypeArg.Unbounded _ -> sb.append('*'); + } + } suffix = sb.append(">;").toString(); } return prefix + className + suffix; } } - public static record TypeArgImpl(WildcardIndicator wildcardIndicator, Optional boundType) implements Signature.TypeArg { + public static enum UnboundedTypeArgImpl implements TypeArg.Unbounded { + INSTANCE; + } - public String signatureString() { - return switch (wildcardIndicator) { - case DEFAULT -> boundType.get().signatureString(); - case EXTENDS -> "+" + boundType.get().signatureString(); - case SUPER -> "-" + boundType.get().signatureString(); - case UNBOUNDED -> "*"; - }; - } + public static record TypeArgImpl(WildcardIndicator wildcardIndicator, RefTypeSig boundType) implements Signature.TypeArg.Bounded { } public static record TypeParamImpl(String identifier, Optional classBound, List interfaceBounds) diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index 3754408fbde..990fdccf8d5 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -1103,8 +1103,7 @@ following: .RS .TP \f[V]all\f[R] -Shows all categories of settings. -This is the default value. +Shows all categories of settings in \f[B]verbose\f[R] detail. .TP \f[V]locale\f[R] Shows settings related to locale. @@ -1112,6 +1111,21 @@ Shows settings related to locale. \f[V]properties\f[R] Shows settings related to system properties. .TP +\f[V]security\f[R] +Shows all settings related to security. +.RS +.PP +sub-category arguments for \f[V]security\f[R] include the following: +.IP \[bu] 2 +\f[V]security:all\f[R] : shows all security settings +.IP \[bu] 2 +\f[V]security:properties\f[R] : shows security properties +.IP \[bu] 2 +\f[V]security:providers\f[R] : shows static security provider settings +.IP \[bu] 2 +\f[V]security:tls\f[R] : shows TLS related security settings +.RE +.TP \f[V]vm\f[R] Shows the settings of the JVM. .TP diff --git a/src/java.desktop/share/classes/sun/font/CodePointIterator.java b/src/java.desktop/share/classes/sun/font/CodePointIterator.java index 179e049db60..31c4bc5c1d4 100644 --- a/src/java.desktop/share/classes/sun/font/CodePointIterator.java +++ b/src/java.desktop/share/classes/sun/font/CodePointIterator.java @@ -56,10 +56,6 @@ public static CodePointIterator create(char[] text, int start, int limit) { return new CharArrayCodePointIterator(text, start, limit); } - public static CodePointIterator create(CharSequence text) { - return new CharSequenceCodePointIterator(text); - } - public static CodePointIterator create(CharacterIterator iter) { return new CharacterIteratorCodePointIterator(iter); } @@ -129,57 +125,6 @@ public int charIndex() { } } -final class CharSequenceCodePointIterator extends CodePointIterator { - private CharSequence text; - private int index; - - public CharSequenceCodePointIterator(CharSequence text) { - this.text = text; - } - - public void setToStart() { - index = 0; - } - - public void setToLimit() { - index = text.length(); - } - - public int next() { - if (index < text.length()) { - char cp1 = text.charAt(index++); - if (Character.isHighSurrogate(cp1) && index < text.length()) { - char cp2 = text.charAt(index+1); - if (Character.isLowSurrogate(cp2)) { - ++index; - return Character.toCodePoint(cp1, cp2); - } - } - return cp1; - } - return DONE; - } - - public int prev() { - if (index > 0) { - char cp2 = text.charAt(--index); - if (Character.isLowSurrogate(cp2) && index > 0) { - char cp1 = text.charAt(index - 1); - if (Character.isHighSurrogate(cp1)) { - --index; - return Character.toCodePoint(cp1, cp2); - } - } - return cp2; - } - return DONE; - } - - public int charIndex() { - return index; - } -} - // note this has different iteration semantics than CharacterIterator final class CharacterIteratorCodePointIterator extends CodePointIterator { private CharacterIterator iter; 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 2b841a5791a..fc90be38062 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 @@ -368,16 +368,20 @@ private void print(StringBuilder sb, Signature sig) { } private void print(StringBuilder sb, Signature.TypeArg ta) { - switch (ta.wildcardIndicator()) { - case DEFAULT -> print(sb, ta.boundType().get()); - case UNBOUNDED -> sb.append('?'); - case EXTENDS -> { - sb.append("? extends "); - print(sb, ta.boundType().get()); - } - case SUPER -> { - sb.append("? super "); - print(sb, ta.boundType().get()); + switch (ta) { + case Signature.TypeArg.Unbounded _ -> sb.append('?'); + case Signature.TypeArg.Bounded bta -> { + switch (bta.wildcardIndicator()) { + case NONE -> print(sb, bta.boundType()); + case EXTENDS -> { + sb.append("? extends "); + print(sb, bta.boundType()); + } + case SUPER -> { + sb.append("? super "); + print(sb, bta.boundType()); + } + } } } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java index 0dbd70801d2..d115b9f5b62 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java @@ -321,6 +321,7 @@ private boolean hasJDKEvents(Map settings) { public String[] getStartupHelp() { Map parameters = Map.of( "$SYNTAX", "-XX:StartFlightRecording:[options]", + "$SOURCE_NO_ARGUMENTS", "-XX:StartFlightRecording", "$SOURCE", "-XX:StartFlightRecording:", "$DELIMITER", ",", "$DELIMITER_NAME", "comma", @@ -334,6 +335,7 @@ public String[] getStartupHelp() { public String[] getHelp() { Map parameters = Map.of( "$SYNTAX", "JFR.start [options]", + "$SOURCE_NO_ARGUMENTS", "$ jcmd JFR.start", "$SOURCE", "$ jcmd JFR.start ", "$DELIMITER", " ", "$DELIMITER_NAME", "whitespace", @@ -440,7 +442,7 @@ Virtual Machine (JVM) shuts down. If set to 'true' and no value Example usage: - $SOURCE + $SOURCE_NO_ARGUMENTS $SOURCEfilename=dump.jfr $SOURCEfilename=$DIRECTORY $SOURCEdumponexit=true diff --git a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp index 6dfde68678a..4639f1c9694 100644 --- a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp +++ b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp @@ -50,7 +50,7 @@ TEST_OTHER_VM(FreeRegionList, length) { // the BOT. size_t bot_size = G1BlockOffsetTable::compute_size(heap.word_size()); HeapWord* bot_data = NEW_C_HEAP_ARRAY(HeapWord, bot_size, mtGC); - ReservedSpace bot_rs(G1BlockOffsetTable::compute_size(heap.word_size()), mtTest); + ReservedSpace bot_rs(G1BlockOffsetTable::compute_size(heap.word_size())); G1RegionToSpaceMapper* bot_storage = G1RegionToSpaceMapper::create_mapper(bot_rs, bot_rs.size(), diff --git a/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp b/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp index 2285f58d55c..8ce98827ab2 100644 --- a/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp +++ b/test/hotspot/gtest/gc/g1/test_stressCommitUncommit.cpp @@ -81,7 +81,7 @@ TEST_VM(G1RegionToSpaceMapper, smallStressAdjacent) { size_t size = G1BlockOffsetTable::compute_size(num_regions * region_size / HeapWordSize); size_t page_size = os::vm_page_size(); - ReservedSpace rs(size, os::vm_page_size(), mtTest); + ReservedSpace rs(size, os::vm_page_size()); G1RegionToSpaceMapper* small_mapper = G1RegionToSpaceMapper::create_mapper(rs, @@ -105,7 +105,7 @@ TEST_VM(G1RegionToSpaceMapper, largeStressAdjacent) { size_t size = G1BlockOffsetTable::compute_size(num_regions * region_size / HeapWordSize); size_t page_size = os::vm_page_size(); - ReservedSpace rs(size, page_size, mtTest); + ReservedSpace rs(size, page_size); G1RegionToSpaceMapper* large_mapper = G1RegionToSpaceMapper::create_mapper(rs, diff --git a/test/hotspot/gtest/gc/z/test_zForwarding.cpp b/test/hotspot/gtest/gc/z/test_zForwarding.cpp index 570e402ccd7..622c6d9d8f4 100644 --- a/test/hotspot/gtest/gc/z/test_zForwarding.cpp +++ b/test/hotspot/gtest/gc/z/test_zForwarding.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,7 +56,7 @@ class ZForwardingTest : public Test { const size_t increment = MAX2(align_up(unused / 100, ZGranuleSize), ZGranuleSize); for (uintptr_t start = 0; start + ZGranuleSize <= ZAddressOffsetMax; start += increment) { - char* const reserved = os::attempt_reserve_memory_at((char*)ZAddressHeapBase + start, ZGranuleSize, !ExecMem /* executable */, mtTest); + char* const reserved = os::attempt_reserve_memory_at((char*)ZAddressHeapBase + start, ZGranuleSize, false /* executable */); if (reserved != nullptr) { // Success return reserved; @@ -100,7 +100,7 @@ class ZForwardingTest : public Test { _reserved = reserved; - os::commit_memory((char*)_reserved, ZGranuleSize, !ExecMem /* executable */, mtTest); + os::commit_memory((char*)_reserved, ZGranuleSize, false /* executable */); _page_offset = uintptr_t(_reserved) - ZAddressHeapBase; } @@ -111,7 +111,7 @@ class ZForwardingTest : public Test { ZGeneration::_old = _old_old; ZGeneration::_young = _old_young; if (_reserved != nullptr) { - os::uncommit_memory((char*)_reserved, ZGranuleSize, !ExecMem, mtTest); + os::uncommit_memory((char*)_reserved, ZGranuleSize, false /* executable */); os::release_memory((char*)_reserved, ZGranuleSize); } } diff --git a/test/hotspot/gtest/memory/test_virtualspace.cpp b/test/hotspot/gtest/memory/test_virtualspace.cpp index a20f85ba6c5..2240f0f4cb3 100644 --- a/test/hotspot/gtest/memory/test_virtualspace.cpp +++ b/test/hotspot/gtest/memory/test_virtualspace.cpp @@ -64,7 +64,7 @@ namespace { static void test_reserved_size(size_t size) { ASSERT_PRED2(is_size_aligned, size, os::vm_allocation_granularity()); - ReservedSpace rs(size, mtTest); + ReservedSpace rs(size); MemoryReleaser releaser(&rs); EXPECT_TRUE(rs.base() != nullptr) << "rs.special: " << rs.special(); @@ -78,7 +78,7 @@ namespace { static void test_reserved_size_alignment(size_t size, size_t alignment) { ASSERT_PRED2(is_size_aligned, size, alignment) << "Incorrect input parameters"; size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); - ReservedSpace rs(size, alignment, page_size, mtTest, (char *) nullptr); + ReservedSpace rs(size, alignment, page_size, (char *) nullptr); ASSERT_TRUE(rs.base() != nullptr) << "rs.special = " << rs.special(); ASSERT_EQ(size, rs.size()) << "rs.special = " << rs.special(); @@ -106,7 +106,7 @@ namespace { bool large = maybe_large && UseLargePages && size >= os::large_page_size(); size_t page_size = large ? os::large_page_size() : os::vm_page_size(); - ReservedSpace rs(size, alignment, page_size, mtTest); + ReservedSpace rs(size, alignment, page_size); MemoryReleaser releaser(&rs); EXPECT_TRUE(rs.base() != nullptr) << "rs.special: " << rs.special(); @@ -215,13 +215,12 @@ namespace { default: case Default: case Reserve: - return ReservedSpace(reserve_size_aligned, mtTest); + return ReservedSpace(reserve_size_aligned); case Disable: case Commit: return ReservedSpace(reserve_size_aligned, os::vm_allocation_granularity(), - os::vm_page_size(), - mtTest); + os::vm_page_size()); } } @@ -300,7 +299,7 @@ TEST_VM(VirtualSpace, actual_committed_space_one_large_page) { size_t large_page_size = os::large_page_size(); - ReservedSpace reserved(large_page_size, large_page_size, large_page_size, mtTest); + ReservedSpace reserved(large_page_size, large_page_size, large_page_size); ReservedSpaceReleaser releaser(&reserved); ASSERT_TRUE(reserved.is_reserved()); @@ -370,7 +369,6 @@ class TestReservedSpace : AllStatic { ReservedSpace rs(size, // size alignment, // alignment page_size, // page size - mtTest, // NMT MEM Flag (char *)nullptr); // requested_address EXPECT_TRUE(rs.base() != nullptr); @@ -389,7 +387,7 @@ class TestReservedSpace : AllStatic { static void test_reserved_space2(size_t size) { ASSERT_TRUE(is_aligned(size, os::vm_allocation_granularity())) << "Must be at least AG aligned"; - ReservedSpace rs(size, mtTest); + ReservedSpace rs(size); EXPECT_TRUE(rs.base() != nullptr); EXPECT_EQ(rs.size(), size) << "rs.size: " << rs.size(); @@ -414,7 +412,7 @@ class TestReservedSpace : AllStatic { bool large = maybe_large && UseLargePages && size >= os::large_page_size(); size_t page_size = large ? os::large_page_size() : os::vm_page_size(); - ReservedSpace rs(size, alignment, page_size, mtTest); + ReservedSpace rs(size, alignment, page_size); EXPECT_TRUE(rs.base() != nullptr); EXPECT_EQ(rs.size(), size) << "rs.size: " << rs.size(); @@ -518,12 +516,12 @@ class TestVirtualSpace : AllStatic { default: case Default: case Reserve: - return ReservedSpace(reserve_size_aligned, mtTest); + return ReservedSpace(reserve_size_aligned); case Disable: case Commit: return ReservedSpace(reserve_size_aligned, os::vm_allocation_granularity(), - os::vm_page_size(), mtTest); + os::vm_page_size()); } } @@ -578,7 +576,7 @@ class TestVirtualSpace : AllStatic { size_t large_page_size = os::large_page_size(); - ReservedSpace reserved(large_page_size, large_page_size, large_page_size, mtTest); + ReservedSpace reserved(large_page_size, large_page_size, large_page_size); EXPECT_TRUE(reserved.is_reserved()); diff --git a/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp b/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp index 359c492bb6a..87ad2a798e0 100644 --- a/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp @@ -114,7 +114,7 @@ TEST_VM(NMT, DISABLED_location_printing_cheap_dead_7) { test_for_dead_c_heap_blo #endif static void test_for_mmap(size_t sz, ssize_t offset) { - char* addr = os::reserve_memory(sz, !ExecMem, mtTest); + char* addr = os::reserve_memory(sz, false, mtTest); if (MemTracker::enabled()) { test_pointer(addr + offset, true, "in mmap'd memory region"); } else { diff --git a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp index 4036c798079..d4959cfa008 100644 --- a/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp +++ b/test/hotspot/gtest/runtime/test_committed_virtualmemory.cpp @@ -93,7 +93,7 @@ class CommittedVirtualMemoryTest { const size_t page_sz = os::vm_page_size(); const size_t size = num_pages * page_sz; char* base = os::reserve_memory(size, !ExecMem, mtThreadStack); - bool result = os::commit_memory(base, size, !ExecMem, mtThreadStack); + bool result = os::commit_memory(base, size, !ExecMem); size_t index; ASSERT_NE(base, (char*)nullptr); for (index = 0; index < touch_pages; index ++) { @@ -132,7 +132,7 @@ class CommittedVirtualMemoryTest { } // Cleanup - os::free_memory(base, size, page_sz, mtThreadStack); + os::free_memory(base, size, page_sz); VirtualMemoryTracker::remove_released_region((address)base, size); rmr = VirtualMemoryTracker::_reserved_regions->find(ReservedMemoryRegion((address)base, size)); @@ -162,7 +162,7 @@ class CommittedVirtualMemoryTest { const size_t size = num_pages * page_sz; char* base = os::reserve_memory(size, !ExecMem, mtTest); ASSERT_NE(base, (char*)nullptr); - result = os::commit_memory(base, size, !ExecMem, mtTest); + result = os::commit_memory(base, size, !ExecMem); ASSERT_TRUE(result); // touch all pages diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 3b7267b5790..55d30349ee5 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -367,7 +367,7 @@ TEST_VM(os, jio_snprintf) { static inline bool can_reserve_executable_memory(void) { bool executable = true; size_t len = 128; - char* p = os::reserve_memory(len, executable, mtTest); + char* p = os::reserve_memory(len, executable); bool exec_supported = (p != nullptr); if (exec_supported) { os::release_memory(p, len); @@ -405,7 +405,7 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) { for (int tries = 0; tries < 256 && p == nullptr; tries ++) { size_t total_range_len = num_stripes * stripe_len; // Reserve a large contiguous area to get the address space... - p = (address)os::reserve_memory(total_range_len, !ExecMem, mtTest); + p = (address)os::reserve_memory(total_range_len); EXPECT_NE(p, (address)nullptr); // .. release it... EXPECT_TRUE(os::release_memory((char*)p, total_range_len)); @@ -419,14 +419,14 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) { #else const bool executable = stripe % 2 == 0; #endif - q = (address)os::attempt_reserve_memory_at((char*)q, stripe_len, executable, mtTest); + q = (address)os::attempt_reserve_memory_at((char*)q, stripe_len, executable); if (q == nullptr) { // Someone grabbed that area concurrently. Cleanup, then retry. tty->print_cr("reserve_multiple: retry (%d)...", stripe); carefully_release_multiple(p, stripe, stripe_len); p = nullptr; } else { - EXPECT_TRUE(os::commit_memory((char*)q, stripe_len, executable, mtTest)); + EXPECT_TRUE(os::commit_memory((char*)q, stripe_len, executable)); } } } @@ -439,12 +439,12 @@ static address reserve_multiple(int num_stripes, size_t stripe_len) { static address reserve_one_commit_multiple(int num_stripes, size_t stripe_len) { assert(is_aligned(stripe_len, os::vm_allocation_granularity()), "Sanity"); size_t total_range_len = num_stripes * stripe_len; - address p = (address)os::reserve_memory(total_range_len, !ExecMem, mtTest); + address p = (address)os::reserve_memory(total_range_len); EXPECT_NE(p, (address)nullptr); for (int stripe = 0; stripe < num_stripes; stripe++) { address q = p + (stripe * stripe_len); if (stripe % 2 == 0) { - EXPECT_TRUE(os::commit_memory((char*)q, stripe_len, !ExecMem, mtTest)); + EXPECT_TRUE(os::commit_memory((char*)q, stripe_len, false)); } } return p; @@ -506,7 +506,7 @@ TEST_VM(os, release_multi_mappings) { PRINT_MAPPINGS("B"); // ...re-reserve the middle stripes. This should work unless release silently failed. - address p2 = (address)os::attempt_reserve_memory_at((char*)p_middle_stripes, middle_stripe_len, !ExecMem, mtTest); + address p2 = (address)os::attempt_reserve_memory_at((char*)p_middle_stripes, middle_stripe_len); ASSERT_EQ(p2, p_middle_stripes); @@ -529,7 +529,7 @@ TEST_VM_ASSERT_MSG(os, release_bad_ranges, ".*bad release") { #else TEST_VM(os, release_bad_ranges) { #endif - char* p = os::reserve_memory(4 * M, !ExecMem, mtTest); + char* p = os::reserve_memory(4 * M); ASSERT_NE(p, (char*)nullptr); // Release part of range ASSERT_FALSE(os::release_memory(p, M)); @@ -564,7 +564,7 @@ TEST_VM(os, release_one_mapping_multi_commits) { // // make things even more difficult by trying to reserve at the border of the region address border = p + num_stripes * stripe_len; - address p2 = (address)os::attempt_reserve_memory_at((char*)border, stripe_len, !ExecMem, mtTest); + address p2 = (address)os::attempt_reserve_memory_at((char*)border, stripe_len); PRINT_MAPPINGS("B"); ASSERT_TRUE(p2 == nullptr || p2 == border); @@ -605,9 +605,9 @@ TEST_VM(os, show_mappings_small_range) { TEST_VM(os, show_mappings_full_range) { // Reserve a small range and fill it with a marker string, should show up // on implementations displaying range snippets - char* p = os::reserve_memory(1 * M, !ExecMem, mtInternal); + char* p = os::reserve_memory(1 * M, false, mtInternal); if (p != nullptr) { - if (os::commit_memory(p, 1 * M, !ExecMem, mtTest)) { + if (os::commit_memory(p, 1 * M, false)) { strcpy(p, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); } } @@ -629,7 +629,7 @@ TEST_VM(os, find_mapping_simple) { // A simple allocation { - address p = (address)os::reserve_memory(total_range_len, !ExecMem, mtTest); + address p = (address)os::reserve_memory(total_range_len); ASSERT_NE(p, (address)nullptr); PRINT_MAPPINGS("A"); for (size_t offset = 0; offset < total_range_len; offset += 4711) { @@ -934,9 +934,9 @@ TEST_VM(os, open_O_CLOEXEC) { } TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_smallpages) { - char* p1 = os::reserve_memory(M, !ExecMem, mtTest); + char* p1 = os::reserve_memory(M, false, mtTest); ASSERT_NE(p1, nullptr); - char* p2 = os::attempt_reserve_memory_at(p1, M, !ExecMem, mtTest); + char* p2 = os::attempt_reserve_memory_at(p1, M); ASSERT_EQ(p2, nullptr); // should have failed os::release_memory(p1, M); } @@ -944,9 +944,9 @@ TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_smallpages) { TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_largepages) { if (UseLargePages && !os::can_commit_large_page_memory()) { // aka special const size_t lpsz = os::large_page_size(); - char* p1 = os::reserve_memory_aligned(lpsz, lpsz, !ExecMem, mtTest); + char* p1 = os::reserve_memory_aligned(lpsz, lpsz, false); ASSERT_NE(p1, nullptr); - char* p2 = os::reserve_memory_special(lpsz, lpsz, lpsz, p1, !ExecMem, mtTest); + char* p2 = os::reserve_memory_special(lpsz, lpsz, lpsz, p1, false); ASSERT_EQ(p2, nullptr); // should have failed os::release_memory(p1, M); } else { @@ -958,9 +958,9 @@ TEST_VM(os, reserve_at_wish_address_shall_not_replace_mappings_largepages) { // On Aix, we should fail attach attempts not aligned to segment boundaries (256m) TEST_VM(os, aix_reserve_at_non_shmlba_aligned_address) { if (Use64KPages) { - char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M, !ExecMem, mtTest); + char* p = os::attempt_reserve_memory_at((char*)0x1f00000, M); ASSERT_EQ(p, nullptr); // should have failed - p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M, !ExecMem, mtTest); + p = os::attempt_reserve_memory_at((char*)((64 * G) + M), M); ASSERT_EQ(p, nullptr); // should have failed } } diff --git a/test/hotspot/gtest/runtime/test_os_linux.cpp b/test/hotspot/gtest/runtime/test_os_linux.cpp index 582a516465c..69c3d991b2a 100644 --- a/test/hotspot/gtest/runtime/test_os_linux.cpp +++ b/test/hotspot/gtest/runtime/test_os_linux.cpp @@ -54,7 +54,7 @@ namespace { const size_t _size; public: static char* reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, size_t page_size, char* req_addr, bool exec) { - return os::reserve_memory_special(bytes, alignment, page_size, req_addr, exec, mtTest); + return os::reserve_memory_special(bytes, alignment, page_size, req_addr, exec); } HugeTlbfsMemory(char* const ptr, size_t size) : _ptr(ptr), _size(size) { } ~HugeTlbfsMemory() { @@ -224,7 +224,7 @@ class TestReserveMemorySpecial : AllStatic { if (!using_explicit_hugepages()) { return; } - char* addr = os::reserve_memory_special(size, alignment, page_size, nullptr, !ExecMem, mtTest); + char* addr = os::reserve_memory_special(size, alignment, page_size, nullptr, false); if (addr != nullptr) { small_page_write(addr, size); os::release_memory_special(addr, size); @@ -281,7 +281,7 @@ class TestReserveMemorySpecial : AllStatic { for (int i = 0; i < num_sizes; i++) { const size_t size = sizes[i]; for (size_t alignment = ag; is_aligned(size, alignment); alignment *= 2) { - char* p = os::reserve_memory_special(size, alignment, lp, nullptr, !ExecMem, mtTest); + char* p = os::reserve_memory_special(size, alignment, lp, nullptr, false); if (p != nullptr) { EXPECT_TRUE(is_aligned(p, alignment)); small_page_write(p, size); @@ -296,7 +296,7 @@ class TestReserveMemorySpecial : AllStatic { for (size_t alignment = ag; is_aligned(size, alignment); alignment *= 2) { // req_addr must be at least large page aligned. char* const req_addr = align_up(mapping1, MAX2(alignment, lp)); - char* p = os::reserve_memory_special(size, alignment, lp, req_addr, !ExecMem, mtTest); + char* p = os::reserve_memory_special(size, alignment, lp, req_addr, false); if (p != nullptr) { EXPECT_EQ(p, req_addr); small_page_write(p, size); @@ -311,7 +311,7 @@ class TestReserveMemorySpecial : AllStatic { for (size_t alignment = ag; is_aligned(size, alignment); alignment *= 2) { // req_addr must be at least large page aligned. char* const req_addr = align_up(mapping2, MAX2(alignment, lp)); - char* p = os::reserve_memory_special(size, alignment, lp, req_addr, !ExecMem, mtTest); + char* p = os::reserve_memory_special(size, alignment, lp, req_addr, false); // as the area around req_addr contains already existing mappings, the API should always // return nullptr (as per contract, it cannot return another address) EXPECT_TRUE(p == nullptr); @@ -355,9 +355,9 @@ TEST_VM(os_linux, pretouch_thp_and_use_concurrent) { const size_t size = 1 * G; const bool useThp = UseTransparentHugePages; UseTransparentHugePages = true; - char* const heap = os::reserve_memory(size, !ExecMem, mtInternal); + char* const heap = os::reserve_memory(size, false, mtInternal); EXPECT_NE(heap, nullptr); - EXPECT_TRUE(os::commit_memory(heap, size, !ExecMem, mtInternal)); + EXPECT_TRUE(os::commit_memory(heap, size, false)); { auto pretouch = [heap, size](Thread*, int) { @@ -379,7 +379,7 @@ TEST_VM(os_linux, pretouch_thp_and_use_concurrent) { for (int i = 0; i < 1000; i++) EXPECT_EQ(*iptr++, i); - EXPECT_TRUE(os::uncommit_memory(heap, size, !ExecMem, mtInternal)); + EXPECT_TRUE(os::uncommit_memory(heap, size, false)); EXPECT_TRUE(os::release_memory(heap, size)); UseTransparentHugePages = useThp; } diff --git a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp index 1e052ddf65e..aad6acc095a 100644 --- a/test/hotspot/gtest/runtime/test_os_reserve_between.cpp +++ b/test/hotspot/gtest/runtime/test_os_reserve_between.cpp @@ -66,7 +66,7 @@ static size_t allocation_granularity() { << " bytes: " << bytes << " alignment: " << alignment << " randomized: " << randomized static char* call_attempt_reserve_memory_between(char* min, char* max, size_t bytes, size_t alignment, bool randomized) { - char* const addr = os::attempt_reserve_memory_between(min, max, bytes, alignment, randomized, mtTest); + char* const addr = os::attempt_reserve_memory_between(min, max, bytes, alignment, randomized); if (addr != nullptr) { EXPECT_TRUE(is_aligned(addr, alignment)) << ERRINFO; EXPECT_TRUE(is_aligned(addr, allocation_granularity())) << ERRINFO; @@ -158,7 +158,7 @@ struct SpaceWithHole { // the hole. const uintptr_t candidate = nth_bit(i); if ((candidate + _len) <= ARMB_constants::absolute_max) { - _base = os::attempt_reserve_memory_at((char*)candidate, _len, !ExecMem, mtTest); + _base = os::attempt_reserve_memory_at((char*)candidate, _len); } } if (_base == nullptr) { @@ -166,8 +166,8 @@ struct SpaceWithHole { } // Release total mapping, remap the individual non-holy parts os::release_memory(_base, _len); - _p1 = os::attempt_reserve_memory_at(_base + _p1_offset, _p1_size, !ExecMem, mtTest); - _p2 = os::attempt_reserve_memory_at(_base + _p2_offset, _p2_size, !ExecMem, mtTest); + _p1 = os::attempt_reserve_memory_at(_base + _p1_offset, _p1_size); + _p2 = os::attempt_reserve_memory_at(_base + _p2_offset, _p2_size); if (_p1 == nullptr || _p2 == nullptr) { return false; } diff --git a/test/hotspot/gtest/runtime/test_os_windows.cpp b/test/hotspot/gtest/runtime/test_os_windows.cpp index 87ae501a08b..8c6f003de6f 100644 --- a/test/hotspot/gtest/runtime/test_os_windows.cpp +++ b/test/hotspot/gtest/runtime/test_os_windows.cpp @@ -67,7 +67,7 @@ void TestReserveMemorySpecial_test() { FLAG_SET_CMDLINE(UseNUMAInterleaving, false); const size_t large_allocation_size = os::large_page_size() * 4; - char* result = os::reserve_memory_special(large_allocation_size, os::large_page_size(), os::large_page_size(), nullptr, !ExecMem, mtTest); + char* result = os::reserve_memory_special(large_allocation_size, os::large_page_size(), os::large_page_size(), nullptr, false); if (result == nullptr) { // failed to allocate memory, skipping the test return; @@ -77,12 +77,12 @@ void TestReserveMemorySpecial_test() { // Reserve another page within the recently allocated memory area. This should fail const size_t expected_allocation_size = os::large_page_size(); char* expected_location = result + os::large_page_size(); - char* actual_location = os::reserve_memory_special(expected_allocation_size, os::large_page_size(), os::large_page_size(), expected_location, !ExecMem, mtTest); + char* actual_location = os::reserve_memory_special(expected_allocation_size, os::large_page_size(), os::large_page_size(), expected_location, false); EXPECT_TRUE(actual_location == nullptr) << "Should not be allowed to reserve within present reservation"; // Instead try reserving after the first reservation. expected_location = result + large_allocation_size; - actual_location = os::reserve_memory_special(expected_allocation_size, os::large_page_size(), os::large_page_size(), expected_location, !ExecMem, mtTest); + actual_location = os::reserve_memory_special(expected_allocation_size, os::large_page_size(), os::large_page_size(), expected_location, false); EXPECT_TRUE(actual_location != nullptr) << "Unexpected reservation failure, can’t verify correct location"; EXPECT_TRUE(actual_location == expected_location) << "Reservation must be at requested location"; MemoryReleaser m2(actual_location, os::large_page_size()); @@ -90,7 +90,7 @@ void TestReserveMemorySpecial_test() { // Now try to do a reservation with a larger alignment. const size_t alignment = os::large_page_size() * 2; const size_t new_large_size = alignment * 4; - char* aligned_request = os::reserve_memory_special(new_large_size, alignment, os::large_page_size(), nullptr, !ExecMem, mtTest); + char* aligned_request = os::reserve_memory_special(new_large_size, alignment, os::large_page_size(), nullptr, false); EXPECT_TRUE(aligned_request != nullptr) << "Unexpected reservation failure, can’t verify correct alignment"; EXPECT_TRUE(is_aligned(aligned_request, alignment)) << "Returned address must be aligned"; MemoryReleaser m3(aligned_request, new_large_size); diff --git a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp index f2b3b843c23..b098416456d 100644 --- a/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp +++ b/test/hotspot/gtest/runtime/test_virtualMemoryTracker.cpp @@ -93,7 +93,7 @@ class VirtualMemoryTrackerTest { static void test_add_committed_region_adjacent() { size_t size = 0x01000000; - ReservedSpace rs(size, mtTest); + ReservedSpace rs(size); address addr = (address)rs.base(); address frame1 = (address)0x1234; @@ -167,7 +167,7 @@ class VirtualMemoryTrackerTest { static void test_add_committed_region_adjacent_overlapping() { size_t size = 0x01000000; - ReservedSpace rs(size, mtTest); + ReservedSpace rs(size); address addr = (address)rs.base(); address frame1 = (address)0x1234; @@ -254,7 +254,7 @@ class VirtualMemoryTrackerTest { static void test_add_committed_region_overlapping() { size_t size = 0x01000000; - ReservedSpace rs(size, mtTest); + ReservedSpace rs(size); address addr = (address)rs.base(); address frame1 = (address)0x1234; @@ -425,7 +425,7 @@ class VirtualMemoryTrackerTest { static void test_remove_uncommitted_region() { size_t size = 0x01000000; - ReservedSpace rs(size, mtTest); + ReservedSpace rs(size); address addr = (address)rs.base(); address frame1 = (address)0x1234; diff --git a/test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndNonExactAllocate.java b/test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndNonExactAllocate.java new file mode 100644 index 00000000000..19b641036bd --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestReduceAllocationAndNonExactAllocate.java @@ -0,0 +1,73 @@ +/* + * 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 8330247 + * @summary Check that Reduce Allocation Merges doesn't try to reduce non-exact allocations. + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * @requires vm.debug & vm.flagless & vm.compiler2.enabled & vm.opt.final.EliminateAllocations + * @run main/othervm -XX:CompileCommand=compileonly,*TestReduceAllocationAndNonExactAllocate*::test + * -XX:CompileCommand=compileonly,*::allocateInstance + * -XX:CompileCommand=dontinline,*TestReduceAllocationAndNonExactAllocate*::* + * -XX:+UnlockDiagnosticVMOptions + * -XX:+TraceReduceAllocationMerges + * -XX:-TieredCompilation + * -Xbatch + * -Xcomp + * -server + * compiler.c2.TestReduceAllocationAndNonExactAllocate + */ + +package compiler.c2; + +import jdk.internal.misc.Unsafe; + +public class TestReduceAllocationAndNonExactAllocate { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + + public static void main(String[] args) { + try { + if (test(20, Integer.class) != 2032) { + throw new RuntimeException("Expected the value to be 2032."); + } + } + catch (InstantiationException e) { + e.printStackTrace(); + } + } + + public static int test(int val, Class c) throws InstantiationException { + Object p = null; + + if (val == 20) { + p = UNSAFE.allocateInstance(c); + } + + dummy(); + return p != null ? 2032 : 3242; + } + + static int dummy() { return 42; } +} diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java deleted file mode 100644 index 9307ab8250a..00000000000 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8136421 - * @requires vm.jvmci - * @library /test/lib / - * @library ../common/patches - * @modules java.base/jdk.internal.misc - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.org.objectweb.asm.tree - * jdk.internal.vm.ci/jdk.vm.ci.hotspot - * jdk.internal.vm.ci/jdk.vm.ci.code - * jdk.internal.vm.ci/jdk.vm.ci.code.site - * jdk.internal.vm.ci/jdk.vm.ci.meta - * jdk.internal.vm.ci/jdk.vm.ci.runtime - * - * @build jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper - * jdk.test.whitebox.WhiteBox jdk.test.whitebox.parser.DiagnosticCommand - * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox - * jdk.test.whitebox.parser.DiagnosticCommand - * @run junit/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest - */ - -package compiler.jvmci.compilerToVM; - -import compiler.jvmci.common.CodeInstallerTest; -import compiler.jvmci.common.CTVMUtilities; -import jdk.test.lib.Asserts; -import jdk.test.lib.Utils; -import jdk.vm.ci.code.InstalledCode; -import jdk.vm.ci.code.site.Site; -import jdk.vm.ci.code.site.DataPatch; -import jdk.vm.ci.hotspot.CompilerToVMHelper; -import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; -import jdk.vm.ci.hotspot.HotSpotNmethod; -import jdk.vm.ci.meta.Assumptions.Assumption; - -import java.util.List; -import org.junit.Test; - -public class InvalidateInstalledCodeTest extends CodeInstallerTest { - - @Test - public void testInvalidation() { - List testCases - = CompileCodeTestCase.generate(/* bci = */ 0); - testCases.addAll(CompileCodeTestCase.generate(/* bci = */ -1)); - testCases.forEach(t -> check(t)); - checkNull(); - } - - private void checkNull() { - Utils.runAndCheckException( - () -> CompilerToVMHelper.invalidateHotSpotNmethod(null, true), - NullPointerException.class); - } - - private void check(CompileCodeTestCase testCase) { - HotSpotResolvedJavaMethod javaMethod = CTVMUtilities.getResolvedMethod(testCase.executable); - HotSpotNmethod nmethod = (HotSpotNmethod) installEmptyCode(new Site[0], new Assumption[0], - new Comment[0], 8, new DataPatch[0], null); - - Asserts.assertTrue(nmethod.isValid(), testCase + " : code is invalid even before invalidation"); - - Asserts.assertTrue(nmethod.isValid(), testCase + " : code is not valid, i = " + nmethod); - Asserts.assertTrue(nmethod.isAlive(), testCase + " : code is not alive, i = " + nmethod); - Asserts.assertNotEquals(nmethod.getStart(), 0L); - - // Make nmethod non-entrant but still alive - CompilerToVMHelper.invalidateHotSpotNmethod(nmethod, false); - Asserts.assertFalse(nmethod.isValid(), testCase + " : code is valid, i = " + nmethod); - Asserts.assertTrue(nmethod.isAlive(), testCase + " : code is not alive, i = " + nmethod); - Asserts.assertEquals(nmethod.getStart(), 0L); - - // Deoptimize the nmethod and cut the link to it from the HotSpotNmethod - CompilerToVMHelper.invalidateHotSpotNmethod(nmethod, true); - Asserts.assertFalse(nmethod.isValid(), testCase + " : code is valid, i = " + nmethod); - Asserts.assertFalse(nmethod.isAlive(), testCase + " : code is alive, i = " + nmethod); - Asserts.assertEquals(nmethod.getStart(), 0L); - } -} diff --git a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.config b/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.config deleted file mode 100644 index 9e2866167c1..00000000000 --- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.config +++ /dev/null @@ -1,2 +0,0 @@ -compiler.jvmci.events.JvmciNotifyInstallEventTest -compiler.jvmci.common.JVMCIHelpers diff --git a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java b/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java deleted file mode 100644 index c5d1b99235a..00000000000 --- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @bug 8136421 - * @requires vm.jvmci & !vm.graal.enabled & vm.compMode == "Xmixed" - * @library / /test/lib - * @library ../common/patches - * @modules java.base/jdk.internal.misc - * @modules java.base/jdk.internal.org.objectweb.asm - * java.base/jdk.internal.org.objectweb.asm.tree - * jdk.internal.vm.ci/jdk.vm.ci.hotspot - * jdk.internal.vm.ci/jdk.vm.ci.code - * jdk.internal.vm.ci/jdk.vm.ci.code.site - * jdk.internal.vm.ci/jdk.vm.ci.meta - * jdk.internal.vm.ci/jdk.vm.ci.runtime - * jdk.internal.vm.ci/jdk.vm.ci.services - * - * @build jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper - * @build compiler.jvmci.common.JVMCIHelpers - * @run driver jdk.test.lib.FileInstaller ./JvmciNotifyInstallEventTest.config - * ./META-INF/services/jdk.vm.ci.services.JVMCIServiceLocator - * @run driver jdk.test.lib.helpers.ClassFileInstaller - * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler - * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory - * compiler.jvmci.common.JVMCIHelpers$EmptyCompilationRequestResult - * compiler.jvmci.common.JVMCIHelpers$EmptyVMEventListener - * @run main/othervm -XX:+UnlockExperimentalVMOptions - * -Djvmci.Compiler=EmptyCompiler -Xbootclasspath/a:. - * -XX:+UseJVMCICompiler -XX:-BootstrapJVMCI - * -XX:-UseJVMCINativeLibrary -XX:JVMCITraceLevel=1 - * -Dtest.jvmci.forceRuntimeStubAllocFail=test_stub_that_fails_to_be_allocated - * compiler.jvmci.events.JvmciNotifyInstallEventTest - * @run main/othervm -XX:+UnlockExperimentalVMOptions - * -Djvmci.Compiler=EmptyCompiler -Xbootclasspath/a:. - * -XX:+UseJVMCICompiler -XX:-BootstrapJVMCI -XX:JVMCINMethodSizeLimit=0 - * -XX:-UseJVMCINativeLibrary - * compiler.jvmci.events.JvmciNotifyInstallEventTest - */ - -package compiler.jvmci.events; - -import compiler.jvmci.common.CTVMUtilities; -import compiler.jvmci.common.testcases.SimpleClass; -import jdk.test.lib.Asserts; -import jdk.test.lib.Platform; -import jdk.test.lib.Utils; -import jdk.vm.ci.services.JVMCIServiceLocator; -import jdk.vm.ci.code.BailoutException; -import jdk.vm.ci.code.CompiledCode; -import jdk.vm.ci.code.InstalledCode; -import jdk.vm.ci.code.site.DataPatch; -import jdk.vm.ci.code.site.Site; -import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; -import jdk.vm.ci.hotspot.HotSpotCompiledCode; -import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; -import jdk.vm.ci.hotspot.HotSpotCompiledNmethod; -import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; -import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; -import jdk.vm.ci.hotspot.HotSpotVMEventListener; -import jdk.vm.ci.meta.Assumptions.Assumption; -import jdk.vm.ci.meta.ResolvedJavaMethod; - -import java.lang.reflect.Method; - -public class JvmciNotifyInstallEventTest extends JVMCIServiceLocator implements HotSpotVMEventListener { - private static final String METHOD_NAME = "testMethod"; - private static volatile int gotInstallNotification = 0; - - public static void main(String args[]) { - new JvmciNotifyInstallEventTest().runTest(); - } - - @Override - public S getProvider(Class service) { - if (service == HotSpotVMEventListener.class) { - return service.cast(this); - } - return null; - } - - private void runTest() { - if (gotInstallNotification != 0) { - throw new Error("Got install notification before test actions"); - } - HotSpotCodeCacheProvider codeCache; - try { - codeCache = (HotSpotCodeCacheProvider) HotSpotJVMCIRuntime.runtime() - .getHostJVMCIBackend().getCodeCache(); - } catch (InternalError ie) { - // passed - return; - } - Method testMethod; - try { - testMethod = SimpleClass.class.getDeclaredMethod(METHOD_NAME); - } catch (NoSuchMethodException e) { - throw new Error("TEST BUG: Can't find " + METHOD_NAME, e); - } - HotSpotResolvedJavaMethod method = CTVMUtilities - .getResolvedMethod(SimpleClass.class, testMethod); - int dataSectionAlignment = 8; // CodeBuffer::SECT_CONSTS code section alignment - HotSpotCompiledCode compiledCode = new HotSpotCompiledNmethod(METHOD_NAME, - new byte[0], 0, new Site[0], new Assumption[0], - new ResolvedJavaMethod[]{method}, new Comment[0], new byte[0], - dataSectionAlignment, new DataPatch[0], false, 0, null, - method, 0, 1, 0L, false); - codeCache.installCode(method, compiledCode, /* installedCode = */ null, - /* speculationLog = */ null, /* isDefault = */ false); - Asserts.assertEQ(gotInstallNotification, 1, - "Got unexpected event count after 1st install attempt"); - // since "empty" compilation result is ok, a second attempt should be ok - codeCache.installCode(method, compiledCode, /* installedCode = */ null, - /* speculationLog = */ null, /* isDefault = */ false); - Asserts.assertEQ(gotInstallNotification, 2, - "Got unexpected event count after 2nd install attempt"); - // and an incorrect cases - Utils.runAndCheckException(() -> { - codeCache.installCode(method, null, null, null, true); - }, NullPointerException.class); - Asserts.assertEQ(gotInstallNotification, 2, - "Got unexpected event count after 3rd install attempt"); - Utils.runAndCheckException(() -> { - codeCache.installCode(null, null, null, null, true); - }, NullPointerException.class); - Asserts.assertEQ(gotInstallNotification, 2, - "Got unexpected event count after 4th install attempt"); - - String stubToFail = System.getProperty("test.jvmci.forceRuntimeStubAllocFail"); - if (Platform.isDebugBuild() && stubToFail != null) { - HotSpotCompiledCode stub = new HotSpotCompiledCode(stubToFail, - /* targetCode */ new byte[0], - /* targetCodeSize */ 0, - /* sites */ new Site[0], - /* assumptions */ new Assumption[0], - /* methods */ new ResolvedJavaMethod[0], - /* comments */ new Comment[0], - /* dataSection */ new byte[0], - dataSectionAlignment, - /* dataSectionPatches */ new DataPatch[0], - /* isImmutablePIC */ false, - /* totalFrameSize */ 0, - /* deoptRescueSlot */ null); - try { - codeCache.installCode(null, stub, null, null, true); - throw new AssertionError("Didn't get expected " + BailoutException.class.getName()); - } catch (BailoutException e) { - Asserts.assertEQ(e.getMessage(), "Error installing " + stubToFail + ": code cache is full"); - } - } - } - - @Override - public void notifyInstall(HotSpotCodeCacheProvider hotSpotCodeCacheProvider, - InstalledCode installedCode, CompiledCode compiledCode) { - gotInstallNotification++; - } -} diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java index 7483c45a654..97583b45458 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/CodeInstallationTest.java @@ -35,6 +35,7 @@ import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; +import jdk.vm.ci.hotspot.HotSpotNmethod; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.MetaAccessProvider; @@ -95,7 +96,7 @@ protected Method getMethod(String name, Class... args) { } } - protected void test(TestCompiler compiler, Method method, Object... args) { + protected HotSpotNmethod test(TestCompiler compiler, Method method, Object... args) { try { HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(method); TestAssembler asm = createAssembler(); @@ -115,9 +116,9 @@ protected void test(TestCompiler compiler, Method method, Object... args) { Object expected = method.invoke(null, args); Object actual = installed.executeVarargs(args); Assert.assertEquals(expected, actual); + return (HotSpotNmethod) installed; } catch (Exception e) { - e.printStackTrace(); - Assert.fail(e.toString()); + throw new AssertionError(e); } } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/RuntimeStubAllocFailTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/RuntimeStubAllocFailTest.java new file mode 100644 index 00000000000..dea523af166 --- /dev/null +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/RuntimeStubAllocFailTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @requires vm.jvmci & !vm.graal.enabled & vm.compMode == "Xmixed" + * @library / /test/lib + * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot + * jdk.internal.vm.ci/jdk.vm.ci.code + * jdk.internal.vm.ci/jdk.vm.ci.code.site + * jdk.internal.vm.ci/jdk.vm.ci.meta + * jdk.internal.vm.ci/jdk.vm.ci.runtime + * + * @run main/othervm -XX:+UnlockExperimentalVMOptions + * -Xbootclasspath/a:. + * -XX:+EnableJVMCI -XX:JVMCITraceLevel=1 + * -Dtest.jvmci.forceRuntimeStubAllocFail=test_stub_that_fails_to_be_allocated + * jdk.vm.ci.code.test.RuntimeStubAllocFailTest + */ + +package jdk.vm.ci.code.test; + +import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import jdk.vm.ci.code.BailoutException; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.code.site.Site; +import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; +import jdk.vm.ci.meta.Assumptions.Assumption; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.runtime.JVMCI; +import jdk.vm.ci.runtime.JVMCIRuntime; +import jdk.vm.ci.runtime.JVMCIBackend; + +public class RuntimeStubAllocFailTest { + + public static void main(String args[]) { + JVMCIBackend backend = JVMCI.getRuntime().getHostJVMCIBackend(); + HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) backend.getCodeCache(); + int dataSectionAlignment = 8; // CodeBuffer::SECT_CONSTS code section alignment + String stubToFail = System.getProperty("test.jvmci.forceRuntimeStubAllocFail"); + if (Platform.isDebugBuild() && stubToFail != null) { + HotSpotCompiledCode stub = new HotSpotCompiledCode(stubToFail, + /* targetCode */ new byte[0], + /* targetCodeSize */ 0, + /* sites */ new Site[0], + /* assumptions */ new Assumption[0], + /* methods */ new ResolvedJavaMethod[0], + /* comments */ new Comment[0], + /* dataSection */ new byte[0], + dataSectionAlignment, + /* dataSectionPatches */ new DataPatch[0], + /* isImmutablePIC */ false, + /* totalFrameSize */ 0, + /* deoptRescueSlot */ null); + try { + codeCache.installCode(null, stub, null, null, true); + throw new AssertionError("Didn't get expected " + BailoutException.class.getName()); + } catch (BailoutException e) { + Asserts.assertEQ(e.getMessage(), "Error installing " + stubToFail + ": code cache is full"); + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java index 80c63392b6e..82058ec02cf 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/SimpleCodeInstallationTest.java @@ -25,7 +25,7 @@ * @test * @requires vm.jvmci * @requires vm.simpleArch == "x64" | vm.simpleArch == "aarch64" | vm.simpleArch == "riscv64" - * @library / + * @library /test/lib / * @modules jdk.internal.vm.ci/jdk.vm.ci.hotspot * jdk.internal.vm.ci/jdk.vm.ci.meta * jdk.internal.vm.ci/jdk.vm.ci.code @@ -39,8 +39,10 @@ */ package jdk.vm.ci.code.test; +import jdk.test.lib.Asserts; import jdk.vm.ci.code.Register; +import jdk.vm.ci.hotspot.HotSpotNmethod; import org.junit.Test; /** @@ -61,6 +63,23 @@ private static void compileAdd(TestAssembler asm) { @Test public void test() { - test(SimpleCodeInstallationTest::compileAdd, getMethod("add", int.class, int.class), 5, 7); + HotSpotNmethod nmethod = test(SimpleCodeInstallationTest::compileAdd, getMethod("add", int.class, int.class), 5, 7); + + // Test code invalidation + Asserts.assertTrue(nmethod.isValid(), "code is not valid, i = " + nmethod); + Asserts.assertTrue(nmethod.isAlive(), "code is not alive, i = " + nmethod); + Asserts.assertNotEquals(nmethod.getStart(), 0L); + + // Make nmethod non-entrant but still alive + nmethod.invalidate(false); + Asserts.assertFalse(nmethod.isValid(), "code is valid, i = " + nmethod); + Asserts.assertTrue(nmethod.isAlive(), "code is not alive, i = " + nmethod); + Asserts.assertEquals(nmethod.getStart(), 0L); + + // Deoptimize the nmethod and cut the link to it from the HotSpotNmethod + nmethod.invalidate(true); + Asserts.assertFalse(nmethod.isValid(), "code is valid, i = " + nmethod); + Asserts.assertFalse(nmethod.isAlive(), "code is alive, i = " + nmethod); + Asserts.assertEquals(nmethod.getStart(), 0L); } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java index f1afef3bae2..6a4f6addd0d 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java @@ -243,6 +243,27 @@ protected TestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config, this.curStackSlot = initialFrameSize; } + public class Bookmark implements AutoCloseable { + private final int registerMark = nextRegister; + private final int codePos = code.position(); + private final int dataPos = data.position(); + + @Override + public void close() { + nextRegister = registerMark; + code.data.position(codePos); + data.data.position(dataPos); + } + } + + /** + * Enters a scope in which the current register, code and data emitting state + * is restored upon leaving the scope. + */ + public Bookmark bookmark() { + return new Bookmark(); + } + public ValueKind getValueKind(JavaKind kind) { return new TestValueKind(codeCache.getTarget().arch.getPlatformKind(kind)); } @@ -296,6 +317,18 @@ protected void recordDataPatchInData(Reference ref) { dataPatches.add(new DataPatch(data.position(), ref)); } + /** + * Emits the 32 bit constant `c` into the data section. + */ + public DataSectionReference emitDataItem(int c) { + DataSectionReference ref = new DataSectionReference(); + ref.setOffset(data.position()); + + recordDataPatchInCode(ref); + data.emitInt(c); + return ref; + } + public DataSectionReference emitDataItem(HotSpotConstant c) { DataSectionReference ref = new DataSectionReference(); ref.setOffset(data.position()); @@ -321,6 +354,50 @@ public HotSpotCompiledCode finish(HotSpotResolvedJavaMethod method) { finishedDataPatches, false, frameSize, deoptRescue, method, -1, id, 0L, false); } + /** + * @param n Number of bits that should be set to 1. Must be between 0 and 32 (inclusive). + * @return A number with n bits set to 1. + */ + public static int getNbitNumberInt(int n) { + assert n >= 0 && n <= 32 : "0 <= n <= 32; instead: " + n; + if (n < 32) { + return (1 << n) - 1; + } else { + return 0xFFFFFFFF; + } + } + + public static boolean isSignedNbit(int n, int value) { + assert n > 0 && n < 32 : n; + int min = -(1 << (n - 1)); + int max = (1 << (n - 1)) - 1; + return value >= min && value <= max; + } + + public static boolean isUnsignedNbit(int n, int value) { + assert n > 0 && n < 32 : n; + return 32 - Integer.numberOfLeadingZeros(value) <= n; + } + + /** + * Determines if `x` is in the range of signed byte values. + */ + public static boolean isByte(int x) { + return (byte) x == x; + } + + /** + * Determines if `l` is in the range of signed int values. + */ + public static boolean isInt(long l) { + return (int) l == l; + } + + public static void check(boolean condition, String errorMessage, Object... args) { + if (!condition) { + throw new AssertionError(errorMessage.formatted(args)); + } + } protected static class Buffer { private ByteBuffer data = ByteBuffer.allocate(32).order(ByteOrder.nativeOrder()); diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java index 9468027bc85..12664bd433f 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java @@ -32,6 +32,7 @@ public class TestHotSpotVMConfig extends HotSpotVMConfigAccess { public TestHotSpotVMConfig(HotSpotVMConfigStore config, Architecture arch) { super(config); ropProtection = (arch instanceof AArch64) ? getFieldValue("VM_Version::_rop_protection", Boolean.class) : false; + nmethodEntryBarrierConcurrentPatch = initNmethodEntryBarrierConcurrentPatch(arch); } public final boolean useCompressedOops = getFlag("UseCompressedOops", Boolean.class); @@ -47,10 +48,37 @@ public TestHotSpotVMConfig(HotSpotVMConfigStore config, Architecture arch) { // Checkstyle: stop public final int MARKID_DEOPT_HANDLER_ENTRY = getConstant("CodeInstaller::DEOPT_HANDLER_ENTRY", Integer.class); + public final int MARKID_FRAME_COMPLETE = getConstant("CodeInstaller::FRAME_COMPLETE", Integer.class); + public final int MARKID_ENTRY_BARRIER_PATCH = getConstant("CodeInstaller::ENTRY_BARRIER_PATCH", Integer.class); public final long handleDeoptStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", Long.class, "address"); public final int maxOopMapStackOffset = getFieldValue("CompilerToVM::Data::_max_oop_map_stack_offset", Integer.class, "int"); public final int heapWordSize = getConstant("HeapWordSize", Integer.class); public final boolean ropProtection; + + private Boolean initNmethodEntryBarrierConcurrentPatch(Architecture arch) { + Boolean patchConcurrent = null; + if (arch instanceof AArch64 && nmethodEntryBarrier != 0) { + Integer patchingType = getFieldValue("CompilerToVM::Data::BarrierSetAssembler_nmethod_patching_type", Integer.class, "int"); + if (patchingType != null) { + // There currently only 2 variants in use that differ only by the presence of a + // dmb instruction + int stw = getConstant("NMethodPatchingType::stw_instruction_and_data_patch", Integer.class); + int conc = getConstant("NMethodPatchingType::conc_data_patch", Integer.class); + if (patchingType == stw) { + patchConcurrent = false; + } else if (patchingType == conc) { + patchConcurrent = true; + } else { + throw new IllegalArgumentException("unsupported barrier sequence " + patchingType); + } + } + } + return patchConcurrent; + } + + public final int threadDisarmedOffset = getFieldValue("CompilerToVM::Data::thread_disarmed_guard_value_offset", Integer.class, "int"); + public final long nmethodEntryBarrier = getFieldValue("CompilerToVM::Data::nmethod_entry_barrier", Long.class, "address"); + public final Boolean nmethodEntryBarrierConcurrentPatch; } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java index e87944f3ca9..8d6814c5435 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/aarch64/AArch64TestAssembler.java @@ -46,8 +46,69 @@ public class AArch64TestAssembler extends TestAssembler { private static final Register scratchRegister = AArch64.rscratch1; + private static final Register scratchRegister2 = AArch64.rscratch2; private static final Register doubleScratch = AArch64.v9; + /** + * Condition Flags for branches. See C1.2.4 + */ + public enum ConditionFlag { + // Integer | Floating-point meanings + /** Equal | Equal. */ + EQ(0x0), + + /** Not Equal | Not equal or unordered. */ + NE(0x1), + + /** Unsigned Higher or Same | Greater than, equal or unordered. */ + HS(0x2), + + /** Unsigned lower | less than. */ + LO(0x3), + + /** Minus (negative) | less than. */ + MI(0x4), + + /** Plus (positive or zero) | greater than, equal or unordered. */ + PL(0x5), + + /** Overflow set | unordered. */ + VS(0x6), + + /** Overflow clear | ordered. */ + VC(0x7), + + /** Unsigned higher | greater than or unordered. */ + HI(0x8), + + /** Unsigned lower or same | less than or equal. */ + LS(0x9), + + /** Signed greater than or equal | greater than or equal. */ + GE(0xA), + + /** Signed less than | less than or unordered. */ + LT(0xB), + + /** Signed greater than | greater than. */ + GT(0xC), + + /** Signed less than or equal | less than, equal or unordered. */ + LE(0xD), + + /** Always | always. */ + AL(0xE), + + /** Always | always (identical to AL, just to have valid 0b1111 encoding). */ + NV(0xF); + + public final int encoding; + + ConditionFlag(int encoding) { + this.encoding = encoding; + } + } + public AArch64TestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) { super(codeCache, config, 16 /* initialFrameSize */, 16 /* stackAlignment */, @@ -215,6 +276,22 @@ private void emitBlr(Register Rn) { | f(0, 4, 0)); } + /** + * C6.2.25 Branch conditionally. + * + * @param condition may not be null. + * @param imm21 Signed 21-bit offset, has to be 4-byte aligned. + */ + protected void emitBranch(ConditionFlag condition, int imm21) { + // B.cond + check(isSignedNbit(21, imm21) && (imm21 & 0b11) == 0, + "0x%x must be a 21-bit signed number and 4-byte aligned", imm21); + int imm19 = (imm21 & getNbitNumberInt(21)) >> 2; + code.emitInt(f(0b001010100, 31, 24) + | f(imm19, 23, 4) + | f(condition.encoding, 3, 0)); + } + private void emitFmov(Register Rd, AArch64Kind kind, Register Rn) { // FMOV (general) int ftype = 0, sf = 0; @@ -261,9 +338,25 @@ public void emitPrologue() { code.emitInt(0xa9bf7bfd); // stp x29, x30, [sp, #-16]! code.emitInt(0x910003fd); // mov x29, sp + emitNMethodEntryBarrier(); + setDeoptRescueSlot(newStackSlot(AArch64Kind.QWORD)); } + private void emitNMethodEntryBarrier() { + recordMark(config.MARKID_ENTRY_BARRIER_PATCH); + DataSectionReference ref = emitDataItem(0); + emitLoadPointer(scratchRegister, AArch64Kind.DWORD, ref); + if (config.nmethodEntryBarrierConcurrentPatch) { + code.emitInt(0xd50339bf); // dmb ishld + } + Register thread = AArch64.r28; + emitLoadPointer(scratchRegister2, AArch64Kind.DWORD, thread, config.threadDisarmedOffset); + code.emitInt(0x6b09011f); // cmp w8, w9 + emitBranch(ConditionFlag.EQ, 8); // jump over slow path, runtime call + emitCall(config.nmethodEntryBarrier); + } + @Override public void emitEpilogue() { recordMark(config.MARKID_DEOPT_HANDLER_ENTRY); @@ -361,8 +454,11 @@ public Register emitLoadPointer(HotSpotConstant c) { @Override public Register emitLoadPointer(Register b, int offset) { - Register ret = newRegister(); - emitLoadRegister(ret, AArch64Kind.QWORD, b, offset); + return emitLoadPointer(newRegister(), AArch64Kind.QWORD, b, offset); + } + + public Register emitLoadPointer(Register ret, AArch64Kind kind, Register b, int offset) { + emitLoadRegister(ret, kind, b, offset); return ret; } @@ -377,10 +473,13 @@ public Register emitLoadNarrowPointer(DataSectionReference ref) { @Override public Register emitLoadPointer(DataSectionReference ref) { + return emitLoadPointer(newRegister(), AArch64Kind.QWORD, ref); + } + + public Register emitLoadPointer(Register ret, AArch64Kind kind, DataSectionReference ref) { recordDataPatchInCode(ref); - Register ret = newRegister(); - emitLoadRegister(ret, AArch64Kind.QWORD, 0xdead); + emitLoadRegister(ret, kind, 0xdead); return ret; } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java index a0fcdd2b0a9..32b0e66df33 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/amd64/AMD64TestAssembler.java @@ -49,6 +49,40 @@ public class AMD64TestAssembler extends TestAssembler { private static final Register scratchRegister = AMD64.r12; private static final Register doubleScratch = AMD64.xmm15; + /** + * The x86 condition codes used for conditional jumps/moves. + */ + public enum ConditionFlag { + Zero(0x4, "|zero|"), + NotZero(0x5, "|nzero|"), + Equal(0x4, "="), + NotEqual(0x5, "!="), + Less(0xc, "<"), + LessEqual(0xe, "<="), + Greater(0xf, ">"), + GreaterEqual(0xd, ">="), + Below(0x2, "|<|"), + BelowEqual(0x6, "|<=|"), + Above(0x7, "|>|"), + AboveEqual(0x3, "|>=|"), + Overflow(0x0, "|of|"), + NoOverflow(0x1, "|nof|"), + CarrySet(0x2, "|carry|"), + CarryClear(0x3, "|ncarry|"), + Negative(0x8, "|neg|"), + Positive(0x9, "|pos|"), + Parity(0xa, "|par|"), + NoParity(0xb, "|npar|"); + + public final int value; + public final String operator; + + ConditionFlag(int value, String operator) { + this.value = value; + this.operator = operator; + } + } + public AMD64TestAssembler(CodeCacheProvider codeCache, TestHotSpotVMConfig config) { super(codeCache, config, 16, 16, AMD64Kind.DWORD, AMD64.rax, AMD64.rcx, AMD64.rdi, AMD64.r8, AMD64.r9, AMD64.r10); } @@ -63,6 +97,62 @@ private void emitFatNop() { code.emitByte(0x00); } + /** + * Emit the expected patchable code sequence for the nmethod entry barrier. The int sized + * payload must be naturally aligned so it can be patched atomically. + */ + private void emitNMethodEntryCompare(int displacement) { + // cmp dword ptr [r15 + ], 0x00000000 + // 41 81 7f 00 00 00 00 + code.emitByte(0x41); + code.emitByte(0x81); + code.emitByte(0x7f); + check(isByte(displacement), "expected byte sized displacement: 0x%x", displacement); + code.emitByte(displacement & 0xff); + check(code.position() % 4 == 0, "must be aligned"); + code.emitInt(0); + } + + /** + * Emits a long (i.e. 6 byte) format conditional branch. + * + * @param offset the offset of the branch target wrt the start of the branch instruction + */ + private void emitBranch(ConditionFlag condition, int offset) { + final int longSize = 6; + int disp32 = offset - longSize; + + // 0000 1111 1000 tttn #32-bit disp + check(isInt(disp32), "must be 32bit disp: %d", disp32); + code.emitByte(0x0F); + code.emitByte(0x80 | condition.value); + code.emitInt(disp32); + } + + public void emitAlign(int modulus) { + while (code.position() % modulus != 0) { + code.emitByte(0x90); + } + } + + private void emitNMethodEntryBarrier() { + // The following code sequence must be emitted in exactly this fashion as HotSpot + // will check that the barrier is the expected code sequence. + emitAlign(4); + recordMark(config.MARKID_FRAME_COMPLETE); + recordMark(config.MARKID_ENTRY_BARRIER_PATCH); + emitNMethodEntryCompare(config.threadDisarmedOffset); + int branchOffset; + try (Bookmark bm = bookmark()) { + int pos = code.position(); + emitBranch(ConditionFlag.Equal, 0); + emitCall(config.nmethodEntryBarrier); + branchOffset = code.position() - pos; + } + emitBranch(ConditionFlag.Equal, branchOffset); + emitCall(config.nmethodEntryBarrier); + } + @Override public void emitPrologue() { // WARNING: Initial instruction MUST be 5 bytes or longer so that @@ -71,6 +161,7 @@ public void emitPrologue() { emitFatNop(); code.emitByte(0x50 | AMD64.rbp.encoding); // PUSH rbp emitMove(true, AMD64.rbp, AMD64.rsp); // MOV rbp, rsp + emitNMethodEntryBarrier(); setDeoptRescueSlot(newStackSlot(AMD64Kind.QWORD)); } @@ -414,7 +505,7 @@ public void emitCallPrologue(CallingConvention cc, Object... prim) { @Override public void emitCall(long addr) { - Register target = emitLoadLong(addr); + Register target = emitLoadLong(AMD64.rax, addr); code.emitByte(0xFF); // CALL r/m64 int enc = target.encoding; if (enc >= 8) { diff --git a/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java b/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java new file mode 100644 index 00000000000..a84ebc5fe5c --- /dev/null +++ b/test/hotspot/jtreg/gc/arguments/TestParallelGCErgo.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package gc.arguments; + +/* + * @test TestParallelGCErgo + * @bug 8272364 + * @requires vm.gc.Parallel + * @summary Verify ParallelGC minimum young and old ergonomics are setup correctly + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @library / + * @run driver gc.arguments.TestParallelGCErgo + */ + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import java.util.ArrayList; +import java.util.Arrays; + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.Platform; + +public class TestParallelGCErgo { + private static final long HEAPWORD_SIZE = Platform.is64bit() ? 8 : 4; + // Must be a power of 2 + private static final long GEN_ALIGNMENT = 64 * 1024 * HEAPWORD_SIZE; + + private static final long MINIMUM_HEAP_SIZE = 256 * 1024 * 1024; // 256M + private static final long EXPECTED_MIN_YOUNG = alignDown(MINIMUM_HEAP_SIZE / 3, GEN_ALIGNMENT); + private static final long EXPECTED_MIN_OLD = MINIMUM_HEAP_SIZE - EXPECTED_MIN_YOUNG; // heap size = young size + old size + + // s has to be a power of 2 + private static long alignDown(long s, long align) { + return s & (~(align-1)); + } + + public static void main(String[] args) throws Exception { + ArrayList flagList = new ArrayList(); + flagList.add("-XX:+UseParallelGC"); + flagList.add("-Xms256m"); + flagList.add("-Xmx1g"); + flagList.add("-Xlog:gc+heap=trace"); + flagList.add("-version"); + + OutputAnalyzer output = GCArguments.executeTestJava(flagList); + output.shouldHaveExitValue(0); + + String stdout = output.getStdout(); + long minimumHeap = getFlagValue("Minimum heap", stdout); + if (minimumHeap != MINIMUM_HEAP_SIZE) { + throw new RuntimeException("Wrong value for minimum heap. Expected " + MINIMUM_HEAP_SIZE + " but got " + minimumHeap); + } + + long minimumYoung = getFlagValue("Minimum young", stdout); + if (minimumYoung != EXPECTED_MIN_YOUNG) { + throw new RuntimeException("Wrong value for minimum young. Expected " + EXPECTED_MIN_YOUNG + " but got " + minimumYoung); + } + + long minimumOld = getFlagValue("Minimum old", stdout); + if (minimumOld != EXPECTED_MIN_OLD) { + throw new RuntimeException("Wrong value for minimum old. Expected " + EXPECTED_MIN_OLD + " but got " + minimumOld); + } + } + + private static long getFlagValue(String flag, String where) { + Matcher m = Pattern.compile(flag + " \\d+").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + String match = m.group(); + return Long.parseLong(match.substring(match.lastIndexOf(" ") + 1, match.length())); + } + +} diff --git a/test/jdk/java/util/Base64/TestEncodingDecodingLength.java b/test/jdk/java/util/Base64/TestEncodingDecodingLength.java index 3a91cd88b1f..ce6d0db4adc 100644 --- a/test/jdk/java/util/Base64/TestEncodingDecodingLength.java +++ b/test/jdk/java/util/Base64/TestEncodingDecodingLength.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,55 +21,95 @@ * questions. */ -import java.nio.ByteBuffer; -import java.util.Arrays; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Base64; -/** +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +/* * @test - * @bug 8210583 8217969 8218265 - * @summary Tests Base64.Encoder.encode and Base64.Decoder.decode - * with the large size of input array/buffer - * @requires (sun.arch.data.model == "64" & os.maxMemory >= 10g) - * @run main/othervm -Xms6g -Xmx8g TestEncodingDecodingLength - * + * @bug 8210583 8217969 8218265 8295153 + * @summary White-box test that effectively checks Base64.Encoder.encode and + * Base64.Decoder.decode behavior with large, (Integer.MAX_VALUE) sized + * input array/buffer. Tests the private methods "encodedOutLength" and + * "decodedOutLength". + * @run junit/othervm --add-opens java.base/java.util=ALL-UNNAMED TestEncodingDecodingLength */ +// We perform a white-box test due to the heavy memory usage that testing +// the public API would require which has shown to cause intermittent issues public class TestEncodingDecodingLength { - public static void main(String[] args) { - int size = Integer.MAX_VALUE - 8; - byte[] inputBytes = new byte[size]; - byte[] outputBytes = new byte[size]; + // A value large enough to test the desired memory conditions in encode and decode + private static final int LARGE_MEM_SIZE = Integer.MAX_VALUE - 8; + private static final Base64.Decoder DECODER = Base64.getDecoder(); + private static final Base64.Encoder ENCODER = Base64.getEncoder(); - // Check encoder with large array length - Base64.Encoder encoder = Base64.getEncoder(); - checkOOM("encode(byte[])", () -> encoder.encode(inputBytes)); - checkIAE("encode(byte[] byte[])", () -> encoder.encode(inputBytes, outputBytes)); - checkOOM("encodeToString(byte[])", () -> encoder.encodeToString(inputBytes)); - checkOOM("encode(ByteBuffer)", () -> encoder.encode(ByteBuffer.wrap(inputBytes))); - - // Check decoder with large array length, - // should not throw any exception - Arrays.fill(inputBytes, (byte) 86); - Base64.Decoder decoder = Base64.getDecoder(); - decoder.decode(inputBytes); - decoder.decode(inputBytes, outputBytes); - decoder.decode(ByteBuffer.wrap(inputBytes)); + // Effectively tests that encode(byte[] src, byte[] dst) throws an + // IllegalArgumentException with array sized near Integer.MAX_VALUE. All the + // encode() methods call encodedOutLength(), which is where the OOME is expected + @Test + public void largeEncodeIAETest() throws IllegalAccessException, + InvocationTargetException, NoSuchMethodException { + Method m = getMethod(ENCODER, + "encodedOutLength", int.class, boolean.class); + // When throwOOME param is false, encodedOutLength should return -1 in + // this situation, which encode() uses to throw IAE + assertEquals(-1, m.invoke(ENCODER, LARGE_MEM_SIZE, false)); } - private static final void checkOOM(String methodName, Runnable r) { + // Effectively tests that the overloaded encode() and encodeToString() methods + // throw OutOfMemoryError with array/buffer sized near Integer.MAX_VALUE + @Test + public void largeEncodeOOMETest() throws IllegalAccessException, NoSuchMethodException { + Method m = getMethod(ENCODER, + "encodedOutLength", int.class, boolean.class); try { - r.run(); - throw new RuntimeException("OutOfMemoryError should have been thrown by: " + methodName); - } catch (OutOfMemoryError er) {} + m.invoke(ENCODER, LARGE_MEM_SIZE, true); + } catch (InvocationTargetException ex) { + Throwable rootEx = ex.getCause(); + assertEquals(OutOfMemoryError.class, rootEx.getClass(), + "OOME should be thrown with Integer.MAX_VALUE input"); + assertEquals("Encoded size is too large", rootEx.getMessage()); + } } - private static final void checkIAE(String methodName, Runnable r) { + // Effectively tests that the overloaded decode() methods do not throw + // OOME nor NASE with array/buffer sized near Integer.MAX_VALUE All the decode + // methods call decodedOutLength(), which is where the previously thrown + // OOME or NASE would occur at. + @Test + public void largeDecodeTest() throws IllegalAccessException, NoSuchMethodException { + Method m = getMethod(DECODER, + "decodedOutLength", byte[].class, int.class, int.class); + byte[] src = {1}; try { - r.run(); - throw new RuntimeException("IllegalArgumentException should have been thrown by: " + methodName); - } catch (IllegalArgumentException iae) {} + /* + decodedOutLength() takes the src array, position, and limit as params. + The src array will be indexed at limit-1 to search for padding. + To avoid passing an array with Integer.MAX_VALUE memory allocated, we + set position param to be -size. Since the initial length + is calculated as limit - position. This mocks the potential overflow + calculation and still allows the array to be indexed without an AIOBE. + */ + m.invoke(DECODER, src, -LARGE_MEM_SIZE + 1, 1); + } catch (InvocationTargetException ex) { + // 8210583 - decode no longer throws NASE + // 8217969 - decode no longer throws OOME + fail("Decode threw an unexpected exception with " + + "Integer.MAX_VALUE sized input: " + ex.getCause()); + } } -} + // Utility to get the private visibility method + private static Method getMethod(Object obj, String methodName, Class... params) + throws NoSuchMethodException { + Method m = obj.getClass().getDeclaredMethod(methodName, params); + m.setAccessible(true); + return m; + } +} diff --git a/test/jdk/javax/swing/JFrame/bug4419914.java b/test/jdk/javax/swing/JFrame/bug4419914.java index 5e15d3c8f91..4574b1ac3d6 100644 --- a/test/jdk/javax/swing/JFrame/bug4419914.java +++ b/test/jdk/javax/swing/JFrame/bug4419914.java @@ -53,8 +53,8 @@ public static void main(String[] args) throws Exception { PassFailJFrame.builder() .title("Tab movement Instructions") .instructions(INSTRUCTIONS) - .rows(12) - .columns(42) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(48) .testUI(bug4419914::createTestUI) .build() .awaitAndCheck(); @@ -65,11 +65,12 @@ private static JFrame createTestUI() { frame.setFocusCycleRoot(true); frame.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); frame.setLocale(Locale.ENGLISH); - frame.enableInputMethods(false); - frame.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); - frame.setLocale(Locale.ENGLISH); - frame.setLayout(new BorderLayout()); + + frame.getContentPane().setComponentOrientation( + ComponentOrientation.RIGHT_TO_LEFT); + frame.getContentPane().setLocale(Locale.ENGLISH); + frame.getContentPane().setLayout(new BorderLayout()); frame.add(new JButton("SOUTH"), BorderLayout.SOUTH); frame.add(new JButton("CENTER"), BorderLayout.CENTER); frame.add(new JButton("END"), BorderLayout.LINE_END); diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index 5b39c0d4985..8a8d8bddc35 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8320360 8330684 8331320 + * @bug 8320360 8330684 8331320 8331655 * @summary Testing ClassFile limits. * @run junit LimitsTest */ @@ -36,6 +36,7 @@ import java.lang.classfile.Opcode; import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.constantpool.ConstantPoolException; +import java.lang.classfile.constantpool.IntegerEntry; import jdk.internal.classfile.impl.DirectMethodBuilder; import jdk.internal.classfile.impl.LabelContext; import jdk.internal.classfile.impl.UnboundAttribute; @@ -106,6 +107,14 @@ void testInvalidClassEntry() { 0, 0, 0, 0, 0, 2, ClassFile.TAG_METHODREF, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}).thisClass()); } + @Test + void testInvalidUtf8Entry() { + var cp = ClassFile.of().parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, + 0, 0, 0, 0, 0, 3, ClassFile.TAG_INTEGER, 0, 0, 0, 0, ClassFile.TAG_NAMEANDTYPE, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}).constantPool(); + assertTrue(cp.entryByIndex(1) instanceof IntegerEntry); //parse valid int entry first + assertThrows(ConstantPoolException.class, () -> cp.entryByIndex(2)); + } + @Test void testInvalidLookupSwitch() { assertThrows(IllegalArgumentException.class, () -> diff --git a/test/jdk/jdk/classfile/SignaturesTest.java b/test/jdk/jdk/classfile/SignaturesTest.java index cfd3201c95a..f4da2405dcd 100644 --- a/test/jdk/jdk/classfile/SignaturesTest.java +++ b/test/jdk/jdk/classfile/SignaturesTest.java @@ -183,9 +183,10 @@ static class Observer extends ArrayList.Inner>{} 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 innerSig = (ClassTypeSig) sig.superclassSignature() // ArrayList - .typeArgs().getFirst() // Outer.Inner - .boundType().orElseThrow(); // assert it's exact bound + var arrayListSig = sig.superclassSignature(); // ArrayList + var arrayListTypeArg = (TypeArg.Bounded) arrayListSig.typeArgs().getFirst(); // Outer.Inner + assertEquals(TypeArg.Bounded.WildcardIndicator.NONE, arrayListTypeArg.wildcardIndicator()); + var innerSig = (ClassTypeSig) arrayListTypeArg.boundType(); assertEquals("Inner", innerSig.className(), "simple name in signature"); assertEquals(Outer.Inner.class.describeConstable().orElseThrow(), innerSig.classDesc(), "ClassDesc derived from signature"); diff --git a/test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java b/test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java index cea86e6e997..79b3fe11cb9 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerInlining.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ package jdk.jfr.event.compiler; -import jdk.internal.org.objectweb.asm.*; import jdk.jfr.Recording; import jdk.jfr.consumer.RecordedEvent; import jdk.jfr.consumer.RecordedMethod; @@ -35,13 +34,24 @@ import jdk.test.whitebox.WhiteBox; import java.io.IOException; +import java.lang.classfile.ClassModel; +import java.lang.classfile.ClassFile; +import java.lang.classfile.Instruction; +import java.lang.classfile.instruction.InvokeInstruction; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.util.*; import java.util.stream.IntStream; +import java.util.stream.Stream; -/** +import static java.lang.constant.ConstantDescs.CD_Object; +import static java.lang.constant.ConstantDescs.CD_void; +import static java.lang.constant.ConstantDescs.INIT_NAME; + +/* * @test CompilerInliningTest * @bug 8073607 * @key jfr @@ -50,8 +60,8 @@ * * @requires vm.opt.Inline == true | vm.opt.Inline == null * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm - * jdk.jfr + * @modules jdk.jfr + * @enablePreview * * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox @@ -64,7 +74,7 @@ public class TestCompilerInlining { private static final int LEVEL_SIMPLE = 1; private static final int LEVEL_FULL_OPTIMIZATION = 4; private static final Executable ENTRY_POINT = getConstructor(TestCase.class); - private static final String TEST_CASE_CLASS_NAME = TestCase.class.getName().replace('.', '/'); + private static final ClassDesc CD_TestCase = TestCase.class.describeConstable().orElseThrow(); public static void main(String[] args) throws Exception { InlineCalls inlineCalls = new InlineCalls(TestCase.class); @@ -100,8 +110,8 @@ private static void testLevel(Map expectedResult, int level) thro MethodDesc caller = methodToMethodDesc(callerObject); MethodDesc callee = ciMethodToMethodDesc(calleeObject); // only TestCase.* -> TestCase.* OR TestCase.* -> Object. are tested/filtered - if (caller.className.equals(TEST_CASE_CLASS_NAME) && (callee.className.equals(TEST_CASE_CLASS_NAME) - || (callee.className.equals("java/lang/Object") && callee.methodName.equals("")))) { + if (caller.className.equals(CD_TestCase) && (callee.className.equals(CD_TestCase) + || (callee.className.equals(CD_Object) && callee.methodName.equals(INIT_NAME)))) { System.out.println(event); boolean succeeded = (boolean) event.getValue("succeeded"); int bci = Events.assertField(event, "bci").atLeast(0).getValue(); @@ -132,17 +142,17 @@ private static int[] determineAvailableLevels() { } private static MethodDesc methodToMethodDesc(RecordedMethod method) { - String internalClassName = method.getType().getName().replace('.', '/'); + ClassDesc classDesc = ClassDesc.of(method.getType().getName()); String methodName = method.getValue("name"); - String methodDescriptor = method.getValue("descriptor"); - return new MethodDesc(internalClassName, methodName, methodDescriptor); + MethodTypeDesc methodDescriptor = MethodTypeDesc.ofDescriptor(method.getValue("descriptor")); + return new MethodDesc(classDesc, methodName, methodDescriptor); } private static MethodDesc ciMethodToMethodDesc(RecordedObject ciMethod) { - String internalClassName = ciMethod.getValue("type"); + ClassDesc classDesc = ClassDesc.ofInternalName(ciMethod.getValue("type")); String methodName = ciMethod.getValue("name"); - String methodDescriptor = ciMethod.getValue("descriptor"); - return new MethodDesc(internalClassName, methodName, methodDescriptor); + MethodTypeDesc methodDescriptor = MethodTypeDesc.ofDescriptor(ciMethod.getValue("descriptor")); + return new MethodDesc(classDesc, methodName, methodDescriptor); } private static Method getMethod(Class aClass, String name, Class... params) { @@ -246,35 +256,33 @@ public String toString() { * data structure for method description */ class MethodDesc { - public final String className; + public final ClassDesc className; public final String methodName; - public final String descriptor; - - public MethodDesc(Class aClass, String methodName, String descriptor) { - this(aClass.getName().replace('.', '/'), methodName, descriptor); - } + public final MethodTypeDesc descriptor; - public MethodDesc(String className, String methodName, String descriptor) { + public MethodDesc(ClassDesc className, String methodName, MethodTypeDesc descriptor) { Objects.requireNonNull(className); Objects.requireNonNull(methodName); Objects.requireNonNull(descriptor); - this.className = className.replace('.', '/'); + this.className = className; this.methodName = methodName; this.descriptor = descriptor; } public MethodDesc(Executable executable) { - Class aClass = executable.getDeclaringClass(); - className = Type.getInternalName(aClass).replace('.', '/'); + className = executable.getDeclaringClass().describeConstable().orElseThrow(); + ClassDesc retType; - if (executable instanceof Constructor) { - methodName = ""; - descriptor = Type.getConstructorDescriptor((Constructor) executable); - } else { + if (executable instanceof Method method) { methodName = executable.getName(); - descriptor = Type.getMethodDescriptor((Method) executable); + retType = method.getReturnType().describeConstable().orElseThrow(); + } else { + methodName = INIT_NAME; + retType = CD_void; } + descriptor = MethodTypeDesc.of(retType, Stream.of(executable.getParameterTypes()) + .map(c -> c.describeConstable().orElseThrow()).toArray(ClassDesc[]::new)); } @Override @@ -361,43 +369,41 @@ public void forceInline(Executable executable) { private static Collection getCalls(Class aClass) { List calls = new ArrayList<>(); - ClassWriter cw; - ClassReader cr; + ClassModel clm; try { - cr = new ClassReader(aClass.getName()); + var stream = ClassLoader.getSystemResourceAsStream(aClass.getName() + .replace('.', '/') + ".class"); + if (stream == null) { + throw new IOException("Cannot find class file for " + aClass.getName()); + } + clm = ClassFile.of().parse(stream.readAllBytes()); } catch (IOException e) { throw new Error("TESTBUG : unexpected IOE during class reading", e); } - cw = new ClassWriter(cr, 0); - ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) { - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String descriptor, String[] exceptions) { - System.out.println("Method: " +name); - MethodVisitor mv = super.visitMethod(access, name, desc, descriptor, exceptions); - return new CallTracer(aClass, name, desc, mv, calls); - } - }; - cr.accept(cv, 0); + clm.methods().forEach(mm -> { + System.out.println("Method: " + mm.methodName().stringValue()); + mm.code().ifPresent(com -> { + MethodDesc caller = new MethodDesc( + clm.thisClass().asSymbol(), + mm.methodName().stringValue(), + mm.methodTypeSymbol() + ); + int offset = 0; + for (var ce : com.elements()) { + if (ce instanceof Instruction ins) { + if (ins instanceof InvokeInstruction inv) { + calls.add(new Call(caller, new MethodDesc( + inv.owner().asSymbol(), + inv.name().stringValue(), + inv.typeSymbol() + ), offset)); + } + offset += ins.sizeInBytes(); + } + } + }); + }); return calls; } - - private static class CallTracer extends MethodVisitor { - private final MethodDesc caller; - private Collection calls; - - public CallTracer(Class aClass, String name, String desc, MethodVisitor mv, Collection calls) { - super(Opcodes.ASM7, mv); - caller = new MethodDesc(aClass.getName(), name, desc); - this.calls = calls; - } - - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { - Label label = new Label(); - visitLabel(label); - super.visitMethodInsn(opcode, owner, name, desc, itf); - calls.add(new Call(caller, new MethodDesc(owner, name, desc), label.getOffset())); - } - } } diff --git a/test/jdk/jdk/jfr/event/io/TestInstrumentation.java b/test/jdk/jdk/jfr/event/io/TestInstrumentation.java index ddbc1206497..5f3885f31bf 100644 --- a/test/jdk/jdk/jfr/event/io/TestInstrumentation.java +++ b/test/jdk/jdk/jfr/event/io/TestInstrumentation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, 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 @@ -23,6 +23,14 @@ package jdk.jfr.event.io; +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.MethodModel; +import java.lang.classfile.MethodTransform; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.util.Arrays; import java.util.Set; import java.util.HashSet; @@ -31,16 +39,15 @@ import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; import java.lang.instrument.IllegalClassFormatException; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.Type; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import static java.lang.constant.ConstantDescs.CD_String; +import static java.lang.constant.ConstantDescs.CD_void; + /* * @test * @summary Test that will instrument the same classes that JFR will also instrument. @@ -48,10 +55,11 @@ * @requires vm.hasJFR * * @library /test/lib /test/jdk - * @modules java.base/jdk.internal.org.objectweb.asm - * java.instrument + * @modules java.instrument * jdk.jartool/sun.tools.jar * jdk.jfr + * @enablePreview + * @comment update --enable-preview in launchTest() too * * @run main/othervm jdk.jfr.event.io.TestInstrumentation */ @@ -90,7 +98,7 @@ public class TestInstrumentation implements ClassFileTransformer { private static TestInstrumentation testTransformer = null; // All methods that will be instrumented. - private static final String[] instrMethodKeys = { + private static final Set instrMethodKeys = Stream.of( "java/io/RandomAccessFile::seek::(J)V", "java/io/RandomAccessFile::read::()I", "java/io/RandomAccessFile::read::([B)I", @@ -116,31 +124,24 @@ public class TestInstrumentation implements ClassFileTransformer { "java/nio/channels/SocketChannel::read::([Ljava/nio/ByteBuffer;)J", "java/nio/channels/SocketChannel::write::([Ljava/nio/ByteBuffer;)J", "sun/nio/ch/FileChannelImpl::read::(Ljava/nio/ByteBuffer;)I", - "sun/nio/ch/FileChannelImpl::write::(Ljava/nio/ByteBuffer;)I", - }; - - private static String getInstrMethodKey(String className, String methodName, String signature) { - // This key is used to identify a class and method. It is sent to callback(key) - return className + "::" + methodName + "::" + signature; - } - - private static String getClassFromMethodKey(String methodKey) { - return methodKey.split("::")[0]; - } + "sun/nio/ch/FileChannelImpl::write::(Ljava/nio/ByteBuffer;)I" + ).map(s -> { + String[] a = s.split("::"); + return new MethodKey(a[0], a[1], a[2]); + }).collect(Collectors.toUnmodifiableSet()); // Set of all classes targeted for instrumentation. - private static Set instrClassesTarget = null; + private static Set instrClassesTarget = null; // Set of all classes where instrumentation has been completed. - private static Set instrClassesDone = null; + private static Set instrClassesDone = null; static { // Split class names from InstrMethodKeys. - instrClassesTarget = new HashSet(); - instrClassesDone = new HashSet(); - for (String s : instrMethodKeys) { - String className = getClassFromMethodKey(s); - instrClassesTarget.add(className); + instrClassesTarget = new HashSet<>(); + instrClassesDone = new HashSet<>(); + for (MethodKey key : instrMethodKeys) { + instrClassesTarget.add(key.owner()); } } @@ -164,9 +165,10 @@ public static void main(String[] args) throws Throwable { runAllTests(TransformStatus.Transformed); // Retransform all classes and then repeat tests - Set> classes = new HashSet>(); - for (String className : instrClassesTarget) { - Class clazz = Class.forName(className.replaceAll("/", ".")); + Set> classes = new HashSet<>(); + for (ClassDesc className : instrClassesTarget) { + var desc = className.descriptorString(); + Class clazz = Class.forName(desc.substring(1, desc.length() - 1).replace('/', '.')); classes.add(clazz); log("Will retransform " + clazz.getName()); } @@ -197,10 +199,10 @@ public static void runAllTests(TransformStatus status) throws Throwable { // Verify that all expected callbacks have been called. Set callbackKeys = InstrumentationCallback.getKeysCopy(); - for (String key : instrMethodKeys) { - boolean gotCallback = callbackKeys.contains(key); + for (MethodKey key : instrMethodKeys) { + boolean gotCallback = callbackKeys.contains(key.toString()); boolean expectsCallback = isClassInstrumented(status, key); - String msg = String.format("key:%s, expects:%b", key, expectsCallback); + String msg = String.format("status:%s, key:%s, expects:%b", status, key, expectsCallback); if (gotCallback != expectsCallback) { throw new Exception("Wrong callback() for " + msg); } else { @@ -214,14 +216,14 @@ public static void runAllTests(TransformStatus status) throws Throwable { } } - private static boolean isClassInstrumented(TransformStatus status, String key) throws Throwable { + private static boolean isClassInstrumented(TransformStatus status, MethodKey key) throws Throwable { switch (status) { case Retransformed: return true; case Removed: return false; case Transformed: - String className = getClassFromMethodKey(key); + var className = key.owner(); return instrClassesDone.contains(className); } throw new Exception("Test error: Unknown TransformStatus: " + status); @@ -279,7 +281,7 @@ private static void launchTest() throws Throwable { String[] args = { "-Xbootclasspath/a:" + testClassDir + "InstrumentationCallback.jar", - "--add-exports", "java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED", + "--enable-preview", "-classpath", classpath, "-javaagent:" + testClassDir + "TestInstrumentation.jar", "jdk.jfr.event.io.TestInstrumentation$TestMain" }; @@ -305,67 +307,52 @@ public byte[] transform( ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain pd, byte[] bytes) throws IllegalClassFormatException { // Check if this class should be instrumented. - if (!instrClassesTarget.contains(className)) { + ClassDesc target = ClassDesc.ofInternalName(className); + if (!instrClassesTarget.contains(target)) { return null; } boolean isRedefinition = classBeingRedefined != null; log("instrument class(" + className + ") " + (isRedefinition ? "redef" : "load")); - ClassReader reader = new ClassReader(bytes); - ClassWriter writer = new ClassWriter( - reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - CallbackClassVisitor classVisitor = new CallbackClassVisitor(writer); - reader.accept(classVisitor, 0); - instrClassesDone.add(className); - return writer.toByteArray(); - } - - private static class CallbackClassVisitor extends ClassVisitor { - private String className; - - public CallbackClassVisitor(ClassVisitor cv) { - super(Opcodes.ASM7, cv); - } - - @Override - public void visit( - int version, int access, String name, String signature, - String superName, String[] interfaces) { - cv.visit(version, access, name, signature, superName, interfaces); - className = name; - } + instrClassesDone.add(target); + var cf = ClassFile.of(); + return cf.transform(cf.parse(bytes), (clb, ce) -> { + MethodKey key; + if (ce instanceof MethodModel mm && instrMethodKeys.contains(key = new MethodKey( + target, mm.methodName().stringValue(), mm.methodTypeSymbol()))) { + clb.transformMethod(mm, MethodTransform.transformingCode(new CodeTransform() { + private static final MethodTypeDesc MTD_callback = MethodTypeDesc.of(CD_void, CD_String); + private static final ClassDesc CD_InstrumentationCallback = InstrumentationCallback.class + .describeConstable().orElseThrow(); + + @Override + public void atStart(CodeBuilder cb) { + cb.loadConstant(key.toString()); + cb.invokestatic(CD_InstrumentationCallback, "callback", MTD_callback); + log("instrumented " + key); + } - @Override - public MethodVisitor visitMethod( - int access, String methodName, String desc, String signature, String[] exceptions) { - String methodKey = getInstrMethodKey(className, methodName, desc); - boolean isInstrumentedMethod = Arrays.asList(instrMethodKeys).contains(methodKey); - MethodVisitor mv = cv.visitMethod(access, methodName, desc, signature, exceptions); - if (isInstrumentedMethod && mv != null) { - mv = new CallbackMethodVisitor(mv, methodKey); - log("instrumented " + methodKey); + @Override + public void accept(CodeBuilder cb, CodeElement ce) { + cb.with(ce); + } + })); + } else { + clb.with(ce); } - return mv; - } + }); } - public static class CallbackMethodVisitor extends MethodVisitor { - private String logMessage; - - public CallbackMethodVisitor(MethodVisitor mv, String logMessage) { - super(Opcodes.ASM7, mv); - this.logMessage = logMessage; + public record MethodKey(ClassDesc owner, String name, MethodTypeDesc desc) { + public MethodKey(String className, String methodName, String signature) { + this(ClassDesc.ofInternalName(className), methodName, MethodTypeDesc.ofDescriptor(signature)); } @Override - public void visitCode() { - mv.visitCode(); - String methodDescr = Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)); - String className = InstrumentationCallback.class.getName().replace('.', '/'); - mv.visitLdcInsn(logMessage); - mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, "callback", methodDescr); + public String toString() { + var ownerDesc = owner.descriptorString(); + return ownerDesc.substring(1, ownerDesc.length() - 1) + "::" + name + "::" + desc.descriptorString(); } } - } diff --git a/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java b/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java index 6dae08044c3..8a8415dc524 100644 --- a/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java +++ b/test/jdk/jdk/jfr/javaagent/TestEventInstrumentation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 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 @@ -22,6 +22,13 @@ */ package jdk.jfr.javaagent; +import java.lang.classfile.ClassFile; +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.CodeElement; +import java.lang.classfile.CodeTransform; +import java.lang.classfile.MethodModel; +import java.lang.classfile.MethodTransform; +import java.lang.constant.ClassDesc; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; import java.lang.instrument.Instrumentation; @@ -29,18 +36,14 @@ import java.nio.file.Paths; import java.security.ProtectionDomain; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.Type; - import jdk.jfr.Event; import jdk.jfr.Recording; import jdk.jfr.consumer.RecordingFile; import jdk.test.lib.Asserts; +import static java.lang.constant.ConstantDescs.INIT_NAME; +import static java.lang.constant.ConstantDescs.MTD_void; + /* * @test * @summary Verify that a subclass of the JFR Event class @@ -48,8 +51,8 @@ * @key jfr * @requires vm.hasJFR * @library /test/lib - * @modules java.base/jdk.internal.org.objectweb.asm - * jdk.jartool/sun.tools.jar + * @modules jdk.jartool/sun.tools.jar + * @enablePreview * @build jdk.jfr.javaagent.InstrumentationEventCallback * jdk.jfr.javaagent.TestEventInstrumentation * @run driver jdk.test.lib.util.JavaAgentBuilder @@ -99,6 +102,9 @@ public static void premain(String args, Instrumentation inst) throws Exception { } static class Transformer implements ClassFileTransformer { + private static final ClassDesc CD_InstrumentationEventCallback = InstrumentationEventCallback.class + .describeConstable().orElseThrow(); + public byte[] transform(ClassLoader classLoader, String className, Class classBeingRedefined, ProtectionDomain pd, byte[] bytes) throws IllegalClassFormatException { @@ -109,13 +115,25 @@ public byte[] transform(ClassLoader classLoader, String className, return null; } - ClassReader reader = new ClassReader(bytes); - ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - CallbackClassVisitor classVisitor = new CallbackClassVisitor(writer); - - // visit the reader's class by the classVisitor - reader.accept(classVisitor, 0); - result = writer.toByteArray(); + var cf = ClassFile.of(); + result = cf.transform(cf.parse(bytes), (clb, ce) -> { + if (ce instanceof MethodModel mm && mm.methodName().equalsString(INIT_NAME)) { + clb.transformMethod(mm, MethodTransform.transformingCode(new CodeTransform() { + @Override + public void atStart(CodeBuilder cb) { + cb.invokestatic(CD_InstrumentationEventCallback, "callback", MTD_void); + log("instrumented in class " + className); + } + + @Override + public void accept(CodeBuilder cb, CodeElement ce) { + cb.accept(ce); + } + })); + } else { + clb.with(ce); + } + }); } catch (Exception e) { log("Exception occured in transform(): " + e.getMessage()); e.printStackTrace(System.out); @@ -123,49 +141,5 @@ public byte[] transform(ClassLoader classLoader, String className, } return result; } - - private static class CallbackClassVisitor extends ClassVisitor { - private String className; - - public CallbackClassVisitor(ClassVisitor cv) { - super(Opcodes.ASM7, cv); - } - - @Override - public void visit(int version, int access, String name, String signature, - String superName, String[] interfaces) { - // visit the header of the class - called per class header visit - cv.visit(version, access, name, signature, superName, interfaces); - className = name; - } - - @Override - public MethodVisitor visitMethod( - int access, String methodName, String desc, - String signature, String[] exceptions) { - // called for each method in a class - boolean isInstrumentedMethod = methodName.contains(""); - MethodVisitor mv = cv.visitMethod(access, methodName, desc, signature, exceptions); - if (isInstrumentedMethod) { - mv = new CallbackMethodVisitor(mv); - log("instrumented in class " + className); - } - return mv; - } - } - - public static class CallbackMethodVisitor extends MethodVisitor { - public CallbackMethodVisitor(MethodVisitor mv) { - super(Opcodes.ASM7, mv); - } - - @Override - public void visitCode() { - mv.visitCode(); - String methodDescr = Type.getMethodDescriptor(Type.VOID_TYPE, Type.VOID_TYPE); - String className = InstrumentationEventCallback.class.getName().replace('.', '/'); - mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, "callback", "()V", false); - } - } } } diff --git a/test/jdk/jdk/jfr/jvm/TestLargeJavaEvent512k.java b/test/jdk/jdk/jfr/jvm/TestLargeJavaEvent512k.java index 93ef8f937d4..eacffb7a13b 100644 --- a/test/jdk/jdk/jfr/jvm/TestLargeJavaEvent512k.java +++ b/test/jdk/jdk/jfr/jvm/TestLargeJavaEvent512k.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 @@ -47,7 +47,6 @@ * @requires vm.hasJFR * @library /test/lib * @modules jdk.jfr/jdk.jfr.internal - * java.base/jdk.internal.org.objectweb.asm * @run main/othervm jdk.jfr.jvm.TestLargeJavaEvent512k */ public class TestLargeJavaEvent512k { diff --git a/test/jdk/jdk/jfr/jvm/TestLargeJavaEvent64k.java b/test/jdk/jdk/jfr/jvm/TestLargeJavaEvent64k.java index d3b535117e5..0de03efb35c 100644 --- a/test/jdk/jdk/jfr/jvm/TestLargeJavaEvent64k.java +++ b/test/jdk/jdk/jfr/jvm/TestLargeJavaEvent64k.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 @@ -47,7 +47,6 @@ * @requires vm.hasJFR * @library /test/lib * @modules jdk.jfr/jdk.jfr.internal - * java.base/jdk.internal.org.objectweb.asm * @run main/othervm jdk.jfr.jvm.TestLargeJavaEvent64k */ public class TestLargeJavaEvent64k { diff --git a/test/langtools/tools/javap/classfile/6888367/T6888367.java b/test/langtools/tools/javap/classfile/6888367/T6888367.java index 05df08b5948..16bc06321ca 100644 --- a/test/langtools/tools/javap/classfile/6888367/T6888367.java +++ b/test/langtools/tools/javap/classfile/6888367/T6888367.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -312,21 +312,14 @@ public String visitTypeParamType(Signature.TypeParam type) { } public String visitWildcardType(Signature.TypeArg type) { - switch (type.wildcardIndicator()) { - case UNBOUNDED -> { - return "W{?}"; - } - case EXTENDS -> { - return "W{e," + print(type.boundType().get()) + "}"; - } - case SUPER -> { - return "W{s," + print(type.boundType().get()) + "}"; - } - default -> { - if (type.boundType().isPresent()) return print(type.boundType().get()); - else throw new AssertionError(); - } - } + return switch (type) { + case Signature.TypeArg.Unbounded _ -> "W{?}"; + case Signature.TypeArg.Bounded b -> switch (b.wildcardIndicator()) { + case EXTENDS -> "W{e," + print(b.boundType()) + "}"; + case SUPER -> "W{s," + print(b.boundType()) + "}"; + case NONE -> print(b.boundType()); + }; + }; } };